Search in sources :

Example 6 with ExternalIdsHolder

use of org.folio.rest.jaxrs.model.ExternalIdsHolder in project mod-source-record-storage by folio-org.

the class SourceStorageBatchApiTest method shouldReturnIdWhenRecordTypeIsMarcHoldings.

@Test
public void shouldReturnIdWhenRecordTypeIsMarcHoldings(TestContext testContext) {
    postSnapshots(testContext, snapshot_1, snapshot_2);
    Record recordMarcHoldings = new Record().withId(FOURTH_UUID).withSnapshotId(snapshot_2.getJobExecutionId()).withRecordType(RecordType.MARC_HOLDING).withRawRecord(rawRecord).withParsedRecord(marcRecord).withMatchedId(FOURTH_UUID).withOrder(1).withExternalIdsHolder(new ExternalIdsHolder().withInstanceId(UUID.randomUUID().toString()).withInstanceHrid(VALID_HRID)).withState(Record.State.OLD);
    postRecords(testContext, record_1, record_2, record_3, recordMarcHoldings);
    Async async = testContext.async();
    RestAssured.given().spec(spec).body(Collections.singletonList(VALID_HRID)).when().post(SOURCE_STORAGE_BATCH_VERIFIED_RECORDS).then().statusCode(HttpStatus.SC_OK).body("invalidMarcBibIds", contains(VALID_HRID));
    async.complete();
}
Also used : ExternalIdsHolder(org.folio.rest.jaxrs.model.ExternalIdsHolder) Async(io.vertx.ext.unit.Async) RawRecord(org.folio.rest.jaxrs.model.RawRecord) Record(org.folio.rest.jaxrs.model.Record) ErrorRecord(org.folio.rest.jaxrs.model.ErrorRecord) ParsedRecord(org.folio.rest.jaxrs.model.ParsedRecord) Test(org.junit.Test)

Example 7 with ExternalIdsHolder

use of org.folio.rest.jaxrs.model.ExternalIdsHolder in project mod-source-record-storage by folio-org.

the class AdditionalFieldsUtilTest method shouldNotAdd035AndAdd001FieldsIf001And003FieldsNotExists.

@Test
public void shouldNotAdd035AndAdd001FieldsIf001And003FieldsNotExists() {
    // given
    String parsedContent = "{\"leader\":\"00115nam  22000731a 4500\",\"fields\":[{\"003\":\"in001\"},{\"507\":{\"subfields\":[{\"a\":\"data\"}],\"ind1\":\" \",\"ind2\":\" \"}},{\"500\":{\"subfields\":[{\"a\":\"data\"}],\"ind1\":\" \",\"ind2\":\" \"}}]}";
    String expectedParsedContent = "{\"leader\":\"00086nam  22000611a 4500\",\"fields\":[{\"001\":\"in001\"},{\"507\":{\"subfields\":[{\"a\":\"data\"}],\"ind1\":\" \",\"ind2\":\" \"}},{\"500\":{\"subfields\":[{\"a\":\"data\"}],\"ind1\":\" \",\"ind2\":\" \"}}]}";
    ParsedRecord parsedRecord = new ParsedRecord();
    parsedRecord.setContent(parsedContent);
    Record record = new Record().withId(UUID.randomUUID().toString()).withParsedRecord(parsedRecord).withGeneration(0).withState(Record.State.ACTUAL).withExternalIdsHolder(new ExternalIdsHolder().withInstanceId("001").withInstanceHrid("in001"));
    JsonObject jsonObject = new JsonObject("{\"hrid\":\"in001\"}");
    Pair<Record, JsonObject> pair = Pair.of(record, jsonObject);
    // when
    AdditionalFieldsUtil.fillHrIdFieldInMarcRecord(pair);
    // then
    Assert.assertEquals(expectedParsedContent, parsedRecord.getContent());
}
Also used : ExternalIdsHolder(org.folio.rest.jaxrs.model.ExternalIdsHolder) JsonObject(io.vertx.core.json.JsonObject) Record(org.folio.rest.jaxrs.model.Record) ParsedRecord(org.folio.rest.jaxrs.model.ParsedRecord) ParsedRecord(org.folio.rest.jaxrs.model.ParsedRecord) Test(org.junit.Test)

Example 8 with ExternalIdsHolder

use of org.folio.rest.jaxrs.model.ExternalIdsHolder in project mod-source-record-storage by folio-org.

the class RecordDaoImpl method updateParsedRecords.

@Override
public Future<ParsedRecordsBatchResponse> updateParsedRecords(RecordCollection recordCollection, String tenantId) {
    Promise<ParsedRecordsBatchResponse> promise = Promise.promise();
    Set<String> recordTypes = new HashSet<>();
    List<Record> records = new ArrayList<>();
    List<String> errorMessages = new ArrayList<>();
    List<UpdateConditionStep<RecordsLbRecord>> recordUpdates = new ArrayList<>();
    List<UpdateConditionStep<org.jooq.Record>> parsedRecordUpdates = new ArrayList<>();
    Field<UUID> prtId = field(name(ID), UUID.class);
    Field<JSONB> prtContent = field(name(CONTENT), JSONB.class);
    List<ParsedRecord> parsedRecords = recordCollection.getRecords().stream().map(this::validateParsedRecordId).peek(record -> {
        // make sure only one record type
        recordTypes.add(record.getRecordType().name());
        if (recordTypes.size() > 1) {
            throw new BadRequestException("Batch record collection only supports single record type");
        }
        UpdateSetFirstStep<RecordsLbRecord> updateFirstStep = DSL.update(RECORDS_LB);
        UpdateSetMoreStep<RecordsLbRecord> updateStep = null;
        // check for external record properties to update
        ExternalIdsHolder externalIdsHolder = record.getExternalIdsHolder();
        AdditionalInfo additionalInfo = record.getAdditionalInfo();
        Metadata metadata = record.getMetadata();
        if (Objects.nonNull(externalIdsHolder)) {
            var recordType = record.getRecordType();
            String externalId = getExternalId(externalIdsHolder, recordType);
            String externalHrid = getExternalHrid(externalIdsHolder, recordType);
            if (StringUtils.isNotEmpty(externalId)) {
                updateStep = updateFirstStep.set(RECORDS_LB.EXTERNAL_ID, UUID.fromString(externalId));
            }
            if (StringUtils.isNotEmpty(externalHrid)) {
                updateStep = (Objects.isNull(updateStep) ? updateFirstStep : updateStep).set(RECORDS_LB.EXTERNAL_HRID, externalHrid);
            }
        }
        if (Objects.nonNull(additionalInfo)) {
            if (Objects.nonNull(additionalInfo.getSuppressDiscovery())) {
                updateStep = (Objects.isNull(updateStep) ? updateFirstStep : updateStep).set(RECORDS_LB.SUPPRESS_DISCOVERY, additionalInfo.getSuppressDiscovery());
            }
        }
        if (Objects.nonNull(metadata)) {
            if (StringUtils.isNotEmpty(metadata.getCreatedByUserId())) {
                updateStep = (Objects.isNull(updateStep) ? updateFirstStep : updateStep).set(RECORDS_LB.CREATED_BY_USER_ID, UUID.fromString(metadata.getCreatedByUserId()));
            }
            if (Objects.nonNull(metadata.getCreatedDate())) {
                updateStep = (Objects.isNull(updateStep) ? updateFirstStep : updateStep).set(RECORDS_LB.CREATED_DATE, metadata.getCreatedDate().toInstant().atOffset(ZoneOffset.UTC));
            }
            if (StringUtils.isNotEmpty(metadata.getUpdatedByUserId())) {
                updateStep = (Objects.isNull(updateStep) ? updateFirstStep : updateStep).set(RECORDS_LB.UPDATED_BY_USER_ID, UUID.fromString(metadata.getUpdatedByUserId()));
            }
            if (Objects.nonNull(metadata.getUpdatedDate())) {
                updateStep = (Objects.isNull(updateStep) ? updateFirstStep : updateStep).set(RECORDS_LB.UPDATED_DATE, metadata.getUpdatedDate().toInstant().atOffset(ZoneOffset.UTC));
            }
        }
        // only attempt update if has id and external values to update
        if (Objects.nonNull(updateStep) && Objects.nonNull(record.getId())) {
            records.add(record);
            recordUpdates.add(updateStep.where(RECORDS_LB.ID.eq(UUID.fromString(record.getId()))));
        }
        try {
            RecordType recordType = toRecordType(record.getRecordType().name());
            recordType.formatRecord(record);
            parsedRecordUpdates.add(DSL.update(table(name(recordType.getTableName()))).set(prtContent, JSONB.valueOf(ParsedRecordDaoUtil.normalizeContent(record.getParsedRecord()))).where(prtId.eq(UUID.fromString(record.getParsedRecord().getId()))));
        } catch (Exception e) {
            errorMessages.add(format(INVALID_PARSED_RECORD_MESSAGE_TEMPLATE, record.getId(), e.getMessage()));
            // if invalid parsed record, set id to null to filter out
            record.getParsedRecord().setId(null);
        }
    }).map(Record::getParsedRecord).filter(parsedRecord -> Objects.nonNull(parsedRecord.getId())).collect(Collectors.toList());
    try (Connection connection = getConnection(tenantId)) {
        DSL.using(connection).transaction(ctx -> {
            DSLContext dsl = DSL.using(ctx);
            // update records
            int[] recordUpdateResults = dsl.batch(recordUpdates).execute();
            // check record update results
            for (int i = 0; i < recordUpdateResults.length; i++) {
                int result = recordUpdateResults[i];
                if (result == 0) {
                    errorMessages.add(format("Record with id %s was not updated", records.get(i).getId()));
                }
            }
            // update parsed records
            int[] parsedRecordUpdateResults = dsl.batch(parsedRecordUpdates).execute();
            // check parsed record update results
            List<ParsedRecord> parsedRecordsUpdated = new ArrayList<>();
            for (int i = 0; i < parsedRecordUpdateResults.length; i++) {
                int result = parsedRecordUpdateResults[i];
                ParsedRecord parsedRecord = parsedRecords.get(i);
                if (result == 0) {
                    errorMessages.add(format("Parsed Record with id '%s' was not updated", parsedRecord.getId()));
                } else {
                    parsedRecordsUpdated.add(parsedRecord);
                }
            }
            promise.complete(new ParsedRecordsBatchResponse().withErrorMessages(errorMessages).withParsedRecords(parsedRecordsUpdated).withTotalRecords(parsedRecordsUpdated.size()));
        });
    } catch (SQLException e) {
        LOG.error("Failed to update records", e);
        promise.fail(e);
    }
    return promise.future();
}
Also used : DSL(org.jooq.impl.DSL) RecordsLbRecord(org.folio.rest.jooq.tables.records.RecordsLbRecord) MarcBibCollection(org.folio.rest.jaxrs.model.MarcBibCollection) DSL.field(org.jooq.impl.DSL.field) Autowired(org.springframework.beans.factory.annotation.Autowired) RecordSearchParameters(org.folio.services.RecordSearchParameters) DSL.condition(org.jooq.impl.DSL.condition) StringUtils(org.apache.commons.lang3.StringUtils) SnapshotsLbRecord(org.folio.rest.jooq.tables.records.SnapshotsLbRecord) Condition(org.jooq.Condition) DSL.trueCondition(org.jooq.impl.DSL.trueCondition) RecordsBatchResponse(org.folio.rest.jaxrs.model.RecordsBatchResponse) RawRecordsLbRecord(org.folio.rest.jooq.tables.records.RawRecordsLbRecord) Record2(org.jooq.Record2) Map(java.util.Map) ErrorRecordsLbRecord(org.folio.rest.jooq.tables.records.ErrorRecordsLbRecord) Metadata(org.folio.rest.jaxrs.model.Metadata) ZoneOffset(java.time.ZoneOffset) RAW_RECORDS_LB(org.folio.rest.jooq.Tables.RAW_RECORDS_LB) GenericCompositeFuture(org.folio.okapi.common.GenericCompositeFuture) Set(java.util.Set) SnapshotDaoUtil(org.folio.dao.util.SnapshotDaoUtil) RecordCollection(org.folio.rest.jaxrs.model.RecordCollection) QueryResult(io.github.jklingsporn.vertx.jooq.shared.internal.QueryResult) Logger(org.apache.logging.log4j.Logger) StrSubstitutor(org.apache.commons.lang.text.StrSubstitutor) ParsedRecord(org.folio.rest.jaxrs.model.ParsedRecord) SelectJoinStep(org.jooq.SelectJoinStep) PARSED_RECORD_CONTENT(org.folio.dao.util.ParsedRecordDaoUtil.PARSED_RECORD_CONTENT) MARC_BIB(org.folio.rest.jooq.enums.RecordType.MARC_BIB) ArrayList(java.util.ArrayList) RecordState(org.folio.rest.jooq.enums.RecordState) RECORDS_LB(org.folio.rest.jooq.Tables.RECORDS_LB) UpdateSetFirstStep(org.jooq.UpdateSetFirstStep) SQLException(java.sql.SQLException) RAW_RECORD_CONTENT(org.folio.dao.util.RawRecordDaoUtil.RAW_RECORD_CONTENT) Lists(com.google.common.collect.Lists) Flowable(io.reactivex.Flowable) JobExecutionStatus(org.folio.rest.jooq.enums.JobExecutionStatus) ParsedRecordsBatchResponse(org.folio.rest.jaxrs.model.ParsedRecordsBatchResponse) LoaderError(org.jooq.LoaderError) ParseFieldsResult(org.folio.services.util.parser.ParseFieldsResult) ErrorRecord(org.folio.rest.jaxrs.model.ErrorRecord) UpdateSetMoreStep(org.jooq.UpdateSetMoreStep) Row(io.vertx.sqlclient.Row) RecordDaoUtil.getExternalHrid(org.folio.dao.util.RecordDaoUtil.getExternalHrid) DSL.table(org.jooq.impl.DSL.table) Connection(java.sql.Connection) Table(org.jooq.Table) IdType(org.folio.dao.util.IdType) UpdateConditionStep(org.jooq.UpdateConditionStep) DSLContext(org.jooq.DSLContext) BadRequestException(javax.ws.rs.BadRequestException) SNAPSHOT_NOT_STARTED_MESSAGE_TEMPLATE(org.folio.dao.util.SnapshotDaoUtil.SNAPSHOT_NOT_STARTED_MESSAGE_TEMPLATE) SortOrder(org.jooq.SortOrder) RecordDaoUtil.filterRecordByType(org.folio.dao.util.RecordDaoUtil.filterRecordByType) DSL.name(org.jooq.impl.DSL.name) DuplicateEventException(org.folio.kafka.exception.DuplicateEventException) Name(org.jooq.Name) RecordDaoUtil(org.folio.dao.util.RecordDaoUtil) Collection(java.util.Collection) RecordDaoUtil.filterRecordByState(org.folio.dao.util.RecordDaoUtil.filterRecordByState) Field(org.jooq.Field) UUID(java.util.UUID) ERROR_RECORDS_LB(org.folio.rest.jooq.Tables.ERROR_RECORDS_LB) Future(io.vertx.core.Future) Collectors(java.util.stream.Collectors) RecordDaoUtil.getExternalId(org.folio.dao.util.RecordDaoUtil.getExternalId) NotFoundException(javax.ws.rs.NotFoundException) String.format(java.lang.String.format) Objects(java.util.Objects) List(java.util.List) Optional(java.util.Optional) ErrorRecordDaoUtil(org.folio.dao.util.ErrorRecordDaoUtil) MatchField(org.folio.dao.util.MatchField) RECORD_NOT_FOUND_TEMPLATE(org.folio.dao.util.RecordDaoUtil.RECORD_NOT_FOUND_TEMPLATE) QueryParamUtil.toRecordType(org.folio.rest.util.QueryParamUtil.toRecordType) RawRecord(org.folio.rest.jaxrs.model.RawRecord) SNAPSHOT_NOT_FOUND_TEMPLATE(org.folio.dao.util.SnapshotDaoUtil.SNAPSHOT_NOT_FOUND_TEMPLATE) SNAPSHOTS_LB(org.folio.rest.jooq.Tables.SNAPSHOTS_LB) HashMap(java.util.HashMap) RawRecordDaoUtil(org.folio.dao.util.RawRecordDaoUtil) ParamType(org.jooq.conf.ParamType) Function(java.util.function.Function) HashSet(java.util.HashSet) RecordType(org.folio.dao.util.RecordType) ExternalIdsHolder(org.folio.rest.jaxrs.model.ExternalIdsHolder) DSL.countDistinct(org.jooq.impl.DSL.countDistinct) AdditionalInfo(org.folio.rest.jaxrs.model.AdditionalInfo) SourceRecord(org.folio.rest.jaxrs.model.SourceRecord) DataAccessException(org.jooq.exception.DataAccessException) PgPool(io.vertx.reactivex.pgclient.PgPool) Record(org.folio.rest.jaxrs.model.Record) Promise(io.vertx.core.Promise) ParseLeaderResult(org.folio.services.util.parser.ParseLeaderResult) ReactiveClassicGenericQueryExecutor(io.github.jklingsporn.vertx.jooq.classic.reactivepg.ReactiveClassicGenericQueryExecutor) ParsedRecordDaoUtil(org.folio.dao.util.ParsedRecordDaoUtil) Component(org.springframework.stereotype.Component) ERROR_RECORD_CONTENT(org.folio.dao.util.ErrorRecordDaoUtil.ERROR_RECORD_CONTENT) TypeConnection(org.folio.services.util.TypeConnection) DSL.max(org.jooq.impl.DSL.max) OrderField(org.jooq.OrderField) JSONB(org.jooq.JSONB) LogManager(org.apache.logging.log4j.LogManager) SourceRecordCollection(org.folio.rest.jaxrs.model.SourceRecordCollection) ArrayUtils(org.apache.commons.lang.ArrayUtils) UpdateConditionStep(org.jooq.UpdateConditionStep) UpdateSetMoreStep(org.jooq.UpdateSetMoreStep) SQLException(java.sql.SQLException) ArrayList(java.util.ArrayList) Metadata(org.folio.rest.jaxrs.model.Metadata) QueryParamUtil.toRecordType(org.folio.rest.util.QueryParamUtil.toRecordType) RecordType(org.folio.dao.util.RecordType) ParsedRecordsBatchResponse(org.folio.rest.jaxrs.model.ParsedRecordsBatchResponse) RecordsLbRecord(org.folio.rest.jooq.tables.records.RecordsLbRecord) SnapshotsLbRecord(org.folio.rest.jooq.tables.records.SnapshotsLbRecord) RawRecordsLbRecord(org.folio.rest.jooq.tables.records.RawRecordsLbRecord) ErrorRecordsLbRecord(org.folio.rest.jooq.tables.records.ErrorRecordsLbRecord) ParsedRecord(org.folio.rest.jaxrs.model.ParsedRecord) ErrorRecord(org.folio.rest.jaxrs.model.ErrorRecord) RawRecord(org.folio.rest.jaxrs.model.RawRecord) SourceRecord(org.folio.rest.jaxrs.model.SourceRecord) Record(org.folio.rest.jaxrs.model.Record) UUID(java.util.UUID) HashSet(java.util.HashSet) ExternalIdsHolder(org.folio.rest.jaxrs.model.ExternalIdsHolder) AdditionalInfo(org.folio.rest.jaxrs.model.AdditionalInfo) JSONB(org.jooq.JSONB) Connection(java.sql.Connection) TypeConnection(org.folio.services.util.TypeConnection) UpdateSetFirstStep(org.jooq.UpdateSetFirstStep) DSLContext(org.jooq.DSLContext) ParsedRecord(org.folio.rest.jaxrs.model.ParsedRecord) SQLException(java.sql.SQLException) BadRequestException(javax.ws.rs.BadRequestException) DuplicateEventException(org.folio.kafka.exception.DuplicateEventException) NotFoundException(javax.ws.rs.NotFoundException) DataAccessException(org.jooq.exception.DataAccessException) BadRequestException(javax.ws.rs.BadRequestException)

Example 9 with ExternalIdsHolder

use of org.folio.rest.jaxrs.model.ExternalIdsHolder in project mod-source-record-storage by folio-org.

the class RecordDaoUtil method toExternalIdsHolder.

private static ExternalIdsHolder toExternalIdsHolder(RecordsLb pojo) {
    ExternalIdsHolder externalIdsHolder = new ExternalIdsHolder();
    var externalIdOptional = Optional.ofNullable(pojo.getExternalId()).map(UUID::toString);
    var externalHridOptional = Optional.ofNullable(pojo.getExternalHrid());
    if (RecordType.MARC_BIB == pojo.getRecordType()) {
        externalIdOptional.ifPresent(externalIdsHolder::setInstanceId);
        externalHridOptional.ifPresent(externalIdsHolder::setInstanceHrid);
    } else if (RecordType.MARC_HOLDING == pojo.getRecordType()) {
        externalIdOptional.ifPresent(externalIdsHolder::setHoldingsId);
        externalHridOptional.ifPresent(externalIdsHolder::setHoldingsHrid);
    } else if (RecordType.MARC_AUTHORITY == pojo.getRecordType()) {
        externalIdOptional.ifPresent(externalIdsHolder::setAuthorityId);
        externalHridOptional.ifPresent(externalIdsHolder::setAuthorityHrid);
    }
    return externalIdsHolder;
}
Also used : ExternalIdsHolder(org.folio.rest.jaxrs.model.ExternalIdsHolder) UUID(java.util.UUID)

Example 10 with ExternalIdsHolder

use of org.folio.rest.jaxrs.model.ExternalIdsHolder in project mod-source-record-manager by folio-org.

the class ChangeManagerParsedRecordsAPITest method shouldUpdateParsedRecordOnPut.

@Test
public void shouldUpdateParsedRecordOnPut(TestContext testContext) throws InterruptedException {
    Async async = testContext.async();
    ParsedRecordDto parsedRecordDto = new ParsedRecordDto().withId(UUID.randomUUID().toString()).withParsedRecord(new ParsedRecord().withId(UUID.randomUUID().toString()).withContent("{\"leader\":\"01240cas a2200397   4500\",\"fields\":[]}")).withRecordType(ParsedRecordDto.RecordType.MARC_HOLDING).withRelatedRecordVersion("1").withExternalIdsHolder(new ExternalIdsHolder().withInstanceId(UUID.randomUUID().toString()));
    RestAssured.given().spec(spec).body(parsedRecordDto).when().put(PARSED_RECORDS_URL + "/" + parsedRecordDto.getId()).then().statusCode(HttpStatus.SC_ACCEPTED);
    String observeTopic = formatTopicName(kafkaConfig.getEnvId(), getDefaultNameSpace(), TENANT_ID, QMEventTypes.QM_RECORD_UPDATED.name());
    kafkaCluster.observeValues(ObserveKeyValues.on(observeTopic, 1).observeFor(30, TimeUnit.SECONDS).build());
    async.complete();
}
Also used : ExternalIdsHolder(org.folio.rest.jaxrs.model.ExternalIdsHolder) Async(io.vertx.ext.unit.Async) ParsedRecordDto(org.folio.rest.jaxrs.model.ParsedRecordDto) ParsedRecord(org.folio.rest.jaxrs.model.ParsedRecord) Test(org.junit.Test) AbstractRestTest(org.folio.rest.impl.AbstractRestTest)

Aggregations

ExternalIdsHolder (org.folio.rest.jaxrs.model.ExternalIdsHolder)25 ParsedRecord (org.folio.rest.jaxrs.model.ParsedRecord)22 Record (org.folio.rest.jaxrs.model.Record)22 Test (org.junit.Test)18 RawRecord (org.folio.rest.jaxrs.model.RawRecord)16 Async (io.vertx.ext.unit.Async)15 JsonObject (io.vertx.core.json.JsonObject)11 ErrorRecord (org.folio.rest.jaxrs.model.ErrorRecord)8 Date (java.util.Date)6 HashMap (java.util.HashMap)6 Snapshot (org.folio.rest.jaxrs.model.Snapshot)6 SourceRecord (org.folio.rest.jaxrs.model.SourceRecord)6 Before (org.junit.Before)6 JsonArray (io.vertx.core.json.JsonArray)5 UUID (java.util.UUID)5 ArrayList (java.util.ArrayList)4 List (java.util.List)4 DataImportEventPayload (org.folio.DataImportEventPayload)4 SnapshotDaoUtil (org.folio.dao.util.SnapshotDaoUtil)4 ObjectMapper (com.fasterxml.jackson.databind.ObjectMapper)3