Skip to content

Commit

Permalink
[MODSOURCE-731] Add PUT endpoint to update SRS record (#588)
Browse files Browse the repository at this point in the history
  • Loading branch information
RomanChernetskyi authored Jan 9, 2024
1 parent 9fc72c6 commit 4ca9f12
Show file tree
Hide file tree
Showing 7 changed files with 420 additions and 2 deletions.
9 changes: 9 additions & 0 deletions descriptors/ModuleDescriptor-template.json
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,15 @@
"source-storage.records.put"
]
},
{
"methods": [
"PUT"
],
"pathPattern": "/source-storage/records/{id}/generation",
"permissionsRequired": [
"source-storage.records.put"
]
},
{
"methods": [
"DELETE"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,21 @@ public void putSourceStorageRecordsById(String id, Record entity, Map<String, St
}
});
}
@Override
public void putSourceStorageRecordsGenerationById(String matchedId, Record entity, Map<String, String> okapiHeaders,
Handler<AsyncResult<Response>> asyncResultHandler, Context vertxContext) {
vertxContext.runOnContext(v -> {
try {
recordService.updateRecordGeneration(matchedId, entity, tenantId)
.map(updated -> PutSourceStorageRecordsGenerationByIdResponse.respond200WithApplicationJson(entity))
.map(Response.class::cast).otherwise(ExceptionHelper::mapExceptionToResponse)
.onComplete(asyncResultHandler);
} catch (Exception e) {
LOG.warn("putSourceStorageRecordsGenerationById:: Failed to update record generation by matchedId {}", matchedId, e);
asyncResultHandler.handle(Future.succeededFuture(ExceptionHelper.mapExceptionToResponse(e)));
}
});
}

@Override
public void deleteSourceStorageRecordsById(String id, Map<String, String> okapiHeaders,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,16 @@ public interface RecordService {
*/
Future<Record> updateRecord(Record record, String tenantId);

/**
* Updates record generation with given matched id
*
* @param matchedId matched id
* @param record record to update
* @param tenantId tenant id
* @return future with updated Record generation
*/
Future<Record> updateRecordGeneration(String matchedId, Record record, String tenantId);

/**
* Searches for {@link SourceRecord} by {@link Condition} and ordered by order fields with offset and limit
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ public class RecordServiceImpl implements RecordService {
private final RecordDao recordDao;
private static final String DUPLICATE_CONSTRAINT = "idx_records_matched_id_gen";
private static final String DUPLICATE_RECORD_MSG = "Incoming file may contain duplicates";
private static final String MATCHED_ID_NOT_EQUAL_TO_999_FIELD = "Matched id (%s) not equal to 999ff$s (%s) field";
private static final String RECORD_WITH_GIVEN_MATCHED_ID_NOT_FOUND = "Record with given matched id (%s) not found";
public static final String UPDATE_RECORD_DUPLICATE_EXCEPTION = "Incoming record could be a duplicate, incoming record generation should not be the same as matched record generation and the execution of job should be started after of creating the previous record generation";
public static final char SUBFIELD_S = 's';
public static final char INDICATOR = 'f';

Expand Down Expand Up @@ -152,6 +155,25 @@ public Future<Record> updateRecord(Record record, String tenantId) {
return recordDao.updateRecord(ensureRecordForeignKeys(record), tenantId);
}

@Override
public Future<Record> updateRecordGeneration(String matchedId, Record record, String tenantId) {
String marcField999s = getFieldFromMarcRecord(record, TAG_999, INDICATOR, INDICATOR, SUBFIELD_S);
if (!matchedId.equals(marcField999s)) {
return Future.failedFuture(new BadRequestException(format(MATCHED_ID_NOT_EQUAL_TO_999_FIELD, matchedId, marcField999s)));
}
record.setId(UUID.randomUUID().toString());

return recordDao.getRecordById(matchedId, tenantId)
.map(r -> r.orElseThrow(() -> new NotFoundException(format(RECORD_WITH_GIVEN_MATCHED_ID_NOT_FOUND, matchedId))))
.compose(v -> saveRecord(record, tenantId))
.recover(throwable -> {
if (throwable instanceof DuplicateRecordException) {
return Future.failedFuture(new BadRequestException(UPDATE_RECORD_DUPLICATE_EXCEPTION));
}
return Future.failedFuture(throwable);
});
}

@Override
public Future<SourceRecordCollection> getSourceRecords(Condition condition, RecordType recordType, Collection<OrderField<?>> orderFields,
int offset, int limit, String tenantId) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.everyItem;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue;

Expand All @@ -12,7 +13,6 @@
import java.util.UUID;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Lists;
import io.restassured.RestAssured;
import io.restassured.response.Response;
import io.vertx.core.json.JsonArray;
Expand Down Expand Up @@ -50,12 +50,14 @@ public class RecordApiTest extends AbstractRestVerticleTest {
private static final String SIXTH_UUID = UUID.randomUUID().toString();
private static final String SEVENTH_UUID = UUID.randomUUID().toString();
private static final String EIGHTH_UUID = UUID.randomUUID().toString();
private static final String GENERATION = "generation";

private static RawRecord rawMarcRecord;
private static ParsedRecord parsedMarcRecord;

private static RawRecord rawEdifactRecord;
private static ParsedRecord parsedEdifactRecord;
private static ParsedRecord parsedMarcRecordWith999ff$s;

static {
try {
Expand All @@ -67,6 +69,13 @@ public class RecordApiTest extends AbstractRestVerticleTest {
.withContent(new ObjectMapper().readValue(TestUtil.readFileFromPath(RAW_EDIFACT_RECORD_CONTENT_SAMPLE_PATH), String.class));
parsedEdifactRecord = new ParsedRecord()
.withContent(new ObjectMapper().readValue(TestUtil.readFileFromPath(PARSED_EDIFACT_RECORD_CONTENT_SAMPLE_PATH), JsonObject.class).encode());
parsedMarcRecordWith999ff$s = new ParsedRecord().withId(FIRST_UUID)
.withContent(new JsonObject().put("leader", "01542ccm a2200361 4500")
.put("fields", new JsonArray().add(new JsonObject().put("999", new JsonObject()
.put("subfields",
new JsonArray().add(new JsonObject().put("s", FIRST_UUID)))
.put("ind1", "f")
.put("ind2", "f")))).encode());
} catch (IOException e) {
e.printStackTrace();
}
Expand Down Expand Up @@ -589,6 +598,120 @@ public void shouldUpdateErrorRecordOnPut(TestContext testContext) {
async.complete();
}

@Test
public void shouldSendBadRequestWhen999ff$sIsNullDuringUpdateRecordGeneration(TestContext testContext) {
postSnapshots(testContext, snapshot_1);

Async async = testContext.async();
Response createResponse = RestAssured.given()
.spec(spec)
.body(record_1)
.when()
.post(SOURCE_STORAGE_RECORDS_PATH);
assertThat(createResponse.statusCode(), is(HttpStatus.SC_CREATED));
Record createdRecord = createResponse.body().as(Record.class);

RestAssured.given()
.spec(spec)
.body(createdRecord)
.when()
.put(SOURCE_STORAGE_RECORDS_PATH + "/" + createdRecord.getId() + "/" + GENERATION)
.then()
.statusCode(HttpStatus.SC_BAD_REQUEST);
async.complete();
}

@Test
public void shouldSendBadRequestWhenMatchedIfNotEqualTo999ff$sDuringUpdateRecordGeneration(TestContext testContext) {
postSnapshots(testContext, snapshot_1);

Async async = testContext.async();
Response createResponse = RestAssured.given()
.spec(spec)
.body(record_1.withParsedRecord(parsedMarcRecordWith999ff$s))
.when()
.post(SOURCE_STORAGE_RECORDS_PATH);
assertThat(createResponse.statusCode(), is(HttpStatus.SC_CREATED));
Record createdRecord = createResponse.body().as(Record.class);

RestAssured.given()
.spec(spec)
.body(createdRecord)
.when()
.put(SOURCE_STORAGE_RECORDS_PATH + "/" + UUID.randomUUID() + "/" + GENERATION)
.then()
.statusCode(HttpStatus.SC_BAD_REQUEST);
async.complete();
}

@Test
public void shouldSendNotFoundWhenUpdateRecordGenerationForNonExistingRecord(TestContext testContext) {
Async async = testContext.async();
RestAssured.given()
.spec(spec)
.body(record_1.withParsedRecord(parsedMarcRecordWith999ff$s))
.when()
.put(SOURCE_STORAGE_RECORDS_PATH + "/" + record_1.getMatchedId() + "/" + GENERATION)
.then()
.statusCode(HttpStatus.SC_NOT_FOUND);
async.complete();
}

@Test
public void shouldSendBadRequestWhenUpdateRecordGenerationWithDuplicate(TestContext testContext) {
postSnapshots(testContext, snapshot_1);

Async async = testContext.async();
Response createResponse = RestAssured.given()
.spec(spec)
.body(record_1.withParsedRecord(parsedMarcRecordWith999ff$s))
.when()
.post(SOURCE_STORAGE_RECORDS_PATH);
assertThat(createResponse.statusCode(), is(HttpStatus.SC_CREATED));
Record createdRecord = createResponse.body().as(Record.class);

postSnapshots(testContext, snapshot_2);
Record recordForUpdate = createdRecord.withSnapshotId(snapshot_2.getJobExecutionId());

RestAssured.given()
.spec(spec)
.body(recordForUpdate)
.when()
.put(SOURCE_STORAGE_RECORDS_PATH + "/" + createdRecord.getMatchedId() + "/" + GENERATION)
.then()
.statusCode(HttpStatus.SC_BAD_REQUEST);
async.complete();
}

@Test
public void shouldUpdateRecordGeneration(TestContext testContext) {
postSnapshots(testContext, snapshot_1);

Async async = testContext.async();
Response createResponse = RestAssured.given()
.spec(spec)
.body(record_1.withParsedRecord(parsedMarcRecordWith999ff$s))
.when()
.post(SOURCE_STORAGE_RECORDS_PATH);
assertThat(createResponse.statusCode(), is(HttpStatus.SC_CREATED));
Record createdRecord = createResponse.body().as(Record.class);

postSnapshots(testContext, snapshot_2);
Record recordForUpdate = createdRecord.withSnapshotId(snapshot_2.getJobExecutionId()).withGeneration(null);

RestAssured.given()
.spec(spec)
.body(recordForUpdate)
.when()
.put(SOURCE_STORAGE_RECORDS_PATH + "/" + createdRecord.getMatchedId() + "/" + GENERATION)
.then()
.statusCode(HttpStatus.SC_OK)
.body("id", not(createdRecord.getId()))
.body("matchedId", is(recordForUpdate.getMatchedId()))
.body("generation", is(1));
async.complete();
}

@Test
public void shouldReturnNotFoundOnGetByIdWhenRecordDoesNotExist() {
RestAssured.given()
Expand Down
Loading

0 comments on commit 4ca9f12

Please sign in to comment.