mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-18 05:01:07 +00:00
Checkpoint, semi-working query endpoint
This commit is contained in:
@ -118,6 +118,11 @@ public class GenerateOpenApiSpecAction extends AbstractQActionFunction<GenerateO
|
|||||||
///////////////////
|
///////////////////
|
||||||
for(QTableMetaData table : qInstance.getTables().values())
|
for(QTableMetaData table : qInstance.getTables().values())
|
||||||
{
|
{
|
||||||
|
if(table.getIsHidden())
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
String tableName = table.getName();
|
String tableName = table.getName();
|
||||||
String tableNameUcFirst = StringUtils.ucFirst(table.getName());
|
String tableNameUcFirst = StringUtils.ucFirst(table.getName());
|
||||||
String tableLabel = table.getLabel();
|
String tableLabel = table.getLabel();
|
||||||
|
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2023. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.api.javalin;
|
||||||
|
|
||||||
|
|
||||||
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public class QBadRequestException extends QException
|
||||||
|
{
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Constructor
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public QBadRequestException(String message)
|
||||||
|
{
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -23,20 +23,28 @@ package com.kingsrook.qqq.api.javalin;
|
|||||||
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
import com.kingsrook.qqq.api.ApiMiddlewareType;
|
import com.kingsrook.qqq.api.ApiMiddlewareType;
|
||||||
|
import com.kingsrook.qqq.api.actions.GenerateOpenApiSpecAction;
|
||||||
import com.kingsrook.qqq.api.actions.GetTableApiFieldsAction;
|
import com.kingsrook.qqq.api.actions.GetTableApiFieldsAction;
|
||||||
import com.kingsrook.qqq.api.model.APIVersion;
|
import com.kingsrook.qqq.api.model.APIVersion;
|
||||||
import com.kingsrook.qqq.api.model.APIVersionRange;
|
import com.kingsrook.qqq.api.model.APIVersionRange;
|
||||||
|
import com.kingsrook.qqq.api.model.actions.GenerateOpenApiSpecInput;
|
||||||
|
import com.kingsrook.qqq.api.model.actions.GenerateOpenApiSpecOutput;
|
||||||
import com.kingsrook.qqq.api.model.actions.GetTableApiFieldsInput;
|
import com.kingsrook.qqq.api.model.actions.GetTableApiFieldsInput;
|
||||||
import com.kingsrook.qqq.api.model.metadata.tables.ApiTableMetaData;
|
import com.kingsrook.qqq.api.model.metadata.tables.ApiTableMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.actions.permissions.PermissionsHelper;
|
import com.kingsrook.qqq.backend.core.actions.permissions.PermissionsHelper;
|
||||||
import com.kingsrook.qqq.backend.core.actions.permissions.TablePermissionSubType;
|
import com.kingsrook.qqq.backend.core.actions.permissions.TablePermissionSubType;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.tables.CountAction;
|
||||||
import com.kingsrook.qqq.backend.core.actions.tables.GetAction;
|
import com.kingsrook.qqq.backend.core.actions.tables.GetAction;
|
||||||
import com.kingsrook.qqq.backend.core.actions.tables.QueryAction;
|
import com.kingsrook.qqq.backend.core.actions.tables.QueryAction;
|
||||||
|
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||||
import com.kingsrook.qqq.backend.core.exceptions.QAuthenticationException;
|
import com.kingsrook.qqq.backend.core.exceptions.QAuthenticationException;
|
||||||
import com.kingsrook.qqq.backend.core.exceptions.QModuleDispatchException;
|
import com.kingsrook.qqq.backend.core.exceptions.QModuleDispatchException;
|
||||||
import com.kingsrook.qqq.backend.core.exceptions.QNotFoundException;
|
import com.kingsrook.qqq.backend.core.exceptions.QNotFoundException;
|
||||||
@ -44,8 +52,13 @@ import com.kingsrook.qqq.backend.core.exceptions.QPermissionDeniedException;
|
|||||||
import com.kingsrook.qqq.backend.core.exceptions.QUserFacingException;
|
import com.kingsrook.qqq.backend.core.exceptions.QUserFacingException;
|
||||||
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.AbstractActionInput;
|
import com.kingsrook.qqq.backend.core.model.actions.AbstractActionInput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.tables.count.CountInput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.tables.count.CountOutput;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.get.GetInput;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.get.GetInput;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.get.GetOutput;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.get.GetOutput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterOrderBy;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput;
|
||||||
@ -56,11 +69,13 @@ import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
|||||||
import com.kingsrook.qqq.backend.core.utils.ExceptionUtils;
|
import com.kingsrook.qqq.backend.core.utils.ExceptionUtils;
|
||||||
import com.kingsrook.qqq.backend.core.utils.JsonUtils;
|
import com.kingsrook.qqq.backend.core.utils.JsonUtils;
|
||||||
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||||
|
import com.kingsrook.qqq.backend.core.utils.ValueUtils;
|
||||||
import com.kingsrook.qqq.backend.javalin.QJavalinAccessLogger;
|
import com.kingsrook.qqq.backend.javalin.QJavalinAccessLogger;
|
||||||
import com.kingsrook.qqq.backend.javalin.QJavalinImplementation;
|
import com.kingsrook.qqq.backend.javalin.QJavalinImplementation;
|
||||||
import com.kingsrook.qqq.backend.javalin.QJavalinUtils;
|
import com.kingsrook.qqq.backend.javalin.QJavalinUtils;
|
||||||
import io.javalin.apibuilder.ApiBuilder;
|
import io.javalin.apibuilder.ApiBuilder;
|
||||||
import io.javalin.apibuilder.EndpointGroup;
|
import io.javalin.apibuilder.EndpointGroup;
|
||||||
|
import io.javalin.http.ContentType;
|
||||||
import io.javalin.http.Context;
|
import io.javalin.http.Context;
|
||||||
import org.eclipse.jetty.http.HttpStatus;
|
import org.eclipse.jetty.http.HttpStatus;
|
||||||
import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair;
|
import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair;
|
||||||
@ -92,12 +107,14 @@ public class QJavalinApiHandler
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** Define the routes
|
** Define the routes
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public static EndpointGroup getRoutes()
|
public EndpointGroup getRoutes()
|
||||||
{
|
{
|
||||||
return (() ->
|
return (() ->
|
||||||
{
|
{
|
||||||
ApiBuilder.path("/api/{version}", () -> // todo - configurable, that /api/ bit?
|
ApiBuilder.path("/api/{version}", () -> // todo - configurable, that /api/ bit?
|
||||||
{
|
{
|
||||||
|
ApiBuilder.get("/openapi.yaml", QJavalinApiHandler::doSpec);
|
||||||
|
|
||||||
ApiBuilder.path("/{tableName}", () ->
|
ApiBuilder.path("/{tableName}", () ->
|
||||||
{
|
{
|
||||||
ApiBuilder.post("/", QJavalinApiHandler::doInsert);
|
ApiBuilder.post("/", QJavalinApiHandler::doInsert);
|
||||||
@ -119,6 +136,27 @@ public class QJavalinApiHandler
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private static void doSpec(Context context)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
QContext.init(qInstance, null);
|
||||||
|
String version = context.pathParam("version");
|
||||||
|
GenerateOpenApiSpecOutput output = new GenerateOpenApiSpecAction().execute(new GenerateOpenApiSpecInput().withVersion(version));
|
||||||
|
context.contentType(ContentType.APPLICATION_YAML);
|
||||||
|
context.result(output.getYaml());
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
QJavalinImplementation.handleException(context, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
@ -151,7 +189,7 @@ public class QJavalinApiHandler
|
|||||||
private static void doGet(Context context)
|
private static void doGet(Context context)
|
||||||
{
|
{
|
||||||
String version = context.pathParam("version");
|
String version = context.pathParam("version");
|
||||||
String tableName = context.pathParam("table");
|
String tableName = context.pathParam("tableName");
|
||||||
String primaryKey = context.pathParam("primaryKey");
|
String primaryKey = context.pathParam("primaryKey");
|
||||||
|
|
||||||
try
|
try
|
||||||
@ -200,14 +238,8 @@ public class QJavalinApiHandler
|
|||||||
+ table.getFields().get(table.getPrimaryKeyField()).getLabel() + " of " + primaryKey));
|
+ table.getFields().get(table.getPrimaryKeyField()).getLabel() + " of " + primaryKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
List<? extends QFieldMetaData> tableApiFields = new GetTableApiFieldsAction().execute(new GetTableApiFieldsInput().withTableName(tableName).withVersion(version)).getFields();
|
List<? extends QFieldMetaData> tableApiFields = new GetTableApiFieldsAction().execute(new GetTableApiFieldsInput().withTableName(tableName).withVersion(version)).getFields();
|
||||||
Map<String, Serializable> outputRecord = new LinkedHashMap<>();
|
LinkedHashMap<String, Serializable> outputRecord = toApiRecord(record, tableApiFields);
|
||||||
for(QFieldMetaData tableApiField : tableApiFields)
|
|
||||||
{
|
|
||||||
// todo - what about display values / possible values
|
|
||||||
// todo - handle removed-from-this-version fields!!
|
|
||||||
outputRecord.put(tableApiField.getName(), record.getValue(tableApiField.getName()));
|
|
||||||
}
|
|
||||||
|
|
||||||
QJavalinAccessLogger.logEndSuccess();
|
QJavalinAccessLogger.logEndSuccess();
|
||||||
context.result(JsonUtils.toJson(outputRecord));
|
context.result(JsonUtils.toJson(outputRecord));
|
||||||
@ -226,40 +258,220 @@ public class QJavalinApiHandler
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
private static void doQuery(Context context)
|
private static void doQuery(Context context)
|
||||||
{
|
{
|
||||||
String table = context.pathParam("table");
|
String version = context.pathParam("version");
|
||||||
String filter = null;
|
String tableName = context.pathParam("tableName");
|
||||||
|
QQueryFilter filter = null;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
List<String> badRequestMessages = new ArrayList<>();
|
||||||
|
|
||||||
|
// todo - make sure version is known in this instance
|
||||||
|
// todo - make sure table is supported in this version
|
||||||
|
|
||||||
|
QTableMetaData table = qInstance.getTable(tableName);
|
||||||
|
|
||||||
|
if(table == null)
|
||||||
|
{
|
||||||
|
throw (new QNotFoundException("Could not find any resources at path " + context.path()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!getApiVersionRange(table).includes(new APIVersion(version)))
|
||||||
|
{
|
||||||
|
throw (new QNotFoundException("This version of this API does not contain the resource path " + context.path()));
|
||||||
|
}
|
||||||
|
|
||||||
QueryInput queryInput = new QueryInput();
|
QueryInput queryInput = new QueryInput();
|
||||||
setupSession(context, queryInput);
|
setupSession(context, queryInput);
|
||||||
QJavalinAccessLogger.logStart("query", logPair("table", table));
|
QJavalinAccessLogger.logStart("apiQuery", logPair("table", tableName));
|
||||||
|
|
||||||
queryInput.setTableName(table);
|
queryInput.setTableName(tableName);
|
||||||
queryInput.setShouldGenerateDisplayValues(true);
|
//? queryInput.setShouldGenerateDisplayValues(true);
|
||||||
queryInput.setShouldTranslatePossibleValues(true);
|
//? queryInput.setShouldTranslatePossibleValues(true);
|
||||||
queryInput.setSkip(QJavalinUtils.integerQueryParam(context, "skip"));
|
|
||||||
queryInput.setLimit(QJavalinUtils.integerQueryParam(context, "limit"));
|
|
||||||
|
|
||||||
PermissionsHelper.checkTablePermissionThrowing(queryInput, TablePermissionSubType.READ);
|
PermissionsHelper.checkTablePermissionThrowing(queryInput, TablePermissionSubType.READ);
|
||||||
|
|
||||||
filter = QJavalinUtils.stringQueryParam(context, "filter");
|
Integer pageSize = 50;
|
||||||
if(!StringUtils.hasContent(filter))
|
if(StringUtils.hasContent(context.queryParam("pageSize")))
|
||||||
{
|
{
|
||||||
filter = context.formParam("filter");
|
try
|
||||||
|
{
|
||||||
|
pageSize = ValueUtils.getValueAsInteger(context.queryParam("pageSize"));
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
badRequestMessages.add("Could not parse pageSize as an integer");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if(filter != null)
|
if(pageSize < 1 || pageSize > 1000)
|
||||||
{
|
{
|
||||||
queryInput.setFilter(JsonUtils.toObject(filter, QQueryFilter.class));
|
badRequestMessages.add("pageSize must be between 1 and 1000.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Integer pageNo = Objects.requireNonNullElse(QJavalinUtils.integerQueryParam(context, "pageNo"), 1);
|
||||||
|
if(pageNo < 1)
|
||||||
|
{
|
||||||
|
badRequestMessages.add("pageNo must be greater than 0.");
|
||||||
|
}
|
||||||
|
|
||||||
|
queryInput.setLimit(pageSize);
|
||||||
|
queryInput.setSkip((pageNo - 1) * pageSize);
|
||||||
|
|
||||||
// queryInput.setQueryJoins(processQueryJoinsParam(context));
|
// queryInput.setQueryJoins(processQueryJoinsParam(context));
|
||||||
|
|
||||||
|
filter = new QQueryFilter();
|
||||||
|
if("and".equalsIgnoreCase(context.queryParam("booleanOperator")))
|
||||||
|
{
|
||||||
|
filter.setBooleanOperator(QQueryFilter.BooleanOperator.AND);
|
||||||
|
}
|
||||||
|
else if("or".equalsIgnoreCase(context.queryParam("booleanOperator")))
|
||||||
|
{
|
||||||
|
filter.setBooleanOperator(QQueryFilter.BooleanOperator.AND);
|
||||||
|
}
|
||||||
|
else if(StringUtils.hasContent(context.queryParam("booleanOperator")))
|
||||||
|
{
|
||||||
|
badRequestMessages.add("booleanOperator must be either AND or OR.");
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean includeCount = true;
|
||||||
|
if("true".equalsIgnoreCase(context.queryParam("includeCount")))
|
||||||
|
{
|
||||||
|
includeCount = true;
|
||||||
|
}
|
||||||
|
else if("false".equalsIgnoreCase(context.queryParam("includeCount")))
|
||||||
|
{
|
||||||
|
includeCount = false;
|
||||||
|
}
|
||||||
|
else if(StringUtils.hasContent(context.queryParam("includeCount")))
|
||||||
|
{
|
||||||
|
badRequestMessages.add("includeCount must be either true or false");
|
||||||
|
}
|
||||||
|
|
||||||
|
String orderBy = context.queryParam("orderBy");
|
||||||
|
if(StringUtils.hasContent(orderBy))
|
||||||
|
{
|
||||||
|
for(String orderByPart : orderBy.split(","))
|
||||||
|
{
|
||||||
|
orderByPart = orderByPart.trim();
|
||||||
|
String[] orderByNameDirection = orderByPart.split(" +");
|
||||||
|
boolean asc = true;
|
||||||
|
if(orderByNameDirection.length == 2)
|
||||||
|
{
|
||||||
|
if("asc".equalsIgnoreCase(orderByNameDirection[1]))
|
||||||
|
{
|
||||||
|
asc = true;
|
||||||
|
}
|
||||||
|
else if("desc".equalsIgnoreCase(orderByNameDirection[1]))
|
||||||
|
{
|
||||||
|
asc = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
badRequestMessages.add("orderBy direction for field " + orderByNameDirection[0] + " must be either ASC or DESC.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(orderByNameDirection.length > 2)
|
||||||
|
{
|
||||||
|
badRequestMessages.add("unrecognized format for orderBy clause: " + orderByPart + ". Expected: fieldName [ASC|DESC].");
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
QFieldMetaData field = table.getField(orderByNameDirection[0]);
|
||||||
|
filter.withOrderBy(new QFilterOrderBy(field.getName(), asc));
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
badRequestMessages.add("unrecognized orderBy field name: " + orderByNameDirection[0] + ".");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<String> nonFilterParams = Set.of("pageSize", "pageNo", "orderBy", "booleanOperator", "includeCount");
|
||||||
|
|
||||||
|
////////////////////////////
|
||||||
|
// look for filter params //
|
||||||
|
////////////////////////////
|
||||||
|
for(Map.Entry<String, List<String>> entry : context.queryParamMap().entrySet())
|
||||||
|
{
|
||||||
|
String name = entry.getKey();
|
||||||
|
List<String> values = entry.getValue();
|
||||||
|
|
||||||
|
if(nonFilterParams.contains(name))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
QFieldMetaData field = table.getField(name);
|
||||||
|
for(String value : values)
|
||||||
|
{
|
||||||
|
if(StringUtils.hasContent(value))
|
||||||
|
{
|
||||||
|
QCriteriaOperator operator = getCriteriaOperator(value);
|
||||||
|
List<Serializable> criteriaValues = getCriteriaValues(field, value);
|
||||||
|
filter.addCriteria(new QFilterCriteria(name, operator, criteriaValues));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
badRequestMessages.add("Unrecognized filter criteria field: " + name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////
|
||||||
|
// no more badRequest checks below here //
|
||||||
|
//////////////////////////////////////////
|
||||||
|
if(!badRequestMessages.isEmpty())
|
||||||
|
{
|
||||||
|
if(badRequestMessages.size() == 1)
|
||||||
|
{
|
||||||
|
throw (new QBadRequestException(badRequestMessages.get(0)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw (new QBadRequestException("Requested failed with " + badRequestMessages.size() + " reasons: " + StringUtils.join(" \n", badRequestMessages)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////
|
||||||
|
// do the query //
|
||||||
|
//////////////////
|
||||||
QueryAction queryAction = new QueryAction();
|
QueryAction queryAction = new QueryAction();
|
||||||
|
queryInput.setFilter(filter);
|
||||||
QueryOutput queryOutput = queryAction.execute(queryInput);
|
QueryOutput queryOutput = queryAction.execute(queryInput);
|
||||||
|
|
||||||
|
Map<String, Serializable> output = new HashMap<>();
|
||||||
|
output.put("pageSize", pageSize);
|
||||||
|
output.put("pageNo", pageNo);
|
||||||
|
|
||||||
|
///////////////////////////////
|
||||||
|
// map record fields for api //
|
||||||
|
///////////////////////////////
|
||||||
|
List<? extends QFieldMetaData> tableApiFields = new GetTableApiFieldsAction().execute(new GetTableApiFieldsInput().withTableName(tableName).withVersion(version)).getFields();
|
||||||
|
ArrayList<Map<String, Serializable>> records = new ArrayList<>();
|
||||||
|
for(QRecord record : queryOutput.getRecords())
|
||||||
|
{
|
||||||
|
records.add(toApiRecord(record, tableApiFields));
|
||||||
|
}
|
||||||
|
output.put("records", records);
|
||||||
|
|
||||||
|
/////////////////////////////
|
||||||
|
// optionally do the count //
|
||||||
|
/////////////////////////////
|
||||||
|
if(includeCount)
|
||||||
|
{
|
||||||
|
CountInput countInput = new CountInput();
|
||||||
|
countInput.setTableName(tableName);
|
||||||
|
countInput.setFilter(filter);
|
||||||
|
CountOutput countOutput = new CountAction().execute(countInput);
|
||||||
|
output.put("count", countOutput.getCount());
|
||||||
|
}
|
||||||
|
|
||||||
QJavalinAccessLogger.logEndSuccess(logPair("recordCount", queryOutput.getRecords().size()), QJavalinAccessLogger.logPairIfSlow("filter", filter, SLOW_LOG_THRESHOLD_MS));
|
QJavalinAccessLogger.logEndSuccess(logPair("recordCount", queryOutput.getRecords().size()), QJavalinAccessLogger.logPairIfSlow("filter", filter, SLOW_LOG_THRESHOLD_MS));
|
||||||
context.result(JsonUtils.toJson(queryOutput));
|
context.result(JsonUtils.toJson(output));
|
||||||
}
|
}
|
||||||
catch(Exception e)
|
catch(Exception e)
|
||||||
{
|
{
|
||||||
@ -270,6 +482,28 @@ public class QJavalinApiHandler
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private static QCriteriaOperator getCriteriaOperator(String value)
|
||||||
|
{
|
||||||
|
// todo - all other operators
|
||||||
|
return (QCriteriaOperator.EQUALS);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private static List<Serializable> getCriteriaValues(QFieldMetaData field, String value)
|
||||||
|
{
|
||||||
|
// todo - parse the thing, do stuff
|
||||||
|
return (List.of(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
@ -300,6 +534,23 @@ public class QJavalinApiHandler
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private static LinkedHashMap<String, Serializable> toApiRecord(QRecord record, List<? extends QFieldMetaData> tableApiFields)
|
||||||
|
{
|
||||||
|
LinkedHashMap<String, Serializable> outputRecord = new LinkedHashMap<>();
|
||||||
|
for(QFieldMetaData tableApiField : tableApiFields)
|
||||||
|
{
|
||||||
|
// todo - what about display values / possible values
|
||||||
|
// todo - handle removed-from-this-version fields!!
|
||||||
|
outputRecord.put(tableApiField.getName(), record.getValue(tableApiField.getName()));
|
||||||
|
}
|
||||||
|
return outputRecord;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
@ -315,6 +566,14 @@ public class QJavalinApiHandler
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public static void handleException(HttpStatus.Code statusCode, Context context, Exception e)
|
public static void handleException(HttpStatus.Code statusCode, Context context, Exception e)
|
||||||
{
|
{
|
||||||
|
QBadRequestException badRequestException = ExceptionUtils.findClassInRootChain(e, QBadRequestException.class);
|
||||||
|
if(badRequestException != null)
|
||||||
|
{
|
||||||
|
statusCode = Objects.requireNonNullElse(statusCode, HttpStatus.Code.BAD_REQUEST); // 400
|
||||||
|
respondWithError(context, statusCode, badRequestException.getMessage());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
QUserFacingException userFacingException = ExceptionUtils.findClassInRootChain(e, QUserFacingException.class);
|
QUserFacingException userFacingException = ExceptionUtils.findClassInRootChain(e, QUserFacingException.class);
|
||||||
if(userFacingException != null)
|
if(userFacingException != null)
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user