Skip to content

Commit

Permalink
MODINVSTOR-1284 User can delete local Subject types/sources when it l…
Browse files Browse the repository at this point in the history
…inked to Instance (#1119)

* MODINVSTOR-1284 User can delete local Subject types/sources when it linked to Instance

* add test

* fix checkstyle

* add additional test

* upd msg

* code review

* fix codestyle

* add indexes

* add indexes

* remove redundant changes

* some changes for clean up

* increase coverage

* increase coverage

* Update NEWS.md

Co-authored-by: Pavlo Smahin <[email protected]>

* pr review

* clean up

* add batch operations

* fix checkstyle

* add more test, update create batch instances

* make creation of instance and linking subjects transactional

* checkstyle

* issues with asyn migration job

* decrease number of recs in async test, to prevent timeout errors

---------

Co-authored-by: Pavlo Smahin <[email protected]>
  • Loading branch information
JavokhirAbdullayev and psmagin authored Dec 18, 2024
1 parent d88858c commit e4830e6
Show file tree
Hide file tree
Showing 15 changed files with 509 additions and 44 deletions.
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
* Requires `API_NAME vX.Y`

### Features
* Unable to delete local Subject types/sources when they are linked to an Instance ([MODINVSTOR-1284](https://folio-org.atlassian.net/browse/MODINVSTOR-1284))
* Modify endpoint for bulk instances upsert with publish events flag ([MODINVSTOR-1283](https://folio-org.atlassian.net/browse/MODINVSTOR-1283))
* Change Kafka event publishing keys for holdings and items ([MODINVSTOR-1281](https://folio-org.atlassian.net/browse/MODINVSTOR-1281))
* Merge custom ECS TLR feature branch into master ([MODINVSTOR-1262](https://folio-org.atlassian.net/browse/MODINVSTOR-1262))
Expand Down
101 changes: 101 additions & 0 deletions src/main/java/org/folio/persist/InstanceRepository.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import io.vertx.core.Future;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.pgclient.PgException;
import io.vertx.sqlclient.Row;
import io.vertx.sqlclient.RowSet;
import io.vertx.sqlclient.RowStream;
Expand All @@ -20,12 +21,14 @@
import java.util.stream.Collectors;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.apache.commons.lang3.tuple.Pair;
import org.folio.cql2pgjson.CQL2PgJSON;
import org.folio.cql2pgjson.exception.FieldException;
import org.folio.dbschema.ObjectMapperTool;
import org.folio.rest.exceptions.BadRequestException;
import org.folio.rest.jaxrs.model.Instance;
import org.folio.rest.jaxrs.model.ResultInfo;
import org.folio.rest.persist.Conn;
import org.folio.rest.persist.SQLConnection;
import org.folio.rest.persist.cql.CQLQueryValidationException;
import org.folio.rest.persist.cql.CQLWrapper;
Expand All @@ -35,11 +38,109 @@ public class InstanceRepository extends AbstractRepository<Instance> {
private static final String INSTANCE_SET_VIEW = "instance_set";
private static final String INSTANCE_HOLDINGS_ITEM_VIEW = "instance_holdings_item_view";
private static final String INVENTORY_VIEW_JSONB_FIELD = "inventory_view.jsonb";
private static final String INSTANCE_SUBJECT_SOURCE_TABLE = "instance_subject_source";
private static final String INSTANCE_SUBJECT_TYPE_TABLE = "instance_subject_type";


public InstanceRepository(Context context, Map<String, String> okapiHeaders) {
super(postgresClient(context, okapiHeaders), INSTANCE_TABLE, Instance.class);
}

public Future<RowSet<Row>> unlinkInstanceFromSubjectSource(Conn conn, String instanceId) {
try {
String sql = unlinkInstanceFromSubjectSql(INSTANCE_SUBJECT_SOURCE_TABLE, instanceId);
return conn.execute(sql);
} catch (PgException e) {
return Future.failedFuture(new BadRequestException(e.getMessage()));
}
}

public Future<RowSet<Row>> unlinkInstanceFromSubjectType(Conn conn, String instanceId) {
try {
String sql = unlinkInstanceFromSubjectSql(INSTANCE_SUBJECT_TYPE_TABLE, instanceId);
return conn.execute(sql);
} catch (PgException e) {
return Future.failedFuture(new BadRequestException(e.getMessage()));
}
}

private String unlinkInstanceFromSubjectSql(String table, String id) {
return String.format("DELETE FROM %s WHERE instance_id = '%s'; ",
postgresClientFuturized.getFullTableName(table), id);
}

public Future<RowSet<Row>> batchLinkSubjectSource(Conn conn, List<Pair<String, String>> sourcePairs) {
try {
String sql = """
INSERT INTO %s (instance_id, source_id)
VALUES %s
ON CONFLICT DO NOTHING;
"""
.formatted(
postgresClientFuturized.getFullTableName(INSTANCE_SUBJECT_SOURCE_TABLE),
sourcePairs.stream()
.map(pair -> String.format("('%s', '%s')", pair.getKey(), pair.getValue()))
.collect(Collectors.joining(", "))
);
return conn.execute(sql);
} catch (PgException e) {
return Future.failedFuture(new BadRequestException(e.getMessage()));
}
}

public Future<RowSet<Row>> batchLinkSubjectType(Conn conn, List<Pair<String, String>> typePairs) {
try {
String sql = """
INSERT INTO %s (instance_id, type_id)
VALUES %s
ON CONFLICT DO NOTHING;
"""
.formatted(
postgresClientFuturized.getFullTableName(INSTANCE_SUBJECT_TYPE_TABLE),
typePairs.stream()
.map(pair -> String.format("('%s', '%s')", pair.getKey(), pair.getValue()))
.collect(Collectors.joining(", "))
);
return conn.execute(sql);
} catch (PgException e) {
return Future.failedFuture(new BadRequestException(e.getMessage()));
}

}

public Future<RowSet<Row>> batchUnlinkSubjectSource(Conn conn, String instanceId, List<String> sourceIds) {
try {
String sql = """
DELETE FROM %s WHERE instance_id = '%s' AND source_id IN ( %s );
"""
.formatted(
postgresClientFuturized.getFullTableName(INSTANCE_SUBJECT_SOURCE_TABLE),
instanceId,
sourceIds.stream().map(id -> "'" + id + "'").collect(Collectors.joining(", "))
);
return conn.execute(sql);
} catch (PgException e) {
return Future.failedFuture(new BadRequestException(e.getMessage()));
}
}

public Future<RowSet<Row>> batchUnlinkSubjectType(Conn conn, String instanceId, List<String> typeIds) {
try {
String sql = """
DELETE FROM %s WHERE instance_id = '%s' AND type_id IN ( %s );
"""
.formatted(
postgresClientFuturized.getFullTableName(INSTANCE_SUBJECT_TYPE_TABLE),
instanceId,
typeIds.stream().map(id -> "'" + id + "'")
.collect(Collectors.joining(", "))
);
return conn.execute(sql);
} catch (PgException e) {
return Future.failedFuture(new BadRequestException(e.getMessage()));
}
}

public Future<RowStream<Row>> getAllIds(SQLConnection connection) {
return postgresClientFuturized.selectStream(connection,
"SELECT id FROM " + postgresClientFuturized.getFullTableName(INSTANCE_TABLE));
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/org/folio/rest/impl/InstanceBatchSyncApi.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package org.folio.rest.impl;

import static org.folio.rest.jaxrs.resource.InstanceStorageBatchSynchronous.PostInstanceStorageBatchSynchronousResponse.respond500WithTextPlain;
import static org.folio.rest.support.EndpointFailureHandler.handleFailure;

import io.vertx.core.AsyncResult;
import io.vertx.core.Context;
Expand All @@ -26,7 +26,7 @@ public void postInstanceStorageBatchSynchronous(boolean upsert, InstancesPost en

new InstanceService(vertxContext, okapiHeaders)
.createInstances(instances.getInstances(), upsert, true, true)
.otherwise(cause -> respond500WithTextPlain(cause.getMessage()))
.onFailure(handleFailure(asyncResultHandler))
.onComplete(asyncResultHandler);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package org.folio.rest.impl;

import static org.folio.rest.jaxrs.resource.InstanceStorageBatchSynchronousUnsafe.PostInstanceStorageBatchSynchronousUnsafeResponse.respond500WithTextPlain;
import static org.folio.rest.support.EndpointFailureHandler.handleFailure;

import io.vertx.core.AsyncResult;
import io.vertx.core.Context;
Expand All @@ -25,7 +25,7 @@ public void postInstanceStorageBatchSynchronousUnsafe(InstancesPost entity, Map<

new InstanceService(vertxContext, okapiHeaders)
.createInstances(instances.getInstances(), true, false, true)
.otherwise(cause -> respond500WithTextPlain(cause.getMessage()))
.onFailure(handleFailure(asyncResultHandler))
.onComplete(asyncResultHandler);
}
}
Loading

0 comments on commit e4830e6

Please sign in to comment.