mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-19 21:50:45 +00:00
Handling of BLOBs
This commit is contained in:
@ -67,6 +67,7 @@ import com.kingsrook.qqq.backend.core.model.actions.tables.update.UpdateInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.update.UpdateOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.Pair;
|
||||
@ -108,6 +109,7 @@ public class ApiImplementation
|
||||
QueryInput queryInput = new QueryInput();
|
||||
queryInput.setTableName(tableName);
|
||||
queryInput.setIncludeAssociations(true);
|
||||
queryInput.setShouldFetchHeavyFields(true);
|
||||
|
||||
PermissionsHelper.checkTablePermissionThrowing(queryInput, TablePermissionSubType.READ);
|
||||
|
||||
@ -251,7 +253,7 @@ public class ApiImplementation
|
||||
{
|
||||
try
|
||||
{
|
||||
filter.addCriteria(parseQueryParamToCriteria(name, value));
|
||||
filter.addCriteria(parseQueryParamToCriteria(field, name, value));
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
@ -506,6 +508,7 @@ public class ApiImplementation
|
||||
|
||||
getInput.setPrimaryKey(primaryKey);
|
||||
getInput.setIncludeAssociations(true);
|
||||
getInput.setShouldFetchHeavyFields(true);
|
||||
|
||||
GetAction getAction = new GetAction();
|
||||
GetOutput getOutput = getAction.execute(getInput);
|
||||
@ -911,7 +914,7 @@ public class ApiImplementation
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private static QFilterCriteria parseQueryParamToCriteria(String name, String value) throws QException
|
||||
private static QFilterCriteria parseQueryParamToCriteria(QFieldMetaData field, String name, String value) throws QException
|
||||
{
|
||||
///////////////////////////////////
|
||||
// process & discard a leading ! //
|
||||
@ -989,6 +992,14 @@ public class ApiImplementation
|
||||
throw (new QException("Unexpected noOfValues [" + selectedOperator.noOfValues + "] in operator [" + selectedOperator + "]"));
|
||||
}
|
||||
|
||||
if(field.getType().equals(QFieldType.BLOB))
|
||||
{
|
||||
if(!selectedOperator.equals(Operator.EMPTY))
|
||||
{
|
||||
throw (new QBadRequestException("Operator " + selectedOperator.prefix + " may not be used for field " + name + " (blob fields only support operators EMPTY or !EMPTY)"));
|
||||
}
|
||||
}
|
||||
|
||||
return (new QFilterCriteria(name, isNot ? selectedOperator.negativeOperator : selectedOperator.positiveOperator, criteriaValues));
|
||||
}
|
||||
|
||||
|
@ -480,9 +480,19 @@ public class GenerateOpenApiSpecAction extends AbstractQActionFunction<GenerateO
|
||||
|
||||
for(QFieldMetaData tableApiField : tableApiFields)
|
||||
{
|
||||
StringBuilder description = new StringBuilder("Query on the " + tableApiField.getLabel() + " field. ");
|
||||
if(tableApiField.getType().equals(QFieldType.BLOB))
|
||||
{
|
||||
description.append("Can only query for EMPTY or !EMPTY.");
|
||||
}
|
||||
else
|
||||
{
|
||||
description.append("Can prefix value with an operator, else defaults to = (equals).");
|
||||
}
|
||||
|
||||
queryGet.getParameters().add(new Parameter()
|
||||
.withName(tableApiField.getName())
|
||||
.withDescription("Query on the " + tableApiField.getLabel() + " field. Can prefix value with an operator, else defaults to = (equals).")
|
||||
.withDescription(description.toString())
|
||||
.withIn("query")
|
||||
.withExplode(true)
|
||||
.withSchema(new Schema()
|
||||
@ -837,6 +847,9 @@ public class GenerateOpenApiSpecAction extends AbstractQActionFunction<GenerateO
|
||||
rs.put("criteriaStringNotLike", new ExampleWithListValue().withSummary("not starting with f").withValue(ListBuilder.of("!LIKE f%")));
|
||||
rs.put("criteriaStringMultiple", new ExampleWithListValue().withSummary("multiple criteria: between bar and foo and not equal to baz").withValue(ListBuilder.of("BETWEEN bar,foo", "!baz")));
|
||||
|
||||
rs.put("criteriaBlobEmpty", new ExampleWithListValue().withSummary("null value").withValue(ListBuilder.of("EMPTY")));
|
||||
rs.put("criteriaBlobNotEmpty", new ExampleWithListValue().withSummary("non-null value").withValue(ListBuilder.of("!EMPTY")));
|
||||
|
||||
return (rs);
|
||||
}
|
||||
|
||||
@ -870,6 +883,10 @@ public class GenerateOpenApiSpecAction extends AbstractQActionFunction<GenerateO
|
||||
{
|
||||
componentExamples.keySet().stream().filter(s -> s.startsWith("criteriaBoolean")).forEach(exampleRefs::add);
|
||||
}
|
||||
else if(tableApiField.getType().equals(QFieldType.BLOB))
|
||||
{
|
||||
componentExamples.keySet().stream().filter(s -> s.startsWith("criteriaBlob")).forEach(exampleRefs::add);
|
||||
}
|
||||
|
||||
Map<String, Example> rs = new LinkedHashMap<>();
|
||||
|
||||
@ -910,10 +927,16 @@ public class GenerateOpenApiSpecAction extends AbstractQActionFunction<GenerateO
|
||||
*******************************************************************************/
|
||||
private Schema getFieldSchema(QTableMetaData table, QFieldMetaData field)
|
||||
{
|
||||
String description = field.getLabel() + " for the " + table.getLabel() + ".";
|
||||
if(field.getType().equals(QFieldType.BLOB))
|
||||
{
|
||||
description = "Base64 encoded " + description;
|
||||
}
|
||||
|
||||
Schema fieldSchema = new Schema()
|
||||
.withType(getFieldType(field))
|
||||
.withFormat(getFieldFormat(field))
|
||||
.withDescription(field.getLabel() + " for the " + table.getLabel() + ".");
|
||||
.withDescription(description);
|
||||
|
||||
if(!field.getIsEditable())
|
||||
{
|
||||
|
@ -24,6 +24,7 @@ package com.kingsrook.qqq.api.actions;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
@ -38,6 +39,7 @@ import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.Association;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||
@ -79,14 +81,23 @@ public class QRecordApiAdapter
|
||||
{
|
||||
ApiFieldMetaData apiFieldMetaData = ObjectUtils.tryAndRequireNonNullElse(() -> ApiFieldMetaDataContainer.of(field).getApiFieldMetaData(apiName), new ApiFieldMetaData());
|
||||
String apiFieldName = ApiFieldMetaData.getEffectiveApiFieldName(apiName, field);
|
||||
|
||||
Serializable value = null;
|
||||
if(StringUtils.hasContent(apiFieldMetaData.getReplacedByFieldName()))
|
||||
{
|
||||
outputRecord.put(apiFieldName, record.getValue(apiFieldMetaData.getReplacedByFieldName()));
|
||||
value = record.getValue(apiFieldMetaData.getReplacedByFieldName());
|
||||
}
|
||||
else
|
||||
{
|
||||
outputRecord.put(apiFieldName, record.getValue(field.getName()));
|
||||
value = record.getValue(field.getName());
|
||||
}
|
||||
|
||||
if(field.getType().equals(QFieldType.BLOB) && value instanceof byte[] bytes)
|
||||
{
|
||||
value = Base64.getEncoder().encodeToString(bytes);
|
||||
}
|
||||
|
||||
outputRecord.put(apiFieldName, value);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -142,6 +153,11 @@ public class QRecordApiAdapter
|
||||
QFieldMetaData field = apiFieldsMap.get(jsonKey);
|
||||
Object value = jsonObject.isNull(jsonKey) ? null : jsonObject.get(jsonKey);
|
||||
|
||||
if(field.getType().equals(QFieldType.BLOB) && value instanceof String s)
|
||||
{
|
||||
value = Base64.getDecoder().decode(s);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// generally, omit non-editable fields - //
|
||||
// however - if we're asked to include the primary key (and this is the primary key), then include it //
|
||||
|
Reference in New Issue
Block a user