Skip to content

Commit

Permalink
CIRCSTORE- 519 Update instead save with the same name circ settings. (#…
Browse files Browse the repository at this point in the history
…478)

* CIRCSTORE-519 add index

* CIRCSTORE-519 replace index

* CIRCSTORE-519 add index

* CIRCSTORE-519 add index

* CIRCSTORE-519 refactored after review

* CIRCSTORE-519 refactored after review using code_style schema

* CIRCSTORE-519 refactored after review using code_style schema

* CIRCSTORE-519 add unit test

* CIRCSTORE-519 add unit test

* CIRCSTORE-519 add unit test

* CIRCSTORE-519 refactored after review

* CIRCSTORE-519 refactored after review

* CIRCSTORE-519 refactored logging

* CIRCSTORE-519 refactored logging and code after review
  • Loading branch information
AntonAntonich authored Aug 16, 2024
1 parent 49d2d1e commit 81c9932
Show file tree
Hide file tree
Showing 5 changed files with 167 additions and 53 deletions.
4 changes: 4 additions & 0 deletions src/main/java/org/folio/persist/AbstractRepository.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ protected AbstractRepository(PostgresClient postgresClient, String tableName,
this.recordType = recordType;
}

public Future<T> saveAndReturnUpdatedEntity(String id, T entity) {
return postgresClient.saveAndReturnUpdatedEntity(tableName, id, entity);
}

public Future<String> save(String id, T entity) {
return postgresClient.save(tableName, id, entity);
}
Expand Down
28 changes: 18 additions & 10 deletions src/main/java/org/folio/rest/impl/CirculationSettingsAPI.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
package org.folio.rest.impl;

import static io.vertx.core.Future.succeededFuture;
import static org.folio.rest.jaxrs.resource.CirculationSettingsStorage.PostCirculationSettingsStorageCirculationSettingsResponse.headersFor201;
import static org.folio.rest.jaxrs.resource.CirculationSettingsStorage.PostCirculationSettingsStorageCirculationSettingsResponse.respond201WithApplicationJson;
import static org.folio.rest.jaxrs.resource.CirculationSettingsStorage.PostCirculationSettingsStorageCirculationSettingsResponse.respond500WithTextPlain;

import java.util.Map;

import javax.ws.rs.core.Response;
Expand All @@ -21,7 +26,10 @@ public void postCirculationSettingsStorageCirculationSettings(String lang,

new CirculationSettingsService(vertxContext, okapiHeaders)
.create(circulationSettings)
.onComplete(asyncResultHandler);
.onSuccess(response -> asyncResultHandler.handle(
succeededFuture(respond201WithApplicationJson(circulationSettings, headersFor201()))))
.onFailure(throwable -> asyncResultHandler.handle(
succeededFuture(respond500WithTextPlain(throwable.getMessage()))));
}

@Override
Expand All @@ -39,9 +47,9 @@ public void getCirculationSettingsStorageCirculationSettingsByCirculationSetting
String circulationSettingsId, String lang, Map<String, String> okapiHeaders,
Handler<AsyncResult<Response>> asyncResultHandler, Context vertxContext) {

new CirculationSettingsService(vertxContext, okapiHeaders)
.findById(circulationSettingsId)
.onComplete(asyncResultHandler);
new CirculationSettingsService(vertxContext, okapiHeaders)
.findById(circulationSettingsId)
.onComplete(asyncResultHandler);
}

@Override
Expand All @@ -50,18 +58,18 @@ public void putCirculationSettingsStorageCirculationSettingsByCirculationSetting
Map<String, String> okapiHeaders, Handler<AsyncResult<Response>> asyncResultHandler,
Context vertxContext) {

new CirculationSettingsService(vertxContext, okapiHeaders)
.update(circulationSettingsId, entity)
.onComplete(asyncResultHandler);
new CirculationSettingsService(vertxContext, okapiHeaders)
.update(circulationSettingsId, entity)
.onComplete(asyncResultHandler);
}

@Override
public void deleteCirculationSettingsStorageCirculationSettingsByCirculationSettingsId(
String circulationSettingsId, String lang, Map<String, String> okapiHeaders,
Handler<AsyncResult<Response>> asyncResultHandler, Context vertxContext) {

new CirculationSettingsService(vertxContext, okapiHeaders)
.delete(circulationSettingsId)
.onComplete(asyncResultHandler);
new CirculationSettingsService(vertxContext, okapiHeaders)
.delete(circulationSettingsId)
.onComplete(asyncResultHandler);
}
}
68 changes: 57 additions & 11 deletions src/main/java/org/folio/service/CirculationSettingsService.java
Original file line number Diff line number Diff line change
@@ -1,26 +1,31 @@
package org.folio.service;

import static org.folio.rest.tools.utils.ValidationHelper.isDuplicate;
import static org.folio.service.event.EntityChangedEventPublisherFactory.circulationSettingsEventPublisher;
import static org.folio.support.ModuleConstants.CIRCULATION_SETTINGS_TABLE;

import java.util.List;
import java.util.Map;

import javax.ws.rs.core.Response;

import lombok.extern.log4j.Log4j2;
import org.folio.persist.CirculationSettingsRepository;
import org.folio.rest.jaxrs.model.CirculationSetting;
import org.folio.rest.jaxrs.model.CirculationSettings;
import org.folio.rest.jaxrs.resource.CirculationSettingsStorage.DeleteCirculationSettingsStorageCirculationSettingsByCirculationSettingsIdResponse;
import org.folio.rest.jaxrs.resource.CirculationSettingsStorage.GetCirculationSettingsStorageCirculationSettingsByCirculationSettingsIdResponse;
import org.folio.rest.jaxrs.resource.CirculationSettingsStorage.GetCirculationSettingsStorageCirculationSettingsResponse;
import org.folio.rest.jaxrs.resource.CirculationSettingsStorage.PostCirculationSettingsStorageCirculationSettingsResponse;
import org.folio.rest.jaxrs.resource.CirculationSettingsStorage.PutCirculationSettingsStorageCirculationSettingsByCirculationSettingsIdResponse;
import org.folio.rest.persist.Criteria.Criteria;
import org.folio.rest.persist.Criteria.Criterion;
import org.folio.rest.persist.PgUtil;
import org.folio.service.event.EntityChangedEventPublisher;

import io.vertx.core.Context;
import io.vertx.core.Future;

@Log4j2
public class CirculationSettingsService {

private final Context vertxContext;
Expand All @@ -42,10 +47,11 @@ public Future<Response> getAll(int offset, int limit, String query) {
GetCirculationSettingsStorageCirculationSettingsResponse.class);
}

public Future<Response> create(CirculationSetting circulationSetting) {
return PgUtil.post(CIRCULATION_SETTINGS_TABLE, circulationSetting, okapiHeaders, vertxContext,
PostCirculationSettingsStorageCirculationSettingsResponse.class)
.compose(eventPublisher.publishCreated());
public Future<CirculationSetting> create(CirculationSetting circulationSetting) {
log.debug("create:: trying to save circulationSetting: {}", circulationSetting);
return repository.saveAndReturnUpdatedEntity(circulationSetting.getId(),
circulationSetting)
.recover(throwable -> updateSettingsValue(circulationSetting, throwable));
}

public Future<Response> findById(String circulationSettingsId) {
Expand All @@ -54,17 +60,57 @@ public Future<Response> findById(String circulationSettingsId) {
GetCirculationSettingsStorageCirculationSettingsByCirculationSettingsIdResponse.class);
}

public Future<Response> update(String circulationSettingsId, CirculationSetting circulationSetting) {
return PgUtil.put(CIRCULATION_SETTINGS_TABLE, circulationSetting, circulationSettingsId, okapiHeaders, vertxContext,
public Future<Response> update(String circulationSettingsId,
CirculationSetting circulationSetting) {

return PgUtil.put(CIRCULATION_SETTINGS_TABLE, circulationSetting, circulationSettingsId,
okapiHeaders, vertxContext,
PutCirculationSettingsStorageCirculationSettingsByCirculationSettingsIdResponse.class)
.compose(eventPublisher.publishUpdated(circulationSetting));
}

public Future<Response> delete(String circulationSettingsId) {
return repository.getById(circulationSettingsId).compose (
circulationSetting -> PgUtil.deleteById(CIRCULATION_SETTINGS_TABLE, circulationSettingsId, okapiHeaders, vertxContext,
DeleteCirculationSettingsStorageCirculationSettingsByCirculationSettingsIdResponse.class)
.compose(eventPublisher.publishRemoved(circulationSetting))
return repository.getById(circulationSettingsId)
.compose(circulationSetting -> PgUtil.deleteById(CIRCULATION_SETTINGS_TABLE,
circulationSettingsId, okapiHeaders, vertxContext,
DeleteCirculationSettingsStorageCirculationSettingsByCirculationSettingsIdResponse.class)
.compose(eventPublisher.publishRemoved(circulationSetting))
);
}

private Future<CirculationSetting> updateSettingsValue(CirculationSetting circulationSetting,
Throwable throwable) {

if (!isDuplicate(throwable.getMessage())) {
log.debug("updateSettingsValue:: error during saving circulation setting: {}. message: {}.",
circulationSetting, throwable.getMessage());
return Future.failedFuture(throwable);
}

log.info("updateSettingsValue:: setting with name: {} already exists.",
circulationSetting.getName());

return getSettingsByName(circulationSetting.getName())
.compose(settings -> updateSettings(settings, circulationSetting));
}

private Future<CirculationSetting> updateSettings(List<CirculationSetting> settings,
CirculationSetting circulationSetting) {

settings.forEach(setting -> setting.setValue(circulationSetting.getValue()));
log.debug("updateSettings:: updating {} setting(s) with name '{}'",
settings::size, circulationSetting::getName);
return repository.update(settings)
.map(circulationSetting);
}

private Future<List<CirculationSetting>> getSettingsByName(String settingsName) {
log.debug("getSettingsByName:: trying to fetch setting by name: {}", settingsName);
Criterion filter = new Criterion(new Criteria()
.addField("'name'")
.setOperation("=")
.setVal(settingsName));

return repository.get(filter);
}
}
9 changes: 8 additions & 1 deletion src/main/resources/templates/db_scripts/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,14 @@
{
"tableName": "circulation_settings",
"withMetadata": true,
"withAuditing": false
"withAuditing": false,
"uniqueIndex": [
{
"fieldName": "name",
"tOps": "ADD",
"caseSensitive": false
}
]
},
{
"tableName": "request",
Expand Down
111 changes: 80 additions & 31 deletions src/test/java/org/folio/rest/api/CirculationSettingsAPITest.java
Original file line number Diff line number Diff line change
@@ -1,75 +1,124 @@
package org.folio.rest.api;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.junit.MatcherAssert.assertThat;

import java.net.MalformedURLException;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;

import io.vertx.core.json.JsonObject;
import lombok.SneakyThrows;
import org.folio.rest.support.ApiTests;
import org.folio.rest.support.http.AssertingRecordClient;
import org.folio.rest.support.http.InterfaceUrls;
import org.junit.Before;
import org.junit.Test;

import io.vertx.core.json.JsonObject;
import java.util.UUID;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.junit.MatcherAssert.assertThat;

public class CirculationSettingsAPITest extends ApiTests {
private static final String ID_KEY = "id";
private static final String NAME_KEY = "name";
private static final String VALUE_KEY = "value";
private static final String SAMPLE_VALUE = "sample";
private static final String SAMPLE_KEY = "sample";
private static final String INITIAL_VALUE = "OK";
private static final String UPDATED_VALUE = "OK1";
private static final String TABLE_NAME = "circulation_settings";
private static final String CIRCULATION_SETTINGS_PROPERTY = "circulation-settings";
private static final int NOT_FOUND_STATUS = 404;

private final AssertingRecordClient circulationSettingsClient =
new AssertingRecordClient(
client, StorageTestSuite.TENANT_ID, InterfaceUrls::circulationSettingsUrl,
"circulation-settings");
client, StorageTestSuite.TENANT_ID, InterfaceUrls::circulationSettingsUrl,
CIRCULATION_SETTINGS_PROPERTY);

@Test
public void canCreateAndRetrieveCirculationSettings() throws MalformedURLException,
ExecutionException, InterruptedException, TimeoutException {
@Before
public void beforeEach() {
StorageTestSuite.cleanUpTable(TABLE_NAME);
}

@Test
@SneakyThrows
public void updateInsteadCreateWithTheSameName() {
String id = UUID.randomUUID().toString();
JsonObject circulationSettingsJson = getCirculationSetting(id);
JsonObject circulationSettingsResponse =
circulationSettingsClient.create(circulationSettingsJson).getJson();
JsonObject circulationSettingsJsonUpdated = getUpdatedSettingsJson();
circulationSettingsClient.create(circulationSettingsJsonUpdated);
JsonObject circulationSettingsById = circulationSettingsClient.getById(id).getJson();

assertThat(circulationSettingsResponse.getString("id"), is(id));
assertThat(circulationSettingsById.getString("id"), is(id));
assertThat(circulationSettingsById.getJsonObject("value"), is(
circulationSettingsJson.getJsonObject("value")));
assertThatCorrectCreation(circulationSettingsResponse, circulationSettingsJson);
assertThat(circulationSettingsClient.getAll().getTotalRecords(), is(1));
assertThat(getValue(circulationSettingsJsonUpdated), is(getValue(circulationSettingsById)));
}

@Test
public void canUpdateCirculationSettings() throws MalformedURLException,
ExecutionException, InterruptedException, TimeoutException {
@SneakyThrows
public void canCreateAndRetrieveCirculationSettings() {
String id = UUID.randomUUID().toString();
JsonObject circulationSettingsJson = getCirculationSetting(id);
JsonObject circulationSettingsResponse =
circulationSettingsClient.create(circulationSettingsJson).getJson();
JsonObject circulationSettingsById = circulationSettingsClient.getById(id).getJson();

assertThat(circulationSettingsResponse.getString(ID_KEY), is(id));
assertThat(circulationSettingsById.getString(ID_KEY), is(id));
assertThat(circulationSettingsById.getJsonObject(VALUE_KEY), is(
circulationSettingsJson.getJsonObject(VALUE_KEY)));
}

@Test
@SneakyThrows
public void canUpdateCirculationSettings() {
String id = UUID.randomUUID().toString();
JsonObject circulationSettingsJson = getCirculationSetting(id);
circulationSettingsClient.create(circulationSettingsJson).getJson();
circulationSettingsClient.attemptPutById(
circulationSettingsJson.put("value", new JsonObject().put("sample", "DONE")));
circulationSettingsJson.put(VALUE_KEY, new JsonObject().put(SAMPLE_KEY, "DONE")));
JsonObject updatedCirculationSettings = circulationSettingsClient.getById(id).getJson();

assertThat(updatedCirculationSettings.getString("id"), is(id));
assertThat(updatedCirculationSettings.getJsonObject("value"), is(
circulationSettingsJson.getJsonObject("value")));
assertThat(updatedCirculationSettings.getString(ID_KEY), is(id));
assertThat(updatedCirculationSettings.getJsonObject(VALUE_KEY), is(
circulationSettingsJson.getJsonObject(VALUE_KEY)));
}

@Test
public void canDeleteCirculationSettings() throws MalformedURLException,
ExecutionException, InterruptedException, TimeoutException {

@SneakyThrows
public void canDeleteCirculationSettings() {
UUID id = UUID.randomUUID();
circulationSettingsClient.create(getCirculationSetting(id.toString())).getJson();
circulationSettingsClient.deleteById(id);
var deletedCirculationSettings = circulationSettingsClient.attemptGetById(id);
assertThat(deletedCirculationSettings.getStatusCode(), is(404));
assertThat(deletedCirculationSettings.getStatusCode(), is(NOT_FOUND_STATUS));
}

private static String getValue(JsonObject circulationSettingsById) {
return circulationSettingsById.getJsonObject(VALUE_KEY).getString(SAMPLE_KEY);
}

private JsonObject getCirculationSetting(String id) {
return new JsonObject()
.put("id", id)
.put("name", "sample")
.put("value", new JsonObject().put("sample", "OK"));
.put(ID_KEY, id)
.put(NAME_KEY, SAMPLE_VALUE)
.put(VALUE_KEY, new JsonObject().put(SAMPLE_KEY, INITIAL_VALUE));
}

private static void assertThatCorrectCreation(JsonObject circulationSettingsResponse,
JsonObject circulationSettingsJson) {

String actualCreatedId = circulationSettingsResponse.getString(ID_KEY);
String expectedCreatedId = circulationSettingsJson.getString(ID_KEY);
String actualCreatedName = circulationSettingsResponse.getString(NAME_KEY);
String expectedCreatedName = circulationSettingsJson.getString(NAME_KEY);

assertThat(actualCreatedId, is(expectedCreatedId));
assertThat(actualCreatedName, is(expectedCreatedName));
}

private JsonObject getUpdatedSettingsJson() {
String updatedId = UUID.randomUUID().toString();
JsonObject circulationSettingsJsonUpdated = getCirculationSetting(updatedId);
JsonObject updatedValue = new JsonObject().put(SAMPLE_KEY, UPDATED_VALUE);
circulationSettingsJsonUpdated.put(VALUE_KEY, updatedValue);
return circulationSettingsJsonUpdated;
}
}

0 comments on commit 81c9932

Please sign in to comment.