Skip to content

Commit 117f2c3

Browse files
CIRCSTORE- 514 Implement Post API to fetch print Event Details (#471)
* CIRCSTORE-514 Adding a plain index for requestId field of jsonb column * CIRCSTORE-514 Adding a new endpoint to fetch request print details * CIRCSTORE-514 Adding new endpoint in module descriptor * CIRCSTORE-514 Adding test cases, example json files * CIRCSTORE-514 Adding try catch and loggers
1 parent 2ade190 commit 117f2c3

12 files changed

+363
-3
lines changed

descriptors/ModuleDescriptor-template.json

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -657,6 +657,15 @@
657657
"permissionsRequired": [
658658
"print-events-storage.print-events-entry.item.post"
659659
]
660+
},
661+
{
662+
"methods": [
663+
"POST"
664+
],
665+
"pathPattern": "/print-events-storage/print-events-status",
666+
"permissionsRequired": [
667+
"print-events-storage.print-events-status.item.post"
668+
]
660669
}
661670
]
662671
},
@@ -697,6 +706,11 @@
697706
"displayName": "print events storage - save print event logs",
698707
"description": "save print event log in storage"
699708
},
709+
{
710+
"permissionName": "print-events-storage.print-events-status.item.post",
711+
"displayName": "print-events-storage - Fetch print event status",
712+
"description": "Fetch print event details for a batch of request Ids"
713+
},
700714
{
701715
"permissionName": "check-in-storage.check-ins.collection.get",
702716
"displayName": "Check-in storage - get check-ins collection",
@@ -1154,7 +1168,8 @@
11541168
"circulation-storage.circulation-settings.item.post",
11551169
"circulation-storage.circulation-settings.item.put",
11561170
"circulation-storage.circulation-settings.item.delete",
1157-
"print-events-storage.print-events-entry.item.post"
1171+
"print-events-storage.print-events-entry.item.post",
1172+
"print-events-storage.print-events-status.item.post"
11581173
]
11591174
},
11601175
{
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"requestIds" : [
3+
"fbbbe691-d6c6-4f40-b9dd-7364ccb1518a",
4+
"fd831be3-f05f-4b6f-b68f-1a976ea1ab0f"
5+
]
6+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"requestId": "fbbbe691-d6c6-4f40-b9dd-7364ccb1518a",
3+
"requesterId": "44642483-f4d4-4a29-a2ba-8eefcf53de16",
4+
"requesterName": "vignesh",
5+
"count": 2,
6+
"printEventDate": "2024-07-04T07:07:00.000+00:00"
7+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"printEventsStatusResponses": [
3+
{
4+
"requestId": "fbbbe691-d6c6-4f40-b9dd-7364ccb1518a",
5+
"requesterId": "44642483-f4d4-4a29-a2ba-8eefcf53de16",
6+
"requesterName": "vignesh",
7+
"count": 2,
8+
"printEventDate": "2024-07-04T07:07:00.000+00:00"
9+
},
10+
{
11+
"requestId": "fd831be3-f05f-4b6f-b68f-1a976ea1ab0f",
12+
"requesterId": "44642483-f4d4-4a29-a2ba-8eefcf53de17",
13+
"requesterName": "siddhu",
14+
"count": 5,
15+
"printEventDate": "2024-07-05T07:07:00.000+00:00"
16+
}
17+
],
18+
"totalRecords": 2
19+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-04/schema#",
3+
"description": "Print Events Request",
4+
"type": "object",
5+
"properties": {
6+
"requestIds": {
7+
"description": "List of request IDs",
8+
"type": "array",
9+
"minItems": 1,
10+
"items": {
11+
"type": "string",
12+
"pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[1-5][a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$"
13+
}
14+
}
15+
}
16+
}
17+
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-04/schema#",
3+
"description": "Print events details",
4+
"type": "object",
5+
"properties": {
6+
"requestId": {
7+
"description": "ID of the request",
8+
"type": "string"
9+
},
10+
"requesterId": {
11+
"description": "ID of the requester",
12+
"type": "string"
13+
},
14+
"requesterName": {
15+
"description": "Name of the requester",
16+
"type": "string"
17+
},
18+
"count": {
19+
"description": "No of times the request is printed",
20+
"type": "integer"
21+
},
22+
"printEventDate": {
23+
"description": "Date and time when the print command is executed",
24+
"type": "string",
25+
"format": "date-time"
26+
}
27+
}
28+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-04/schema#",
3+
"description": "Collection of print events details",
4+
"type": "object",
5+
"properties": {
6+
"printEventsStatusResponses": {
7+
"description": "List of print events details",
8+
"id": "printEvents",
9+
"type": "array",
10+
"items": {
11+
"type": "object",
12+
"$ref": "print-events-status-response.json"
13+
}
14+
},
15+
"totalRecords": {
16+
"type": "integer"
17+
}
18+
},
19+
"required": [
20+
"printEventsStatusResponses",
21+
"totalRecords"
22+
]
23+
}

ramls/print-events-storage.raml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ documentation:
1010

1111
types:
1212
print-events-request: !include print-events-request.json
13+
print-events-status-request: !include print-events-status-request.json
14+
print-events-status-responses: !include print-events-status-responses.json
1315
errors: !include raml-util/schemas/errors.schema
1416

1517
traits:
@@ -46,3 +48,26 @@ traits:
4648
body:
4749
text/plain:
4850
example: "Internal server error"
51+
/print-events-status:
52+
post:
53+
is: [validate]
54+
description: Fetch batch of print event details
55+
body:
56+
application/json:
57+
type: print-events-status-request
58+
responses:
59+
200:
60+
description: "Requests print event details are successfully retreived"
61+
body:
62+
application/json:
63+
type: print-events-status-responses
64+
422:
65+
description: "Unprocessable entity"
66+
body:
67+
application/json:
68+
type: errors
69+
500:
70+
description: "Internal server error"
71+
body:
72+
text/plain:
73+
example: "Internal server error"

src/main/java/org/folio/rest/impl/PrintEventsApi.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import io.vertx.core.Context;
55
import io.vertx.core.Handler;
66
import org.folio.rest.jaxrs.model.PrintEventsRequest;
7+
import org.folio.rest.jaxrs.model.PrintEventsStatusRequest;
78
import org.folio.rest.jaxrs.resource.PrintEventsStorage;
89
import org.folio.service.PrintEventsService;
910
import org.slf4j.Logger;
@@ -25,4 +26,12 @@ public void postPrintEventsStoragePrintEventsEntry(PrintEventsRequest printEvent
2526
.onSuccess(response -> asyncResultHandler.handle(succeededFuture(response)))
2627
.onFailure(throwable -> asyncResultHandler.handle(succeededFuture(PostPrintEventsStoragePrintEventsEntryResponse.respond500WithTextPlain(throwable.getMessage()))));
2728
}
29+
30+
@Override
31+
public void postPrintEventsStoragePrintEventsStatus(PrintEventsStatusRequest entity, Map<String, String> okapiHeaders, Handler<AsyncResult<Response>> asyncResultHandler, Context vertxContext) {
32+
LOG.info("postPrintEventsStoragePrintEventsStatus:: Fetching print event details for requestIds {}",
33+
entity.getRequestIds());
34+
new PrintEventsService(vertxContext, okapiHeaders)
35+
.getPrintEventRequestDetails(entity.getRequestIds(), asyncResultHandler);
36+
}
2837
}

src/main/java/org/folio/service/PrintEventsService.java

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,33 @@
11
package org.folio.service;
22

3+
import io.vertx.core.AsyncResult;
34
import io.vertx.core.Context;
45
import io.vertx.core.Future;
6+
import io.vertx.core.Handler;
7+
import io.vertx.sqlclient.Row;
8+
import io.vertx.sqlclient.RowSet;
9+
import org.folio.rest.RestVerticle;
510
import org.folio.rest.jaxrs.model.PrintEventsRequest;
11+
import org.folio.rest.jaxrs.model.PrintEventsStatusResponse;
12+
import org.folio.rest.jaxrs.model.PrintEventsStatusResponses;
613
import org.folio.rest.jaxrs.resource.PrintEventsStorage;
714
import org.folio.rest.model.PrintEvent;
815
import org.folio.rest.persist.PgUtil;
16+
import org.folio.rest.persist.PostgresClient;
917
import org.slf4j.Logger;
1018
import org.slf4j.LoggerFactory;
1119

1220
import javax.ws.rs.core.Response;
21+
import java.time.ZoneOffset;
22+
import java.util.ArrayList;
23+
import java.util.Date;
1324
import java.util.List;
1425
import java.util.Map;
26+
import java.util.stream.Collectors;
1527

28+
import static io.vertx.core.Future.succeededFuture;
29+
import static org.folio.rest.persist.PgUtil.postgresClient;
30+
import static org.folio.rest.persist.PostgresClient.convertToPsqlStandard;
1631
import static org.folio.support.ModuleConstants.PRINT_EVENTS_TABLE;
1732

1833
public class PrintEventsService {
@@ -22,6 +37,23 @@ public class PrintEventsService {
2237
private final Context vertxContext;
2338
private final Map<String, String> okapiHeaders;
2439

40+
private static final String PRINT_EVENT_FETCH_QUERY = """
41+
WITH cte AS (
42+
SELECT id, jsonb->>'requestId' AS request_id, jsonb->>'printEventDate' AS last_updated_date,
43+
jsonb->>'requesterName' AS requester_name, jsonb->>'requesterId' AS requester_id,
44+
COUNT(*) OVER (PARTITION BY jsonb->>'requestId') AS request_count,
45+
ROW_NUMBER() OVER (PARTITION BY jsonb->>'requestId'
46+
ORDER BY (jsonb->>'printEventDate')::timestamptz DESC) AS rank
47+
FROM %s.%s
48+
where jsonb->>'requestId' in (%s)
49+
)
50+
SELECT request_id, requester_name, requester_id, request_count, (last_updated_date)::timestamptz
51+
FROM cte
52+
WHERE
53+
rank = 1;
54+
""";
55+
56+
2557

2658
public PrintEventsService(Context vertxContext, Map<String, String> okapiHeaders) {
2759
this.vertxContext = vertxContext;
@@ -41,4 +73,53 @@ public Future<Response> create(PrintEventsRequest printEventRequest) {
4173
return PgUtil.postSync(PRINT_EVENTS_TABLE, printEvents, MAX_ENTITIES, false, okapiHeaders, vertxContext,
4274
PrintEventsStorage.PostPrintEventsStoragePrintEventsEntryResponse.class);
4375
}
76+
77+
public void getPrintEventRequestDetails(List<String> requestIds, Handler<AsyncResult<Response>> asyncResultHandler) {
78+
LOG.debug("getPrintEventRequestDetails:: Fetching print event details for requestIds {}", requestIds);
79+
String tenantId = okapiHeaders.get(RestVerticle.OKAPI_HEADER_TENANT);
80+
PostgresClient postgresClient = postgresClient(vertxContext, okapiHeaders);
81+
postgresClient.execute(formatQuery(tenantId, requestIds), handler -> {
82+
try {
83+
if (handler.succeeded()) {
84+
asyncResultHandler.handle(
85+
succeededFuture(PrintEventsStorage.PostPrintEventsStoragePrintEventsStatusResponse
86+
.respond200WithApplicationJson(mapRowSetToResponse(handler.result()))));
87+
} else {
88+
LOG.warn("getPrintEventRequestDetails:: Error while executing query", handler.cause());
89+
asyncResultHandler.handle(succeededFuture(PrintEventsStorage.PostPrintEventsStoragePrintEventsStatusResponse
90+
.respond500WithTextPlain(handler.cause())));
91+
}
92+
} catch (Exception ex) {
93+
LOG.warn("getPrintEventRequestDetails:: Error while fetching print details", ex);
94+
asyncResultHandler.handle(succeededFuture(PrintEventsStorage.PostPrintEventsStoragePrintEventsEntryResponse
95+
.respond500WithTextPlain(ex.getMessage())));
96+
}
97+
});
98+
}
99+
100+
private String formatQuery(String tenantId, List<String> requestIds) {
101+
String formattedRequestIds = requestIds
102+
.stream()
103+
.map(requestId -> "'" + requestId + "'")
104+
.collect(Collectors.joining(", "));
105+
return String.format(PRINT_EVENT_FETCH_QUERY, convertToPsqlStandard(tenantId), PRINT_EVENTS_TABLE, formattedRequestIds);
106+
}
107+
108+
private PrintEventsStatusResponses mapRowSetToResponse(RowSet<Row> rowSet) {
109+
PrintEventsStatusResponses printEventsStatusResponses = new PrintEventsStatusResponses();
110+
List<PrintEventsStatusResponse> responseList = new ArrayList<>();
111+
rowSet.forEach(row -> {
112+
var response = new PrintEventsStatusResponse();
113+
response.setRequestId(row.getString("request_id"));
114+
response.setRequesterName(row.getString("requester_name"));
115+
response.setRequesterId(row.getString("requester_id"));
116+
response.setCount(row.getInteger("request_count"));
117+
response.setPrintEventDate(Date.from(row.getLocalDateTime("last_updated_date")
118+
.atZone(ZoneOffset.UTC).toInstant()));
119+
responseList.add(response);
120+
});
121+
printEventsStatusResponses.setPrintEventsStatusResponses(responseList);
122+
printEventsStatusResponses.setTotalRecords(rowSet.size());
123+
return printEventsStatusResponses;
124+
}
44125
}

0 commit comments

Comments
 (0)