use of org.folio.cql2pgjson.CQL2PgJSON in project raml-module-builder by folio-org.
the class PgUtil method get.
/**
* Get records by CQL.
* @param table the table that contains the records
* @param clazz the class of the record type T
* @param collectionClazz the class of the collection type C containing records of type T
* @param cql the CQL query for filtering and sorting the records
* @param hasTotalRecords how to calculate totalRecords
* @param offset number of records to skip, use 0 or negative number for not skipping
* @param limit maximum number of records to return, use a negative number for no limit
* @param okapiHeaders http headers provided by okapi
* @param vertxContext the current context
* @param responseDelegateClass the ResponseDelegate class generated as defined by the RAML file,
* must have these methods: respond200(C), respond400WithTextPlain(Object), respond500WithTextPlain(Object).
* @return future where to return the result created by the responseDelegateClass
*/
// Method has >7 parameters
@SuppressWarnings({ "squid:S107" })
public static <T, C> Future<Response> get(String table, Class<T> clazz, Class<C> collectionClazz, String cql, String hasTotalRecords, int offset, int limit, Map<String, String> okapiHeaders, Context vertxContext, Class<? extends ResponseDelegate> responseDelegateClass) {
try {
CQL2PgJSON cql2pgJson = new CQL2PgJSON(table + "." + JSON_COLUMN);
CQLWrapper cqlWrapper = new CQLWrapper(cql2pgJson, cql, limit, offset, hasTotalRecords);
PreparedCQL preparedCql = new PreparedCQL(table, cqlWrapper, okapiHeaders);
return get(preparedCql, clazz, collectionClazz, okapiHeaders, vertxContext, responseDelegateClass);
} catch (Exception e) {
logger.error(e.getMessage(), e);
final Method respond500;
try {
respond500 = responseDelegateClass.getMethod(RESPOND_500_WITH_TEXT_PLAIN, Object.class);
} catch (Exception e2) {
logger.error(e2.getMessage(), e2);
return response(e2.getMessage(), null, null);
}
// invalid CQL is handled by get(...), here we get Exception about invalid table
return response(e.getMessage(), respond500, respond500);
}
}
use of org.folio.cql2pgjson.CQL2PgJSON in project raml-module-builder by folio-org.
the class PgUtil method streamGet.
/**
* Streaming GET with query. This produces a HTTP with JSON content with
* properties {@code totalRecords}, {@code resultInfo} and custom element.
* The custom element is array type which POJO that is of type clazz.
* The JSON schema looks as follows:
*
* <pre>{@code
* "properties": {
* "element": {
* "description": "the custom element array wrapper",
* "type": "array",
* "items": {
* "description": "The clazz",
* "type": "object",
* "$ref": "clazz.schema"
* }
* },
* "totalRecords": {
* "type": "integer"
* },
* "resultInfo": {
* "$ref": "raml-util/schemas/resultInfo.schema",
* "readonly": true
* }
* },
* "required": [
* "instances"
* ]
*</pre>
* @param <T> Class for each item returned
* @param table SQL table
* @param clazz The item class
* @param cql CQL query
* @param hasTotalRecords "auto" for estimating totalRecords, "none" to suppress totalRecords estimation
* @param offset offset >= 0; < 0 for no offset
* @param limit limit >= 0 ; <0 for no limit
* @param facets facets (null or empty for no facets)
* @param element wrapper JSON element for list of items (eg books / users)
* @param routingContext routing context from which a HTTP response is made
* @param okapiHeaders
* @param vertxContext
*/
// Method has >7 parameters
@SuppressWarnings("squid:S107")
public static <T> void streamGet(String table, Class<T> clazz, String cql, String hasTotalRecords, int offset, int limit, List<String> facets, String element, int queryTimeout, RoutingContext routingContext, Map<String, String> okapiHeaders, Context vertxContext) {
HttpServerResponse response = routingContext.response();
try {
List<FacetField> facetList = FacetManager.convertFacetStrings2FacetFields(facets, JSON_COLUMN);
CQLWrapper wrapper = new CQLWrapper(new CQL2PgJSON(table + "." + JSON_COLUMN), cql, limit, offset, hasTotalRecords);
streamGet(table, clazz, wrapper, facetList, element, queryTimeout, routingContext, okapiHeaders, vertxContext);
} catch (Exception e) {
logger.error(e.getMessage(), e);
response.setStatusCode(500);
response.putHeader(HttpHeaders.CONTENT_TYPE, "text/plain");
response.end(e.toString());
}
}
use of org.folio.cql2pgjson.CQL2PgJSON in project raml-module-builder by folio-org.
the class PgUtil method getWithOptimizedSql.
/**
* Run the cql query using optimized SQL (if possible) or standard SQL.
* <p>
* PostgreSQL has no statistics about a field within a JSONB resulting in bad performance.
* <p>
* This method requires that the sortField has a b-tree index (non-unique) and caseSensitive=false
* and removeAccents=true, and that the cql query is supported by a full text index.
* <p>
* This method starts a full table scan until getOptimizedSqlSize() records have been scanned.
* Then it assumes that there are only a few result records and uses the full text match.
* If the requested number of records have been found it stops immediately.
* @param table
* @param clazz
* @param cql
* @param queryTimeout query timeout in milliseconds, or 0 for no timeout
* @param okapiHeaders
* @param vertxContext
* @param responseDelegateClass
* @return
*/
public static <T, C> Future<Response> getWithOptimizedSql(String table, Class<T> clazz, Class<C> collectionClazz, String sortField, String cql, int offset, int limit, int queryTimeout, Map<String, String> okapiHeaders, Context vertxContext, Class<? extends ResponseDelegate> responseDelegateClass) {
final Method respond500;
try {
respond500 = responseDelegateClass.getMethod(RESPOND_500_WITH_TEXT_PLAIN, Object.class);
} catch (Exception e) {
logger.error(e.getMessage(), e);
return response(e.getMessage(), null, null);
}
final Method respond200;
final Method respond400;
try {
respond200 = responseDelegateClass.getMethod(RESPOND_200_WITH_APPLICATION_JSON, collectionClazz);
respond400 = responseDelegateClass.getMethod(RESPOND_400_WITH_TEXT_PLAIN, Object.class);
} catch (Exception e) {
logger.error(e.getMessage(), e);
return response(e.getMessage(), respond500, respond500);
}
try {
CQL2PgJSON cql2pgJson = new CQL2PgJSON(table + "." + JSON_COLUMN);
CQLWrapper cqlWrapper = new CQLWrapper(cql2pgJson, cql, limit, offset);
PreparedCQL preparedCql = new PreparedCQL(table, cqlWrapper, okapiHeaders);
String sql = generateOptimizedSql(sortField, preparedCql, offset, limit);
if (sql == null) {
// the cql is not suitable for optimization, generate simple sql
return get(preparedCql, clazz, collectionClazz, okapiHeaders, vertxContext, responseDelegateClass);
}
logger.info("Optimized SQL generated. Source CQL: " + cql);
Promise<Response> promise = Promise.promise();
PostgresClient postgresClient = postgresClient(vertxContext, okapiHeaders);
postgresClient.select(sql, queryTimeout, reply -> {
try {
if (reply.failed()) {
Throwable cause = reply.cause();
logger.error("Optimized SQL failed: " + cause.getMessage() + ": " + sql, cause);
response(cause.getMessage(), respond500, respond500).onComplete(promise);
return;
}
C collection = collection(clazz, collectionClazz, reply.result(), offset, limit);
response(collection, respond200, respond500).onComplete(promise);
} catch (Exception e) {
logger.error(e.getMessage(), e);
response(e.getMessage(), respond500, respond500).onComplete(promise);
}
});
return promise.future();
} catch (FieldException | QueryValidationException e) {
logger.error(e.getMessage(), e);
return response(e.getMessage(), respond400, respond500);
} catch (Exception e) {
logger.error(e.getMessage(), e);
return response(e.getMessage(), respond500, respond500);
}
}
use of org.folio.cql2pgjson.CQL2PgJSON in project raml-module-builder by folio-org.
the class PgUtil method delete.
/**
* Delete records by CQL.
* @param table the table that contains the records
* @param cql the CQL query for filtering the records
* @param okapiHeaders http headers provided by okapi
* @param vertxContext the current context
* @param responseDelegateClass the ResponseDelegate class generated as defined by the RAML file,
* must have these methods: respond204(), respond400WithTextPlain(Object), respond500WithTextPlain(Object).
* @return future where to return the result created by the responseDelegateClass
*/
// Method has >7 parameters
@SuppressWarnings({ "unchecked", "squid:S107" })
public static Future<Response> delete(String table, String cql, Map<String, String> okapiHeaders, Context vertxContext, Class<? extends ResponseDelegate> responseDelegateClass) {
final Method respond500;
try {
respond500 = responseDelegateClass.getMethod(RESPOND_500_WITH_TEXT_PLAIN, Object.class);
} catch (Exception e) {
logger.error(e.getMessage(), e);
return response(e.getMessage(), null, null);
}
final Method respond400;
final Method respond204;
try {
respond400 = responseDelegateClass.getMethod(RESPOND_400_WITH_TEXT_PLAIN, Object.class);
respond204 = responseDelegateClass.getMethod(RESPOND_204);
} catch (Exception e) {
logger.error(e.getMessage(), e);
return response(e.getMessage(), respond500, respond500);
}
try {
CQL2PgJSON cql2pgJson = new CQL2PgJSON(table + "." + JSON_COLUMN);
CQLWrapper cqlWrapper = new CQLWrapper(cql2pgJson, cql, -1, -1);
PreparedCQL preparedCql = new PreparedCQL(table, cqlWrapper, okapiHeaders);
Promise<Response> promise = Promise.promise();
PostgresClient postgresClient = PgUtil.postgresClient(vertxContext, okapiHeaders);
postgresClient.delete(preparedCql.getTableName(), preparedCql.getCqlWrapper(), reply -> {
try {
if (reply.failed()) {
String message = PgExceptionUtil.badRequestMessage(reply.cause());
if (message == null) {
message = reply.cause().getMessage();
}
logger.error(message, reply.cause());
response(message, respond400, respond500).onComplete(promise);
return;
}
response(respond204, respond500).onComplete(promise);
} catch (Exception e) {
logger.error(e.getMessage(), e);
response(e.getMessage(), respond500, respond500).onComplete(promise);
}
});
return promise.future();
} catch (Exception e) {
logger.error(e.getMessage(), e);
return response(e.getMessage(), respond400, respond500);
}
}
use of org.folio.cql2pgjson.CQL2PgJSON in project raml-module-builder by folio-org.
the class PostgresClientIT method streamGetCursorPage.
private void streamGetCursorPage(TestContext context, int limit) throws Exception {
Async async = context.async();
CQLWrapper cql = new CQLWrapper(new CQL2PgJSON("jsonb"), "id=*", limit, /* offset */
0);
postgresClient.streamGet(MOCK_POLINES_TABLE, Object.class, "jsonb", cql, false, null, context.asyncAssertSuccess(r -> {
AtomicInteger count = new AtomicInteger();
r.handler(streamHandler -> {
count.incrementAndGet();
});
r.endHandler(x -> {
context.assertEquals(limit, count.get());
async.complete();
});
r.exceptionHandler(e -> context.fail(e));
}));
}
Aggregations