Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CIRC-2138: added sync for request table post PrintEvent insertions #487

Merged
merged 10 commits into from
Sep 25, 2024
24 changes: 24 additions & 0 deletions ramls/request.json
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,30 @@
"description": "Tags",
"$ref": "raml-util/schemas/tags.schema"
},
"printDetails": {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As you are adding a new section in request.json I think you need to bump up the interface version of this module if not done already.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed-> a0e8d4b

"type": "object",
"description": "PrintDetails",
"properties": {
"printCount": {
"type": "integer",
"description": "Number of times print slip generated."
},
"requesterId": {
"type": "string",
"description": "UUID of print slip requester."
},
"isPrinted": {
"type": "boolean",
"description": "Whether print slip was printed in past."
},
"printEventDate": {
"type": "string",
"format": "date-time",
"description": "Date and time when print slip was generated last time."
}
},
"additionalProperties": false
},
"awaitingPickupRequestClosedDate": {
"description": "A date when the request with awaiting pickup status was closed",
"type": "string",
Expand Down
6 changes: 1 addition & 5 deletions src/main/java/org/folio/rest/impl/PrintEventsApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,14 @@
import javax.ws.rs.core.Response;
import java.util.Map;

import static io.vertx.core.Future.succeededFuture;

public class PrintEventsApi implements PrintEventsStorage {
private static final Logger LOG = LoggerFactory.getLogger(PrintEventsApi.class);

@Override
public void postPrintEventsStoragePrintEventsEntry(PrintEventsRequest printEventsRequest, Map<String, String> okapiHeaders, Handler<AsyncResult<Response>> asyncResultHandler, Context vertxContext) {
LOG.info("postPrintEventsStoragePrintEvents:: save print events {}", printEventsRequest);
new PrintEventsService(vertxContext, okapiHeaders)
.create(printEventsRequest)
.onSuccess(response -> asyncResultHandler.handle(succeededFuture(response)))
.onFailure(throwable -> asyncResultHandler.handle(succeededFuture(PostPrintEventsStoragePrintEventsEntryResponse.respond500WithTextPlain(throwable.getMessage()))));
.create(printEventsRequest, asyncResultHandler);
}

@Override
Expand Down
89 changes: 80 additions & 9 deletions src/main/java/org/folio/service/PrintEventsService.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import io.vertx.core.AsyncResult;
import io.vertx.core.Context;
import io.vertx.core.Future;
import io.vertx.core.Handler;
import io.vertx.sqlclient.Row;
import io.vertx.sqlclient.RowSet;
Expand All @@ -14,28 +13,31 @@
import org.folio.rest.model.PrintEvent;
import org.folio.rest.persist.PgUtil;
import org.folio.rest.persist.PostgresClient;
import org.folio.rest.tools.utils.MetadataUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.ws.rs.core.Response;
import java.text.SimpleDateFormat;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
import java.util.stream.Collectors;

import static io.vertx.core.Future.succeededFuture;
import static org.folio.rest.persist.PgUtil.postgresClient;
import static org.folio.rest.persist.PostgresClient.convertToPsqlStandard;
import static org.folio.support.ModuleConstants.PRINT_EVENTS_TABLE;
import static org.folio.support.ModuleConstants.REQUEST_TABLE;

public class PrintEventsService {

private static final Logger LOG = LoggerFactory.getLogger(PrintEventsService.class);
private static final int MAX_ENTITIES = 10000;
private final Context vertxContext;
private final Map<String, String> okapiHeaders;
private final PostgresClient postgresClient;

private static final String PRINT_EVENT_FETCH_QUERY = """
WITH cte AS (
Expand All @@ -53,31 +55,100 @@ ORDER BY (jsonb->>'printEventDate')::timestamptz DESC) AS rank
rank = 1;
""";

private static String requestPrintSyncQueryString = """
WITH print_counts AS (
SELECT
jsonb->>'requestId' AS request_id,
COUNT(*) AS print_count
FROM %s
WHERE jsonb->>'requestId' IN (%s)
GROUP BY jsonb->>'requestId'
)
UPDATE %s
SET jsonb =
(jsonb
|| jsonb_build_object(
'printDetails',
jsonb_build_object(
'printCount', print_counts.print_count,
'requesterId', %s,
'isPrinted', true,
'printEventDate', %s
)
)
)
FROM print_counts
WHERE id = print_counts.request_id::uuid;
""";



public PrintEventsService(Context vertxContext, Map<String, String> okapiHeaders) {
this.vertxContext = vertxContext;
this.okapiHeaders = okapiHeaders;
this.postgresClient = PgUtil.postgresClient(vertxContext, okapiHeaders);
}

public Future<Response> create(PrintEventsRequest printEventRequest) {
public void create(PrintEventsRequest printEventRequest,
Handler<AsyncResult<Response>> asyncResultHandler) {
LOG.info("create:: save print events {}", printEventRequest);
List<PrintEvent> printEvents = printEventRequest.getRequestIds().stream().map(requestId -> {
List<PrintEvent> printEvents =
printEventRequest.getRequestIds().stream().map(requestId -> {
PrintEvent event = new PrintEvent();
event.setRequestId(requestId);
event.setRequesterId(printEventRequest.getRequesterId());
event.setRequesterName(printEventRequest.getRequesterName());
event.setPrintEventDate(printEventRequest.getPrintEventDate());
return event;
}).toList();
return PgUtil.postSync(PRINT_EVENTS_TABLE, printEvents, MAX_ENTITIES, false, okapiHeaders, vertxContext,
PrintEventsStorage.PostPrintEventsStoragePrintEventsEntryResponse.class);
try {
MetadataUtil.populateMetadata(printEvents, okapiHeaders);
} catch (Exception e) {
String msg =
"Cannot populate metadata of printEvents list elements: " + e.getMessage();
LOG.error(msg, e);
asyncResultHandler.handle(succeededFuture(PrintEventsStorage.PostPrintEventsStoragePrintEventsEntryResponse.respond500WithTextPlain(msg)));
return;
}

postgresClient.withTrans(conn -> conn.saveBatch(PRINT_EVENTS_TABLE,
printEvents)
.compose(printEventsResult -> conn.execute(
buildRequestSyncQuery(printEventRequest, okapiHeaders)
))).onFailure(handler ->
asyncResultHandler.handle(
succeededFuture(PrintEventsStorage.PostPrintEventsStoragePrintEventsEntryResponse.respond500WithTextPlain(handler.getMessage()))
)
).onSuccess(handler ->
asyncResultHandler.handle(
succeededFuture(PrintEventsStorage.PostPrintEventsStoragePrintEventsEntryResponse.respond201())
));
}

private String buildRequestSyncQuery(PrintEventsRequest printEventRequest,
Map<String, String> okapiHeaders) {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
df.setTimeZone(TimeZone.getTimeZone(ZoneOffset.UTC));

String tenantId = okapiHeaders.get(RestVerticle.OKAPI_HEADER_TENANT);
String printEventTableName =
convertToPsqlStandard(tenantId) + "." + PRINT_EVENTS_TABLE;
String requestTableName =
convertToPsqlStandard(tenantId) + "." + REQUEST_TABLE;
String requestIds = printEventRequest.getRequestIds().stream()
.map(requestId -> "'" + requestId + "'")
.collect(Collectors.joining(", "));
String requesterId = "'" + printEventRequest.getRequesterId() + "'";
String printEventDate =
"'" + df.format(printEventRequest.getPrintEventDate()) + "'";

return requestPrintSyncQueryString.formatted(printEventTableName,
requestIds, requestTableName, requesterId,
printEventDate);
}

public void getPrintEventRequestDetails(List<String> requestIds, Handler<AsyncResult<Response>> asyncResultHandler) {
LOG.debug("getPrintEventRequestDetails:: Fetching print event details for requestIds {}", requestIds);
String tenantId = okapiHeaders.get(RestVerticle.OKAPI_HEADER_TENANT);
PostgresClient postgresClient = postgresClient(vertxContext, okapiHeaders);
postgresClient.execute(formatQuery(tenantId, requestIds), handler -> {
try {
if (handler.succeeded()) {
Expand Down
13 changes: 13 additions & 0 deletions src/test/java/org/folio/rest/api/PrintEventsAPITest.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

import static org.folio.rest.support.http.InterfaceUrls.printEventsUrl;
import static org.folio.rest.support.matchers.HttpResponseStatusCodeMatchers.isCreated;
import static org.folio.rest.support.matchers.HttpResponseStatusCodeMatchers.isInternalServerError;
import static org.folio.rest.support.matchers.HttpResponseStatusCodeMatchers.isOk;
import static org.folio.rest.support.matchers.HttpResponseStatusCodeMatchers.isUnprocessableEntity;
import static org.hamcrest.core.Is.is;
Expand Down Expand Up @@ -180,6 +181,18 @@ public void getPrintEventStatusWithInvalidRequestIds() throws MalformedURLExcept
assertThat(jsonObject.getJsonArray("printEventsStatusResponses").size(), is(0));
}

@Test
public void createPrintEventLogAndValidate5XX() throws MalformedURLException,
ExecutionException, InterruptedException {
JsonObject printEventsJson = getPrintEvent();
final CompletableFuture<JsonResponse> postCompleted = new CompletableFuture<>();
client.post(printEventsUrl("/print-events-entry"), printEventsJson,
"INVALID_TENANT_ID",
ResponseHandler.json(postCompleted));
final JsonResponse postResponse = postCompleted.get();
assertThat(postResponse, isInternalServerError());
}

private JsonObject getPrintEvent() {
List<String> requestIds = List.of("5f5751b4-e352-4121-adca-204b0c2aec43", "5f5751b4-e352-4121-adca-204b0c2aec44");
return new JsonObject()
Expand Down