mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-18 13:10:44 +00:00
Support multiple api's within a q instance. For science!
This commit is contained in:
@ -30,15 +30,16 @@ import java.util.Comparator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import com.kingsrook.qqq.api.model.APIVersion;
|
||||
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.metadata.ApiInstanceMetaData;
|
||||
import com.kingsrook.qqq.api.model.metadata.ApiInstanceMetaDataContainer;
|
||||
import com.kingsrook.qqq.api.model.metadata.fields.ApiFieldMetaData;
|
||||
import com.kingsrook.qqq.api.model.metadata.tables.ApiTableMetaData;
|
||||
import com.kingsrook.qqq.api.model.metadata.tables.ApiTableMetaDataContainer;
|
||||
import com.kingsrook.qqq.api.model.openapi.Components;
|
||||
import com.kingsrook.qqq.api.model.openapi.Contact;
|
||||
import com.kingsrook.qqq.api.model.openapi.Content;
|
||||
@ -187,21 +188,43 @@ public class GenerateOpenApiSpecAction extends AbstractQActionFunction<GenerateO
|
||||
*******************************************************************************/
|
||||
public GenerateOpenApiSpecOutput execute(GenerateOpenApiSpecInput input) throws QException
|
||||
{
|
||||
String version = input.getVersion();
|
||||
String basePath = "/api/" + version + "/";
|
||||
|
||||
QInstance qInstance = QContext.getQInstance();
|
||||
String version = input.getVersion();
|
||||
|
||||
ApiInstanceMetaDataContainer apiInstanceMetaDataContainer = ApiInstanceMetaDataContainer.of(qInstance);
|
||||
if(apiInstanceMetaDataContainer == null)
|
||||
{
|
||||
throw new QException("No ApiInstanceMetaDataContainer exists in this instance");
|
||||
}
|
||||
|
||||
if(!StringUtils.hasContent(input.getApiName()))
|
||||
{
|
||||
throw new QException("Missing required input: apiName");
|
||||
}
|
||||
|
||||
ApiInstanceMetaData apiInstanceMetaData = apiInstanceMetaDataContainer.getApiInstanceMetaData(input.getApiName());
|
||||
if(apiInstanceMetaData == null)
|
||||
{
|
||||
throw new QException("Could not find apiInstanceMetaData named [" + input.getApiName() + "] in this instance");
|
||||
}
|
||||
|
||||
if(!StringUtils.hasContent(input.getVersion()))
|
||||
{
|
||||
throw new QException("Missing required input: version");
|
||||
}
|
||||
|
||||
ApiInstanceMetaData apiInstanceMetaData = ApiInstanceMetaData.of(qInstance);
|
||||
if(!apiInstanceMetaData.getSupportedVersions().contains(new APIVersion(version)))
|
||||
{
|
||||
throw (new QException("[" + version + "] is not a supported API Version."));
|
||||
}
|
||||
|
||||
String basePath = apiInstanceMetaData.getPath() + version + "/";
|
||||
String apiName = apiInstanceMetaData.getName();
|
||||
|
||||
OpenAPI openAPI = new OpenAPI()
|
||||
.withVersion("3.0.3")
|
||||
.withInfo(new Info()
|
||||
.withTitle(apiInstanceMetaData.getName())
|
||||
.withTitle(apiInstanceMetaData.getLabel())
|
||||
.withDescription(apiInstanceMetaData.getDescription())
|
||||
.withContact(new Contact()
|
||||
.withEmail(apiInstanceMetaData.getContactEmail()))
|
||||
@ -272,7 +295,14 @@ public class GenerateOpenApiSpecAction extends AbstractQActionFunction<GenerateO
|
||||
continue;
|
||||
}
|
||||
|
||||
ApiTableMetaData apiTableMetaData = ApiTableMetaData.of(table);
|
||||
ApiTableMetaDataContainer apiTableMetaDataContainer = ApiTableMetaDataContainer.of(table);
|
||||
if(apiTableMetaDataContainer == null)
|
||||
{
|
||||
LOG.debug("Omitting table [" + tableName + "] because it does not have an apiTableMetaDataContainer");
|
||||
continue;
|
||||
}
|
||||
|
||||
ApiTableMetaData apiTableMetaData = apiTableMetaDataContainer.getApiTableMetaData(apiName);
|
||||
if(apiTableMetaData == null)
|
||||
{
|
||||
LOG.debug("Omitting table [" + tableName + "] because it does not have any apiTableMetaData");
|
||||
@ -312,8 +342,8 @@ public class GenerateOpenApiSpecAction extends AbstractQActionFunction<GenerateO
|
||||
String primaryKeyName = table.getPrimaryKeyField();
|
||||
QFieldMetaData primaryKeyField = table.getField(table.getPrimaryKeyField());
|
||||
String primaryKeyLabel = primaryKeyField.getLabel();
|
||||
String primaryKeyApiName = ApiFieldMetaData.getEffectiveApiFieldName(primaryKeyField);
|
||||
List<QFieldMetaData> tableApiFields = new GetTableApiFieldsAction().execute(new GetTableApiFieldsInput().withTableName(tableName).withVersion(version)).getFields();
|
||||
String primaryKeyApiName = ApiFieldMetaData.getEffectiveApiFieldName(apiName, primaryKeyField);
|
||||
List<QFieldMetaData> tableApiFields = new GetTableApiFieldsAction().execute(new GetTableApiFieldsInput().withTableName(tableName).withVersion(version).withApiName(apiName)).getFields();
|
||||
|
||||
///////////////////////////////
|
||||
// permissions for the table //
|
||||
@ -365,13 +395,13 @@ public class GenerateOpenApiSpecAction extends AbstractQActionFunction<GenerateO
|
||||
for(QFieldMetaData field : tableApiFields)
|
||||
{
|
||||
Schema fieldSchema = getFieldSchema(table, field);
|
||||
tableFields.put(ApiFieldMetaData.getEffectiveApiFieldName(field), fieldSchema);
|
||||
tableFields.put(ApiFieldMetaData.getEffectiveApiFieldName(apiInstanceMetaData.getName(), field), fieldSchema);
|
||||
}
|
||||
|
||||
//////////////////////////////////
|
||||
// recursively add associations //
|
||||
//////////////////////////////////
|
||||
addAssociations(table, tableSchema);
|
||||
addAssociations(apiName, table, tableSchema);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// table as a search result (the base search result, plus the table itself) //
|
||||
@ -770,13 +800,13 @@ public class GenerateOpenApiSpecAction extends AbstractQActionFunction<GenerateO
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private static void addAssociations(QTableMetaData table, Schema tableSchema)
|
||||
private static void addAssociations(String apiName, QTableMetaData table, Schema tableSchema)
|
||||
{
|
||||
for(Association association : CollectionUtils.nonNullList(table.getAssociations()))
|
||||
{
|
||||
String associatedTableName = association.getAssociatedTableName();
|
||||
QTableMetaData associatedTable = QContext.getQInstance().getTable(associatedTableName);
|
||||
ApiTableMetaData associatedApiTableMetaData = Objects.requireNonNullElse(ApiTableMetaData.of(associatedTable), new ApiTableMetaData());
|
||||
ApiTableMetaData associatedApiTableMetaData = ObjectUtils.tryElse(() -> ApiTableMetaDataContainer.of(associatedTable).getApiTableMetaData(apiName), new ApiTableMetaData());
|
||||
String associatedTableApiName = StringUtils.hasContent(associatedApiTableMetaData.getApiTableName()) ? associatedApiTableMetaData.getApiTableName() : associatedTableName;
|
||||
|
||||
tableSchema.getProperties().put(association.getName(), new Schema()
|
||||
|
@ -30,13 +30,16 @@ import com.kingsrook.qqq.api.model.APIVersionRange;
|
||||
import com.kingsrook.qqq.api.model.actions.GetTableApiFieldsInput;
|
||||
import com.kingsrook.qqq.api.model.actions.GetTableApiFieldsOutput;
|
||||
import com.kingsrook.qqq.api.model.metadata.fields.ApiFieldMetaData;
|
||||
import com.kingsrook.qqq.api.model.metadata.fields.ApiFieldMetaDataContainer;
|
||||
import com.kingsrook.qqq.api.model.metadata.tables.ApiTableMetaData;
|
||||
import com.kingsrook.qqq.api.model.metadata.tables.ApiTableMetaDataContainer;
|
||||
import com.kingsrook.qqq.backend.core.actions.AbstractQActionFunction;
|
||||
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||
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.ObjectUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||
import org.apache.commons.lang.BooleanUtils;
|
||||
|
||||
@ -73,7 +76,7 @@ public class GetTableApiFieldsAction extends AbstractQActionFunction<GetTableApi
|
||||
fieldList.sort(Comparator.comparing(QFieldMetaData::getLabel));
|
||||
for(QFieldMetaData field : fieldList)
|
||||
{
|
||||
if(!isExcluded(field) && getApiVersionRange(field).includes(version))
|
||||
if(!isExcluded(input.getApiName(), field) && getApiVersionRange(input.getApiName(), field).includes(version))
|
||||
{
|
||||
fields.add(field);
|
||||
}
|
||||
@ -82,9 +85,9 @@ public class GetTableApiFieldsAction extends AbstractQActionFunction<GetTableApi
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// look for removed fields (e.g., not currently in the table anymore), that are in this version //
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
for(QFieldMetaData field : CollectionUtils.nonNullList(getRemovedApiFields(table)))
|
||||
for(QFieldMetaData field : CollectionUtils.nonNullList(getRemovedApiFields(input.getApiName(), table)))
|
||||
{
|
||||
if(!isExcluded(field) && getApiVersionRangeForRemovedField(field).includes(version))
|
||||
if(!isExcluded(input.getApiName(), field) && getApiVersionRangeForRemovedField(input.getApiName(), field).includes(version))
|
||||
{
|
||||
fields.add(field);
|
||||
}
|
||||
@ -98,9 +101,9 @@ public class GetTableApiFieldsAction extends AbstractQActionFunction<GetTableApi
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private boolean isExcluded(QFieldMetaData field)
|
||||
private boolean isExcluded(String apiName, QFieldMetaData field)
|
||||
{
|
||||
ApiFieldMetaData apiFieldMetaData = ApiFieldMetaData.of(field);
|
||||
ApiFieldMetaData apiFieldMetaData = getApiFieldMetaData(apiName, field);
|
||||
if(apiFieldMetaData != null && BooleanUtils.isTrue(apiFieldMetaData.getIsExcluded()))
|
||||
{
|
||||
return (true);
|
||||
@ -114,14 +117,14 @@ public class GetTableApiFieldsAction extends AbstractQActionFunction<GetTableApi
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private APIVersionRange getApiVersionRangeForRemovedField(QFieldMetaData field)
|
||||
private APIVersionRange getApiVersionRangeForRemovedField(String apiName, QFieldMetaData field)
|
||||
{
|
||||
ApiFieldMetaData middlewareMetaData = ApiFieldMetaData.of(field);
|
||||
if(middlewareMetaData != null && middlewareMetaData.getInitialVersion() != null)
|
||||
ApiFieldMetaData apiFieldMetaData = getApiFieldMetaData(apiName, field);
|
||||
if(apiFieldMetaData != null && apiFieldMetaData.getInitialVersion() != null)
|
||||
{
|
||||
if(StringUtils.hasContent(middlewareMetaData.getFinalVersion()))
|
||||
if(StringUtils.hasContent(apiFieldMetaData.getFinalVersion()))
|
||||
{
|
||||
return (APIVersionRange.betweenAndIncluding(middlewareMetaData.getInitialVersion(), middlewareMetaData.getFinalVersion()));
|
||||
return (APIVersionRange.betweenAndIncluding(apiFieldMetaData.getInitialVersion(), apiFieldMetaData.getFinalVersion()));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -139,12 +142,12 @@ public class GetTableApiFieldsAction extends AbstractQActionFunction<GetTableApi
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private APIVersionRange getApiVersionRange(QFieldMetaData field)
|
||||
private APIVersionRange getApiVersionRange(String apiName, QFieldMetaData field)
|
||||
{
|
||||
ApiFieldMetaData middlewareMetaData = ApiFieldMetaData.of(field);
|
||||
if(middlewareMetaData != null && middlewareMetaData.getInitialVersion() != null)
|
||||
ApiFieldMetaData apiFieldMetaData = getApiFieldMetaData(apiName, field);
|
||||
if(apiFieldMetaData != null && apiFieldMetaData.getInitialVersion() != null)
|
||||
{
|
||||
return (APIVersionRange.afterAndIncluding(middlewareMetaData.getInitialVersion()));
|
||||
return (APIVersionRange.afterAndIncluding(apiFieldMetaData.getInitialVersion()));
|
||||
}
|
||||
|
||||
return (APIVersionRange.none());
|
||||
@ -155,9 +158,19 @@ public class GetTableApiFieldsAction extends AbstractQActionFunction<GetTableApi
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private List<QFieldMetaData> getRemovedApiFields(QTableMetaData table)
|
||||
private static ApiFieldMetaData getApiFieldMetaData(String apiName, QFieldMetaData field)
|
||||
{
|
||||
ApiTableMetaData apiTableMetaData = ApiTableMetaData.of(table);
|
||||
return ObjectUtils.tryAndRequireNonNullElse(() -> ApiFieldMetaDataContainer.of(field).getApiFieldMetaData(apiName), new ApiFieldMetaData());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private List<QFieldMetaData> getRemovedApiFields(String apiName, QTableMetaData table)
|
||||
{
|
||||
ApiTableMetaData apiTableMetaData = ObjectUtils.tryAndRequireNonNullElse(() -> ApiTableMetaDataContainer.of(table).getApiTableMetaData(apiName), new ApiTableMetaData());
|
||||
if(apiTableMetaData != null)
|
||||
{
|
||||
return (apiTableMetaData.getRemovedApiFields());
|
||||
|
@ -32,6 +32,7 @@ import java.util.stream.Collectors;
|
||||
import com.kingsrook.qqq.api.javalin.QBadRequestException;
|
||||
import com.kingsrook.qqq.api.model.actions.GetTableApiFieldsInput;
|
||||
import com.kingsrook.qqq.api.model.metadata.fields.ApiFieldMetaData;
|
||||
import com.kingsrook.qqq.api.model.metadata.fields.ApiFieldMetaDataContainer;
|
||||
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
||||
@ -40,7 +41,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||
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;
|
||||
import com.kingsrook.qqq.backend.core.utils.Pair;
|
||||
import com.kingsrook.qqq.backend.core.utils.ObjectUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
@ -53,17 +54,17 @@ public class QRecordApiAdapter
|
||||
{
|
||||
private static final QLogger LOG = QLogger.getLogger(QRecordApiAdapter.class);
|
||||
|
||||
private static Map<Pair<String, String>, List<QFieldMetaData>> fieldListCache = new HashMap<>();
|
||||
private static Map<Pair<String, String>, Map<String, QFieldMetaData>> fieldMapCache = new HashMap<>();
|
||||
private static Map<ApiNameVersionAndTableName, List<QFieldMetaData>> fieldListCache = new HashMap<>();
|
||||
private static Map<ApiNameVersionAndTableName, Map<String, QFieldMetaData>> fieldMapCache = new HashMap<>();
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Convert a QRecord to a map for the API
|
||||
*******************************************************************************/
|
||||
public static Map<String, Serializable> qRecordToApiMap(QRecord record, String tableName, String apiVersion) throws QException
|
||||
public static Map<String, Serializable> qRecordToApiMap(QRecord record, String tableName, String apiName, String apiVersion) throws QException
|
||||
{
|
||||
List<QFieldMetaData> tableApiFields = getTableApiFieldList(tableName, apiVersion);
|
||||
List<QFieldMetaData> tableApiFields = getTableApiFieldList(new ApiNameVersionAndTableName(apiName, apiVersion, tableName));
|
||||
LinkedHashMap<String, Serializable> outputRecord = new LinkedHashMap<>();
|
||||
|
||||
/////////////////////////////////////////
|
||||
@ -71,9 +72,8 @@ public class QRecordApiAdapter
|
||||
/////////////////////////////////////////
|
||||
for(QFieldMetaData field : tableApiFields)
|
||||
{
|
||||
ApiFieldMetaData apiFieldMetaData = ApiFieldMetaData.of(field);
|
||||
|
||||
String apiFieldName = ApiFieldMetaData.getEffectiveApiFieldName(field);
|
||||
ApiFieldMetaData apiFieldMetaData = ObjectUtils.tryAndRequireNonNullElse(() -> ApiFieldMetaDataContainer.of(field).getApiFieldMetaData(apiName), new ApiFieldMetaData());
|
||||
String apiFieldName = ApiFieldMetaData.getEffectiveApiFieldName(apiName, field);
|
||||
if(StringUtils.hasContent(apiFieldMetaData.getReplacedByFieldName()))
|
||||
{
|
||||
outputRecord.put(apiFieldName, record.getValue(apiFieldMetaData.getReplacedByFieldName()));
|
||||
@ -96,7 +96,7 @@ public class QRecordApiAdapter
|
||||
|
||||
for(QRecord associatedRecord : CollectionUtils.nonNullList(CollectionUtils.nonNullMap(record.getAssociatedRecords()).get(association.getName())))
|
||||
{
|
||||
associationList.add(qRecordToApiMap(associatedRecord, association.getAssociatedTableName(), apiVersion));
|
||||
associationList.add(qRecordToApiMap(associatedRecord, association.getAssociatedTableName(), apiName, apiVersion));
|
||||
}
|
||||
}
|
||||
|
||||
@ -108,12 +108,12 @@ public class QRecordApiAdapter
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public static QRecord apiJsonObjectToQRecord(JSONObject jsonObject, String tableName, String apiVersion, boolean includePrimaryKey) throws QException
|
||||
public static QRecord apiJsonObjectToQRecord(JSONObject jsonObject, String tableName, String apiName, String apiVersion, boolean includePrimaryKey) throws QException
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// make map of apiFieldNames (e.g., names as api uses them) to QFieldMetaData //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
Map<String, QFieldMetaData> apiFieldsMap = getTableApiFieldMap(tableName, apiVersion);
|
||||
Map<String, QFieldMetaData> apiFieldsMap = getTableApiFieldMap(new ApiNameVersionAndTableName(apiName, apiVersion, tableName));
|
||||
List<String> unrecognizedFieldNames = new ArrayList<>();
|
||||
QRecord qRecord = new QRecord();
|
||||
|
||||
@ -153,7 +153,7 @@ public class QRecordApiAdapter
|
||||
}
|
||||
}
|
||||
|
||||
ApiFieldMetaData apiFieldMetaData = ApiFieldMetaData.of(field);
|
||||
ApiFieldMetaData apiFieldMetaData = ObjectUtils.tryAndRequireNonNullElse(() -> ApiFieldMetaDataContainer.of(field).getApiFieldMetaData(apiName), new ApiFieldMetaData());
|
||||
if(StringUtils.hasContent(apiFieldMetaData.getReplacedByFieldName()))
|
||||
{
|
||||
qRecord.setValue(apiFieldMetaData.getReplacedByFieldName(), value);
|
||||
@ -178,7 +178,7 @@ public class QRecordApiAdapter
|
||||
{
|
||||
if(subObject instanceof JSONObject subJsonObject)
|
||||
{
|
||||
QRecord subRecord = apiJsonObjectToQRecord(subJsonObject, association.getAssociatedTableName(), apiVersion, includePrimaryKey);
|
||||
QRecord subRecord = apiJsonObjectToQRecord(subJsonObject, association.getAssociatedTableName(), apiName, apiVersion, includePrimaryKey);
|
||||
qRecord.withAssociatedRecord(association.getName(), subRecord);
|
||||
}
|
||||
else
|
||||
@ -214,16 +214,15 @@ public class QRecordApiAdapter
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private static Map<String, QFieldMetaData> getTableApiFieldMap(String tableName, String apiVersion) throws QException
|
||||
private static Map<String, QFieldMetaData> getTableApiFieldMap(ApiNameVersionAndTableName apiNameVersionAndTableName) throws QException
|
||||
{
|
||||
Pair<String, String> key = new Pair<>(tableName, apiVersion);
|
||||
if(!fieldMapCache.containsKey(key))
|
||||
if(!fieldMapCache.containsKey(apiNameVersionAndTableName))
|
||||
{
|
||||
Map<String, QFieldMetaData> map = getTableApiFieldList(tableName, apiVersion).stream().collect(Collectors.toMap(f -> (ApiFieldMetaData.getEffectiveApiFieldName(f)), f -> f));
|
||||
fieldMapCache.put(key, map);
|
||||
Map<String, QFieldMetaData> map = getTableApiFieldList(apiNameVersionAndTableName).stream().collect(Collectors.toMap(f -> (ApiFieldMetaData.getEffectiveApiFieldName(apiNameVersionAndTableName.apiName(), f)), f -> f));
|
||||
fieldMapCache.put(apiNameVersionAndTableName, map);
|
||||
}
|
||||
|
||||
return (fieldMapCache.get(key));
|
||||
return (fieldMapCache.get(apiNameVersionAndTableName));
|
||||
}
|
||||
|
||||
|
||||
@ -231,14 +230,27 @@ public class QRecordApiAdapter
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private static List<QFieldMetaData> getTableApiFieldList(String tableName, String apiVersion) throws QException
|
||||
private static List<QFieldMetaData> getTableApiFieldList(ApiNameVersionAndTableName apiNameVersionAndTableName) throws QException
|
||||
{
|
||||
Pair<String, String> key = new Pair<>(tableName, apiVersion);
|
||||
if(!fieldListCache.containsKey(key))
|
||||
if(!fieldListCache.containsKey(apiNameVersionAndTableName))
|
||||
{
|
||||
List<QFieldMetaData> value = new GetTableApiFieldsAction().execute(new GetTableApiFieldsInput().withTableName(tableName).withVersion(apiVersion)).getFields();
|
||||
fieldListCache.put(key, value);
|
||||
List<QFieldMetaData> value = new GetTableApiFieldsAction().execute(new GetTableApiFieldsInput()
|
||||
.withTableName(apiNameVersionAndTableName.tableName())
|
||||
.withVersion(apiNameVersionAndTableName.apiVersion())
|
||||
.withApiName(apiNameVersionAndTableName.apiName())).getFields();
|
||||
fieldListCache.put(apiNameVersionAndTableName, value);
|
||||
}
|
||||
return (fieldListCache.get(key));
|
||||
return (fieldListCache.get(apiNameVersionAndTableName));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private record ApiNameVersionAndTableName(String apiName, String apiVersion, String tableName)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -44,7 +44,9 @@ import com.kingsrook.qqq.api.model.actions.GenerateOpenApiSpecInput;
|
||||
import com.kingsrook.qqq.api.model.actions.GenerateOpenApiSpecOutput;
|
||||
import com.kingsrook.qqq.api.model.metadata.APILogMetaDataProvider;
|
||||
import com.kingsrook.qqq.api.model.metadata.ApiInstanceMetaData;
|
||||
import com.kingsrook.qqq.api.model.metadata.ApiInstanceMetaDataContainer;
|
||||
import com.kingsrook.qqq.api.model.metadata.tables.ApiTableMetaData;
|
||||
import com.kingsrook.qqq.api.model.metadata.tables.ApiTableMetaDataContainer;
|
||||
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.tables.CountAction;
|
||||
@ -92,6 +94,7 @@ import com.kingsrook.qqq.backend.core.modules.authentication.QAuthenticationModu
|
||||
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.ExceptionUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.JsonUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.Pair;
|
||||
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.ValueUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.collections.ListBuilder;
|
||||
@ -121,7 +124,10 @@ public class QJavalinApiHandler
|
||||
|
||||
private static QInstance qInstance;
|
||||
|
||||
private static Map<String, Map<String, QTableMetaData>> tableApiNameMap = new HashMap<>();
|
||||
/////////////////////////////////////
|
||||
// key: Pair<apiName, apiVersion> //
|
||||
/////////////////////////////////////
|
||||
private static Map<Pair<String, String>, Map<String, QTableMetaData>> tableApiNameMap = new HashMap<>();
|
||||
|
||||
private static Map<String, Integer> apiLogUserIdCache = new HashMap<>();
|
||||
|
||||
@ -156,56 +162,59 @@ public class QJavalinApiHandler
|
||||
ApiBuilder.get("/api/docs/js/rapidoc.min.js", (context) -> QJavalinApiHandler.serveResource(context, "rapidoc/rapidoc-9.3.4.min.js", MapBuilder.of("Content-Type", ContentType.JAVASCRIPT)));
|
||||
ApiBuilder.get("/api/docs/css/qqq-api-styles.css", (context) -> QJavalinApiHandler.serveResource(context, "rapidoc/rapidoc-overrides.css", MapBuilder.of("Content-Type", ContentType.CSS)));
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// default page is the current version spec //
|
||||
//////////////////////////////////////////////
|
||||
ApiBuilder.get("/api/", QJavalinApiHandler::doSpecHtml);
|
||||
|
||||
ApiBuilder.path("/api/{version}", () -> // todo - configurable, that /api/ bit?
|
||||
ApiInstanceMetaDataContainer apiInstanceMetaDataContainer = ApiInstanceMetaDataContainer.of(qInstance);
|
||||
for(Map.Entry<String, ApiInstanceMetaData> entry : apiInstanceMetaDataContainer.getApis().entrySet())
|
||||
{
|
||||
////////////////////////////////////////////
|
||||
// default page for a version is its spec //
|
||||
////////////////////////////////////////////
|
||||
ApiBuilder.get("/", QJavalinApiHandler::doSpecHtml);
|
||||
ApiInstanceMetaData apiInstanceMetaData = entry.getValue();
|
||||
String rootPath = apiInstanceMetaData.getPath();
|
||||
|
||||
ApiBuilder.get("/openapi.yaml", QJavalinApiHandler::doSpecYaml);
|
||||
ApiBuilder.get("/openapi.json", QJavalinApiHandler::doSpecJson);
|
||||
ApiBuilder.get("/openapi.html", QJavalinApiHandler::doSpecHtml);
|
||||
//////////////////////////////////////////////
|
||||
// default page is the current version spec //
|
||||
//////////////////////////////////////////////
|
||||
ApiBuilder.get(rootPath, context -> doSpecHtml(context, apiInstanceMetaData));
|
||||
|
||||
ApiBuilder.path("/{tableName}", () ->
|
||||
ApiBuilder.path(rootPath + "{version}", () ->
|
||||
{
|
||||
ApiBuilder.get("/openapi.yaml", QJavalinApiHandler::doSpecYaml);
|
||||
ApiBuilder.get("/openapi.json", QJavalinApiHandler::doSpecJson);
|
||||
////////////////////////////////////////////
|
||||
// default page for a version is its spec //
|
||||
////////////////////////////////////////////
|
||||
ApiBuilder.get("/", context -> doSpecHtml(context, apiInstanceMetaData));
|
||||
|
||||
ApiBuilder.post("/", QJavalinApiHandler::doInsert);
|
||||
ApiBuilder.get("/openapi.yaml", context -> doSpecYaml(context, apiInstanceMetaData));
|
||||
ApiBuilder.get("/openapi.json", context -> doSpecJson(context, apiInstanceMetaData));
|
||||
ApiBuilder.get("/openapi.html", context -> doSpecHtml(context, apiInstanceMetaData));
|
||||
|
||||
ApiBuilder.get("/query", QJavalinApiHandler::doQuery);
|
||||
// ApiBuilder.post("/query", QJavalinApiHandler::doQuery);
|
||||
ApiBuilder.path("/{tableName}", () ->
|
||||
{
|
||||
ApiBuilder.get("/openapi.yaml", context -> doSpecYaml(context, apiInstanceMetaData));
|
||||
ApiBuilder.get("/openapi.json", context -> doSpecJson(context, apiInstanceMetaData));
|
||||
|
||||
ApiBuilder.post("/bulk", QJavalinApiHandler::bulkInsert);
|
||||
ApiBuilder.patch("/bulk", QJavalinApiHandler::bulkUpdate);
|
||||
ApiBuilder.delete("/bulk", QJavalinApiHandler::bulkDelete);
|
||||
ApiBuilder.post("/", context -> doInsert(context, apiInstanceMetaData));
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// remember to keep the wildcard paths after the specific paths //
|
||||
//////////////////////////////////////////////////////////////////
|
||||
ApiBuilder.get("/{primaryKey}", QJavalinApiHandler::doGet);
|
||||
ApiBuilder.patch("/{primaryKey}", QJavalinApiHandler::doUpdate);
|
||||
ApiBuilder.delete("/{primaryKey}", QJavalinApiHandler::doDelete);
|
||||
ApiBuilder.get("/query", context -> doQuery(context, apiInstanceMetaData));
|
||||
// ApiBuilder.post("/query", context -> doQuery(context, apiInstanceMetaData));
|
||||
|
||||
ApiBuilder.post("/bulk", context -> bulkInsert(context, apiInstanceMetaData));
|
||||
ApiBuilder.patch("/bulk", context -> bulkUpdate(context, apiInstanceMetaData));
|
||||
ApiBuilder.delete("/bulk", context -> bulkDelete(context, apiInstanceMetaData));
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// remember to keep the wildcard paths after the specific paths //
|
||||
//////////////////////////////////////////////////////////////////
|
||||
ApiBuilder.get("/{primaryKey}", context -> doGet(context, apiInstanceMetaData));
|
||||
ApiBuilder.patch("/{primaryKey}", context -> doUpdate(context, apiInstanceMetaData));
|
||||
ApiBuilder.delete("/{primaryKey}", context -> doDelete(context, apiInstanceMetaData));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
ApiBuilder.get("/api/versions.json", QJavalinApiHandler::doVersions);
|
||||
|
||||
ApiBuilder.before("/*", QJavalinApiHandler::setupCORS);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// default all other /api/ requests (for the methods we support) to a standard 404 response //
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
ApiBuilder.get("/api/*", QJavalinApiHandler::doPathNotFound);
|
||||
ApiBuilder.delete("/api/*", QJavalinApiHandler::doPathNotFound);
|
||||
ApiBuilder.patch("/api/*", QJavalinApiHandler::doPathNotFound);
|
||||
ApiBuilder.post("/api/*", QJavalinApiHandler::doPathNotFound);
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// default all other requests under the root path (for the methods we support) to a standard 404 response //
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
ApiBuilder.get(rootPath + "*", QJavalinApiHandler::doPathNotFound);
|
||||
ApiBuilder.delete(rootPath + "*", QJavalinApiHandler::doPathNotFound);
|
||||
ApiBuilder.patch(rootPath + "*", QJavalinApiHandler::doPathNotFound);
|
||||
ApiBuilder.post(rootPath + "*", QJavalinApiHandler::doPathNotFound);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// if the main implementation class has a hot-swapper installed, use it here too //
|
||||
@ -241,10 +250,8 @@ public class QJavalinApiHandler
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private static void doVersions(Context context)
|
||||
private static void doVersions(Context context, ApiInstanceMetaData apiInstanceMetaData)
|
||||
{
|
||||
ApiInstanceMetaData apiInstanceMetaData = ApiInstanceMetaData.of(qInstance);
|
||||
|
||||
Map<String, Object> rs = new HashMap<>();
|
||||
rs.put("supportedVersions", apiInstanceMetaData.getSupportedVersions().stream().map(String::valueOf).collect(Collectors.toList()));
|
||||
rs.put("currentVersion", apiInstanceMetaData.getCurrentVersion().toString());
|
||||
@ -401,7 +408,7 @@ public class QJavalinApiHandler
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private static void doSpecYaml(Context context)
|
||||
private static void doSpecYaml(Context context, ApiInstanceMetaData apiInstanceMetaData)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -409,6 +416,8 @@ public class QJavalinApiHandler
|
||||
String version = context.pathParam("version");
|
||||
|
||||
GenerateOpenApiSpecInput input = new GenerateOpenApiSpecInput().withVersion(version);
|
||||
input.setApiName(apiInstanceMetaData.getName());
|
||||
|
||||
try
|
||||
{
|
||||
if(StringUtils.hasContent(context.pathParam("tableName")))
|
||||
@ -438,13 +447,14 @@ public class QJavalinApiHandler
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private static void doSpecJson(Context context)
|
||||
private static void doSpecJson(Context context, ApiInstanceMetaData apiInstanceMetaData)
|
||||
{
|
||||
try
|
||||
{
|
||||
QContext.init(qInstance, null);
|
||||
String version = context.pathParam("version");
|
||||
GenerateOpenApiSpecInput input = new GenerateOpenApiSpecInput().withVersion(version);
|
||||
input.setApiName(apiInstanceMetaData.getName());
|
||||
|
||||
try
|
||||
{
|
||||
@ -475,7 +485,7 @@ public class QJavalinApiHandler
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private static void doSpecHtml(Context context)
|
||||
private static void doSpecHtml(Context context, ApiInstanceMetaData apiInstanceMetaData)
|
||||
{
|
||||
String version;
|
||||
|
||||
@ -485,11 +495,10 @@ public class QJavalinApiHandler
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
ApiInstanceMetaData apiInstanceMetaData = ApiInstanceMetaData.of(qInstance);
|
||||
version = apiInstanceMetaData.getCurrentVersion().toString();
|
||||
}
|
||||
|
||||
doSpecHtml(context, version);
|
||||
doSpecHtml(context, version, apiInstanceMetaData);
|
||||
}
|
||||
|
||||
|
||||
@ -497,12 +506,11 @@ public class QJavalinApiHandler
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private static void doSpecHtml(Context context, String version)
|
||||
private static void doSpecHtml(Context context, String version, ApiInstanceMetaData apiInstanceMetaData)
|
||||
{
|
||||
try
|
||||
{
|
||||
QBrandingMetaData branding = qInstance.getBranding();
|
||||
ApiInstanceMetaData apiInstanceMetaData = ApiInstanceMetaData.of(qInstance);
|
||||
QBrandingMetaData branding = qInstance.getBranding();
|
||||
|
||||
if(!apiInstanceMetaData.getSupportedVersions().contains(new APIVersion(version)))
|
||||
{
|
||||
@ -536,7 +544,7 @@ public class QJavalinApiHandler
|
||||
StringBuilder otherVersionOptions = new StringBuilder();
|
||||
for(APIVersion supportedVersion : apiInstanceMetaData.getSupportedVersions())
|
||||
{
|
||||
otherVersionOptions.append("<option value=\"/api/").append(supportedVersion).append("/openapi.html\">").append(supportedVersion).append("</option>");
|
||||
otherVersionOptions.append("<option value=\"").append(apiInstanceMetaData.getPath()).append(supportedVersion).append("/openapi.html\">").append(supportedVersion).append("</option>");
|
||||
}
|
||||
html = html.replace("{otherVersionOptions}", otherVersionOptions.toString());
|
||||
|
||||
@ -565,7 +573,7 @@ public class QJavalinApiHandler
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private static void doGet(Context context)
|
||||
private static void doGet(Context context, ApiInstanceMetaData apiInstanceMetaData)
|
||||
{
|
||||
String version = context.pathParam("version");
|
||||
String tableApiName = context.pathParam("tableName");
|
||||
@ -574,7 +582,7 @@ public class QJavalinApiHandler
|
||||
|
||||
try
|
||||
{
|
||||
QTableMetaData table = validateTableAndVersion(context, version, tableApiName);
|
||||
QTableMetaData table = validateTableAndVersion(context, apiInstanceMetaData, version, tableApiName);
|
||||
String tableName = table.getName();
|
||||
|
||||
GetInput getInput = new GetInput();
|
||||
@ -605,7 +613,7 @@ public class QJavalinApiHandler
|
||||
+ table.getFields().get(table.getPrimaryKeyField()).getLabel() + " of " + primaryKey));
|
||||
}
|
||||
|
||||
Map<String, Serializable> outputRecord = QRecordApiAdapter.qRecordToApiMap(record, tableName, version);
|
||||
Map<String, Serializable> outputRecord = QRecordApiAdapter.qRecordToApiMap(record, tableName, apiInstanceMetaData.getName(), version);
|
||||
|
||||
QJavalinAccessLogger.logEndSuccess();
|
||||
String resultString = JsonUtils.toJson(outputRecord);
|
||||
@ -817,7 +825,7 @@ public class QJavalinApiHandler
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private static void doQuery(Context context)
|
||||
private static void doQuery(Context context, ApiInstanceMetaData apiInstanceMetaData)
|
||||
{
|
||||
String version = context.pathParam("version");
|
||||
String tableApiName = context.pathParam("tableName");
|
||||
@ -828,7 +836,7 @@ public class QJavalinApiHandler
|
||||
{
|
||||
List<String> badRequestMessages = new ArrayList<>();
|
||||
|
||||
QTableMetaData table = validateTableAndVersion(context, version, tableApiName);
|
||||
QTableMetaData table = validateTableAndVersion(context, apiInstanceMetaData, version, tableApiName);
|
||||
String tableName = table.getName();
|
||||
|
||||
QueryInput queryInput = new QueryInput();
|
||||
@ -1023,7 +1031,7 @@ public class QJavalinApiHandler
|
||||
ArrayList<Map<String, Serializable>> records = new ArrayList<>();
|
||||
for(QRecord record : queryOutput.getRecords())
|
||||
{
|
||||
records.add(QRecordApiAdapter.qRecordToApiMap(record, tableName, version));
|
||||
records.add(QRecordApiAdapter.qRecordToApiMap(record, tableName, apiInstanceMetaData.getName(), version));
|
||||
}
|
||||
|
||||
/////////////////////////////
|
||||
@ -1057,11 +1065,11 @@ public class QJavalinApiHandler
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private static QTableMetaData validateTableAndVersion(Context context, String version, String tableApiName) throws QNotFoundException
|
||||
private static QTableMetaData validateTableAndVersion(Context context, ApiInstanceMetaData apiInstanceMetaData, String version, String tableApiName) throws QNotFoundException
|
||||
{
|
||||
QNotFoundException qNotFoundException = new QNotFoundException("Could not find any resources at path " + context.path());
|
||||
|
||||
QTableMetaData table = getTableByApiName(version, tableApiName);
|
||||
QTableMetaData table = getTableByApiName(apiInstanceMetaData.getName(), version, tableApiName);
|
||||
|
||||
if(table == null)
|
||||
{
|
||||
@ -1073,7 +1081,13 @@ public class QJavalinApiHandler
|
||||
throw (qNotFoundException);
|
||||
}
|
||||
|
||||
ApiTableMetaData apiTableMetaData = ApiTableMetaData.of(table);
|
||||
ApiTableMetaDataContainer apiTableMetaDataContainer = ApiTableMetaDataContainer.of(table);
|
||||
if(apiTableMetaDataContainer == null)
|
||||
{
|
||||
throw (qNotFoundException);
|
||||
}
|
||||
|
||||
ApiTableMetaData apiTableMetaData = apiTableMetaDataContainer.getApiTableMetaData(apiInstanceMetaData.getName());
|
||||
if(apiTableMetaData == null)
|
||||
{
|
||||
throw (qNotFoundException);
|
||||
@ -1085,7 +1099,7 @@ public class QJavalinApiHandler
|
||||
}
|
||||
|
||||
APIVersion requestApiVersion = new APIVersion(version);
|
||||
List<APIVersion> supportedVersions = ApiInstanceMetaData.of(qInstance).getSupportedVersions();
|
||||
List<APIVersion> supportedVersions = apiInstanceMetaData.getSupportedVersions();
|
||||
if(CollectionUtils.nullSafeIsEmpty(supportedVersions) || !supportedVersions.contains(requestApiVersion))
|
||||
{
|
||||
throw (qNotFoundException);
|
||||
@ -1104,27 +1118,40 @@ public class QJavalinApiHandler
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private static QTableMetaData getTableByApiName(String version, String tableApiName)
|
||||
private static QTableMetaData getTableByApiName(String apiName, String version, String tableApiName)
|
||||
{
|
||||
if(tableApiNameMap.get(version) == null)
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// tableApiNameMap is a map of (apiName,apiVersion) => Map<String, QTableMetaData>. //
|
||||
// that is to say, a 2-level map. The first level is keyed by (apiName,apiVersion) pairs. //
|
||||
// the second level is keyed by tableApiNames. //
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
Pair<String, String> key = new Pair<>(apiName, version);
|
||||
if(tableApiNameMap.get(key) == null)
|
||||
{
|
||||
Map<String, QTableMetaData> map = new HashMap<>();
|
||||
|
||||
for(QTableMetaData table : qInstance.getTables().values())
|
||||
{
|
||||
ApiTableMetaData apiTableMetaData = ApiTableMetaData.of(table);
|
||||
String name = table.getName();
|
||||
if(apiTableMetaData != null && StringUtils.hasContent(apiTableMetaData.getApiTableName()))
|
||||
ApiTableMetaDataContainer apiTableMetaDataContainer = ApiTableMetaDataContainer.of(table);
|
||||
if(apiTableMetaDataContainer != null)
|
||||
{
|
||||
name = apiTableMetaData.getApiTableName();
|
||||
ApiTableMetaData apiTableMetaData = apiTableMetaDataContainer.getApiTableMetaData(apiName);
|
||||
if(apiTableMetaData != null)
|
||||
{
|
||||
String name = table.getName();
|
||||
if(StringUtils.hasContent(apiTableMetaData.getApiTableName()))
|
||||
{
|
||||
name = apiTableMetaData.getApiTableName();
|
||||
}
|
||||
map.put(name, table);
|
||||
}
|
||||
}
|
||||
map.put(name, table);
|
||||
}
|
||||
|
||||
tableApiNameMap.put(version, map);
|
||||
tableApiNameMap.put(key, map);
|
||||
}
|
||||
|
||||
return (tableApiNameMap.get(version).get(tableApiName));
|
||||
return (tableApiNameMap.get(key).get(tableApiName));
|
||||
}
|
||||
|
||||
|
||||
@ -1258,7 +1285,7 @@ public class QJavalinApiHandler
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private static void doInsert(Context context)
|
||||
private static void doInsert(Context context, ApiInstanceMetaData apiInstanceMetaData)
|
||||
{
|
||||
String version = context.pathParam("version");
|
||||
String tableApiName = context.pathParam("tableName");
|
||||
@ -1266,7 +1293,7 @@ public class QJavalinApiHandler
|
||||
|
||||
try
|
||||
{
|
||||
QTableMetaData table = validateTableAndVersion(context, version, tableApiName);
|
||||
QTableMetaData table = validateTableAndVersion(context, apiInstanceMetaData, version, tableApiName);
|
||||
String tableName = table.getName();
|
||||
|
||||
InsertInput insertInput = new InsertInput();
|
||||
@ -1288,7 +1315,7 @@ public class QJavalinApiHandler
|
||||
JSONTokener jsonTokener = new JSONTokener(context.body().trim());
|
||||
JSONObject jsonObject = new JSONObject(jsonTokener);
|
||||
|
||||
insertInput.setRecords(List.of(QRecordApiAdapter.apiJsonObjectToQRecord(jsonObject, tableName, version, false)));
|
||||
insertInput.setRecords(List.of(QRecordApiAdapter.apiJsonObjectToQRecord(jsonObject, tableName, apiInstanceMetaData.getName(), version, false)));
|
||||
|
||||
if(jsonTokener.more())
|
||||
{
|
||||
@ -1328,7 +1355,7 @@ public class QJavalinApiHandler
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private static void bulkInsert(Context context)
|
||||
private static void bulkInsert(Context context, ApiInstanceMetaData apiInstanceMetaData)
|
||||
{
|
||||
String version = context.pathParam("version");
|
||||
String tableApiName = context.pathParam("tableName");
|
||||
@ -1336,7 +1363,7 @@ public class QJavalinApiHandler
|
||||
|
||||
try
|
||||
{
|
||||
QTableMetaData table = validateTableAndVersion(context, version, tableApiName);
|
||||
QTableMetaData table = validateTableAndVersion(context, apiInstanceMetaData, version, tableApiName);
|
||||
String tableName = table.getName();
|
||||
|
||||
InsertInput insertInput = new InsertInput();
|
||||
@ -1367,7 +1394,7 @@ public class QJavalinApiHandler
|
||||
for(int i = 0; i < jsonArray.length(); i++)
|
||||
{
|
||||
JSONObject jsonObject = jsonArray.getJSONObject(i);
|
||||
recordList.add(QRecordApiAdapter.apiJsonObjectToQRecord(jsonObject, tableName, version, false));
|
||||
recordList.add(QRecordApiAdapter.apiJsonObjectToQRecord(jsonObject, tableName, apiInstanceMetaData.getName(), version, false));
|
||||
}
|
||||
|
||||
if(jsonTokener.more())
|
||||
@ -1437,7 +1464,7 @@ public class QJavalinApiHandler
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private static void bulkUpdate(Context context)
|
||||
private static void bulkUpdate(Context context, ApiInstanceMetaData apiInstanceMetaData)
|
||||
{
|
||||
String version = context.pathParam("version");
|
||||
String tableApiName = context.pathParam("tableName");
|
||||
@ -1445,7 +1472,7 @@ public class QJavalinApiHandler
|
||||
|
||||
try
|
||||
{
|
||||
QTableMetaData table = validateTableAndVersion(context, version, tableApiName);
|
||||
QTableMetaData table = validateTableAndVersion(context, apiInstanceMetaData, version, tableApiName);
|
||||
String tableName = table.getName();
|
||||
|
||||
UpdateInput updateInput = new UpdateInput();
|
||||
@ -1476,7 +1503,7 @@ public class QJavalinApiHandler
|
||||
for(int i = 0; i < jsonArray.length(); i++)
|
||||
{
|
||||
JSONObject jsonObject = jsonArray.getJSONObject(i);
|
||||
recordList.add(QRecordApiAdapter.apiJsonObjectToQRecord(jsonObject, tableName, version, true));
|
||||
recordList.add(QRecordApiAdapter.apiJsonObjectToQRecord(jsonObject, tableName, apiInstanceMetaData.getName(), version, true));
|
||||
}
|
||||
|
||||
if(jsonTokener.more())
|
||||
@ -1579,7 +1606,7 @@ public class QJavalinApiHandler
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private static void bulkDelete(Context context)
|
||||
private static void bulkDelete(Context context, ApiInstanceMetaData apiInstanceMetaData)
|
||||
{
|
||||
String version = context.pathParam("version");
|
||||
String tableApiName = context.pathParam("tableName");
|
||||
@ -1587,7 +1614,7 @@ public class QJavalinApiHandler
|
||||
|
||||
try
|
||||
{
|
||||
QTableMetaData table = validateTableAndVersion(context, version, tableApiName);
|
||||
QTableMetaData table = validateTableAndVersion(context, apiInstanceMetaData, version, tableApiName);
|
||||
String tableName = table.getName();
|
||||
|
||||
DeleteInput deleteInput = new DeleteInput();
|
||||
@ -1710,7 +1737,7 @@ public class QJavalinApiHandler
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private static void doUpdate(Context context)
|
||||
private static void doUpdate(Context context, ApiInstanceMetaData apiInstanceMetaData)
|
||||
{
|
||||
String version = context.pathParam("version");
|
||||
String tableApiName = context.pathParam("tableName");
|
||||
@ -1719,7 +1746,7 @@ public class QJavalinApiHandler
|
||||
|
||||
try
|
||||
{
|
||||
QTableMetaData table = validateTableAndVersion(context, version, tableApiName);
|
||||
QTableMetaData table = validateTableAndVersion(context, apiInstanceMetaData, version, tableApiName);
|
||||
String tableName = table.getName();
|
||||
|
||||
UpdateInput updateInput = new UpdateInput();
|
||||
@ -1741,7 +1768,7 @@ public class QJavalinApiHandler
|
||||
JSONTokener jsonTokener = new JSONTokener(context.body().trim());
|
||||
JSONObject jsonObject = new JSONObject(jsonTokener);
|
||||
|
||||
QRecord qRecord = QRecordApiAdapter.apiJsonObjectToQRecord(jsonObject, tableName, version, false);
|
||||
QRecord qRecord = QRecordApiAdapter.apiJsonObjectToQRecord(jsonObject, tableName, apiInstanceMetaData.getName(), version, false);
|
||||
qRecord.setValue(table.getPrimaryKeyField(), primaryKey);
|
||||
updateInput.setRecords(List.of(qRecord));
|
||||
|
||||
@ -1794,7 +1821,7 @@ public class QJavalinApiHandler
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private static void doDelete(Context context)
|
||||
private static void doDelete(Context context, ApiInstanceMetaData apiInstanceMetaData)
|
||||
{
|
||||
String version = context.pathParam("version");
|
||||
String tableApiName = context.pathParam("tableName");
|
||||
@ -1803,7 +1830,7 @@ public class QJavalinApiHandler
|
||||
|
||||
try
|
||||
{
|
||||
QTableMetaData table = validateTableAndVersion(context, version, tableApiName);
|
||||
QTableMetaData table = validateTableAndVersion(context, apiInstanceMetaData, version, tableApiName);
|
||||
String tableName = table.getName();
|
||||
|
||||
DeleteInput deleteInput = new DeleteInput();
|
||||
|
@ -30,6 +30,7 @@ import com.kingsrook.qqq.backend.core.model.actions.AbstractActionInput;
|
||||
*******************************************************************************/
|
||||
public class GenerateOpenApiSpecInput extends AbstractActionInput
|
||||
{
|
||||
private String apiName;
|
||||
private String version;
|
||||
private String tableName;
|
||||
|
||||
@ -95,4 +96,35 @@ public class GenerateOpenApiSpecInput extends AbstractActionInput
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for apiName
|
||||
*******************************************************************************/
|
||||
public String getApiName()
|
||||
{
|
||||
return (this.apiName);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for apiName
|
||||
*******************************************************************************/
|
||||
public void setApiName(String apiName)
|
||||
{
|
||||
this.apiName = apiName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for apiName
|
||||
*******************************************************************************/
|
||||
public GenerateOpenApiSpecInput withApiName(String apiName)
|
||||
{
|
||||
this.apiName = apiName;
|
||||
return (this);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ import com.kingsrook.qqq.backend.core.model.actions.AbstractActionInput;
|
||||
*******************************************************************************/
|
||||
public class GetTableApiFieldsInput extends AbstractActionInput
|
||||
{
|
||||
private String apiName;
|
||||
private String tableName;
|
||||
private String version;
|
||||
|
||||
@ -95,4 +96,35 @@ public class GetTableApiFieldsInput extends AbstractActionInput
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for apiName
|
||||
*******************************************************************************/
|
||||
public String getApiName()
|
||||
{
|
||||
return (this.apiName);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for apiName
|
||||
*******************************************************************************/
|
||||
public void setApiName(String apiName)
|
||||
{
|
||||
this.apiName = apiName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for apiName
|
||||
*******************************************************************************/
|
||||
public GetTableApiFieldsInput withApiName(String apiName)
|
||||
{
|
||||
this.apiName = apiName;
|
||||
return (this);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -23,8 +23,9 @@ package com.kingsrook.qqq.api.model.metadata;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeSet;
|
||||
import java.util.function.Consumer;
|
||||
import com.kingsrook.qqq.api.model.APILog;
|
||||
import com.kingsrook.qqq.api.model.APIVersion;
|
||||
@ -104,12 +105,20 @@ public class APILogMetaDataProvider
|
||||
new QPossibleValue<>(500, "500 (Internal Server Error)")
|
||||
)));
|
||||
|
||||
List<QPossibleValue<?>> apiVersionPossibleValues = new ArrayList<>();
|
||||
ApiInstanceMetaData apiInstanceMetaData = ApiInstanceMetaData.of(instance);
|
||||
LinkedHashSet<APIVersion> allVersions = new LinkedHashSet<>();
|
||||
allVersions.addAll(apiInstanceMetaData.getPastVersions());
|
||||
allVersions.addAll(apiInstanceMetaData.getSupportedVersions());
|
||||
allVersions.addAll(apiInstanceMetaData.getFutureVersions());
|
||||
List<QPossibleValue<?>> apiVersionPossibleValues = new ArrayList<>();
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// todo... this, this whole thing, should probably have "which api" as another field too... ugh. //
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
TreeSet<APIVersion> allVersions = new TreeSet<>();
|
||||
ApiInstanceMetaDataContainer apiInstanceMetaDataContainer = ApiInstanceMetaDataContainer.of(instance);
|
||||
for(Map.Entry<String, ApiInstanceMetaData> entry : apiInstanceMetaDataContainer.getApis().entrySet())
|
||||
{
|
||||
ApiInstanceMetaData apiInstanceMetaData = entry.getValue();
|
||||
allVersions.addAll(apiInstanceMetaData.getPastVersions());
|
||||
allVersions.addAll(apiInstanceMetaData.getSupportedVersions());
|
||||
allVersions.addAll(apiInstanceMetaData.getFutureVersions());
|
||||
}
|
||||
|
||||
for(APIVersion version : allVersions)
|
||||
{
|
||||
|
@ -24,14 +24,14 @@ package com.kingsrook.qqq.api.model.metadata;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import com.kingsrook.qqq.api.ApiMiddlewareType;
|
||||
import com.kingsrook.qqq.api.model.APIVersion;
|
||||
import com.kingsrook.qqq.api.model.metadata.tables.ApiTableMetaData;
|
||||
import com.kingsrook.qqq.api.model.metadata.tables.ApiTableMetaDataContainer;
|
||||
import com.kingsrook.qqq.api.model.openapi.Server;
|
||||
import com.kingsrook.qqq.backend.core.instances.QInstanceValidator;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QMiddlewareInstanceMetaData;
|
||||
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.StringUtils;
|
||||
@ -41,9 +41,11 @@ import org.apache.commons.lang.BooleanUtils;
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class ApiInstanceMetaData extends QMiddlewareInstanceMetaData
|
||||
public class ApiInstanceMetaData
|
||||
{
|
||||
private String name;
|
||||
private String label;
|
||||
private String path;
|
||||
private String description;
|
||||
private String contactEmail;
|
||||
|
||||
@ -59,58 +61,45 @@ public class ApiInstanceMetaData extends QMiddlewareInstanceMetaData
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public ApiInstanceMetaData()
|
||||
public void validate(String apiName, QInstance qInstance, QInstanceValidator validator)
|
||||
{
|
||||
setType(ApiMiddlewareType.NAME);
|
||||
}
|
||||
validator.assertCondition(Objects.equals(apiName, name), "Name mismatch for instance api (" + apiName + " != " + name + ")");
|
||||
validator.assertCondition(StringUtils.hasContent(name), "Missing name for api " + apiName);
|
||||
|
||||
if(validator.assertCondition(StringUtils.hasContent(path), "Missing path for api " + apiName))
|
||||
{
|
||||
validator.assertCondition(path.startsWith("/"), "Path for api " + apiName + " does not start with '/' (but it needs to).");
|
||||
validator.assertCondition(path.endsWith("/"), "Path for api " + apiName + " does not end with '/' (but it needs to).");
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public static ApiInstanceMetaData of(QInstance qInstance)
|
||||
{
|
||||
return ((ApiInstanceMetaData) qInstance.getMiddlewareMetaData(ApiMiddlewareType.NAME));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public void validate(QInstance qInstance, QInstanceValidator validator)
|
||||
{
|
||||
validator.assertCondition(StringUtils.hasContent(name), "Missing name for instance api");
|
||||
validator.assertCondition(StringUtils.hasContent(description), "Missing description for instance api");
|
||||
validator.assertCondition(StringUtils.hasContent(contactEmail), "Missing contactEmail for instance api");
|
||||
validator.assertCondition(StringUtils.hasContent(label), "Missing label for api " + apiName);
|
||||
validator.assertCondition(StringUtils.hasContent(description), "Missing description for api " + apiName);
|
||||
validator.assertCondition(StringUtils.hasContent(contactEmail), "Missing contactEmail for api " + apiName);
|
||||
|
||||
Set<APIVersion> allVersions = new HashSet<>();
|
||||
|
||||
if(validator.assertCondition(currentVersion != null, "Missing currentVersion for instance api"))
|
||||
if(validator.assertCondition(currentVersion != null, "Missing currentVersion for api " + apiName))
|
||||
{
|
||||
allVersions.add(currentVersion);
|
||||
}
|
||||
|
||||
if(validator.assertCondition(supportedVersions != null, "Missing supportedVersions for instance api"))
|
||||
if(validator.assertCondition(supportedVersions != null, "Missing supportedVersions for api " + apiName))
|
||||
{
|
||||
validator.assertCondition(supportedVersions.contains(currentVersion), "supportedVersions [" + supportedVersions + "] does not contain currentVersion [" + currentVersion + "] for instance api");
|
||||
validator.assertCondition(supportedVersions.contains(currentVersion), "supportedVersions [" + supportedVersions + "] does not contain currentVersion [" + currentVersion + "] for api " + apiName);
|
||||
allVersions.addAll(supportedVersions);
|
||||
}
|
||||
|
||||
for(APIVersion pastVersion : CollectionUtils.nonNullList(pastVersions))
|
||||
{
|
||||
validator.assertCondition(pastVersion.compareTo(currentVersion) < 0, "pastVersion [" + pastVersion + "] is not lexicographically before currentVersion [" + currentVersion + "] for instance api");
|
||||
validator.assertCondition(pastVersion.compareTo(currentVersion) < 0, "pastVersion [" + pastVersion + "] is not lexicographically before currentVersion [" + currentVersion + "] for api " + apiName);
|
||||
allVersions.add(pastVersion);
|
||||
}
|
||||
|
||||
for(APIVersion futureVersion : CollectionUtils.nonNullList(futureVersions))
|
||||
{
|
||||
validator.assertCondition(futureVersion.compareTo(currentVersion) > 0, "futureVersion [" + futureVersion + "] is not lexicographically after currentVersion [" + currentVersion + "] for instance api");
|
||||
validator.assertCondition(futureVersion.compareTo(currentVersion) > 0, "futureVersion [" + futureVersion + "] is not lexicographically after currentVersion [" + currentVersion + "] for api " + apiName);
|
||||
allVersions.add(futureVersion);
|
||||
}
|
||||
|
||||
@ -119,12 +108,16 @@ public class ApiInstanceMetaData extends QMiddlewareInstanceMetaData
|
||||
/////////////////////////////////
|
||||
for(QTableMetaData table : qInstance.getTables().values())
|
||||
{
|
||||
ApiTableMetaData apiTableMetaData = ApiTableMetaData.of(table);
|
||||
if(apiTableMetaData != null)
|
||||
ApiTableMetaDataContainer apiTableMetaDataContainer = ApiTableMetaDataContainer.of(table);
|
||||
if(apiTableMetaDataContainer != null)
|
||||
{
|
||||
if(BooleanUtils.isNotTrue(apiTableMetaData.getIsExcluded()))
|
||||
ApiTableMetaData apiTableMetaData = apiTableMetaDataContainer.getApiTableMetaData(apiName);
|
||||
if(apiTableMetaData != null)
|
||||
{
|
||||
validator.assertCondition(allVersions.contains(new APIVersion(apiTableMetaData.getInitialVersion())), "Table " + table.getName() + "'s initial API version is not a recognized version.");
|
||||
if(BooleanUtils.isNotTrue(apiTableMetaData.getIsExcluded()))
|
||||
{
|
||||
validator.assertCondition(allVersions.contains(new APIVersion(apiTableMetaData.getInitialVersion())), "Table " + table.getName() + "'s initial API version is not a recognized version for api " + apiName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -411,4 +404,66 @@ public class ApiInstanceMetaData extends QMiddlewareInstanceMetaData
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for label
|
||||
*******************************************************************************/
|
||||
public String getLabel()
|
||||
{
|
||||
return (this.label);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for label
|
||||
*******************************************************************************/
|
||||
public void setLabel(String label)
|
||||
{
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for label
|
||||
*******************************************************************************/
|
||||
public ApiInstanceMetaData withLabel(String label)
|
||||
{
|
||||
this.label = label;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for path
|
||||
*******************************************************************************/
|
||||
public String getPath()
|
||||
{
|
||||
return (this.path);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for path
|
||||
*******************************************************************************/
|
||||
public void setPath(String path)
|
||||
{
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for path
|
||||
*******************************************************************************/
|
||||
public ApiInstanceMetaData withPath(String path)
|
||||
{
|
||||
this.path = path;
|
||||
return (this);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,137 @@
|
||||
/*
|
||||
* 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.model.metadata;
|
||||
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.api.ApiMiddlewareType;
|
||||
import com.kingsrook.qqq.backend.core.instances.QInstanceValidator;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QMiddlewareInstanceMetaData;
|
||||
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class ApiInstanceMetaDataContainer extends QMiddlewareInstanceMetaData
|
||||
{
|
||||
private Map<String, ApiInstanceMetaData> apis;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public ApiInstanceMetaDataContainer()
|
||||
{
|
||||
setType(ApiMiddlewareType.NAME);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public static ApiInstanceMetaDataContainer of(QInstance qInstance)
|
||||
{
|
||||
return ((ApiInstanceMetaDataContainer) qInstance.getMiddlewareMetaData(ApiMiddlewareType.NAME));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public void validate(QInstance qInstance, QInstanceValidator validator)
|
||||
{
|
||||
for(Map.Entry<String, ApiInstanceMetaData> entry : CollectionUtils.nonNullMap(apis).entrySet())
|
||||
{
|
||||
entry.getValue().validate(entry.getKey(), qInstance, validator);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for apis
|
||||
*******************************************************************************/
|
||||
public Map<String, ApiInstanceMetaData> getApis()
|
||||
{
|
||||
return (this.apis);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for apis
|
||||
*******************************************************************************/
|
||||
public ApiInstanceMetaData getApiInstanceMetaData(String apiName)
|
||||
{
|
||||
if(this.apis == null)
|
||||
{
|
||||
return (null);
|
||||
}
|
||||
|
||||
return (this.apis.get(apiName));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for apis
|
||||
*******************************************************************************/
|
||||
public void setApis(Map<String, ApiInstanceMetaData> apis)
|
||||
{
|
||||
this.apis = apis;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for apis
|
||||
*******************************************************************************/
|
||||
public ApiInstanceMetaDataContainer withApis(Map<String, ApiInstanceMetaData> apis)
|
||||
{
|
||||
this.apis = apis;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for apis
|
||||
*******************************************************************************/
|
||||
public ApiInstanceMetaDataContainer withApiInstanceMetaData(ApiInstanceMetaData apiInstanceMetaData)
|
||||
{
|
||||
if(this.apis == null)
|
||||
{
|
||||
this.apis = new LinkedHashMap<>();
|
||||
}
|
||||
this.apis.put(apiInstanceMetaData.getName(), apiInstanceMetaData);
|
||||
return (this);
|
||||
}
|
||||
|
||||
}
|
@ -22,16 +22,14 @@
|
||||
package com.kingsrook.qqq.api.model.metadata.fields;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.api.ApiMiddlewareType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QMiddlewareFieldMetaData;
|
||||
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class ApiFieldMetaData extends QMiddlewareFieldMetaData
|
||||
public class ApiFieldMetaData
|
||||
{
|
||||
private String initialVersion;
|
||||
private String finalVersion;
|
||||
@ -44,35 +42,18 @@ public class ApiFieldMetaData extends QMiddlewareFieldMetaData
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public ApiFieldMetaData()
|
||||
public static String getEffectiveApiFieldName(String apiName, QFieldMetaData field)
|
||||
{
|
||||
setType("api");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public static ApiFieldMetaData of(QFieldMetaData field)
|
||||
{
|
||||
return ((ApiFieldMetaData) field.getMiddlewareMetaData(ApiMiddlewareType.NAME));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public static String getEffectiveApiFieldName(QFieldMetaData field)
|
||||
{
|
||||
ApiFieldMetaData apiFieldMetaData = ApiFieldMetaData.of(field);
|
||||
if(apiFieldMetaData != null && StringUtils.hasContent(apiFieldMetaData.apiFieldName))
|
||||
ApiFieldMetaDataContainer apiFieldMetaDataContainer = ApiFieldMetaDataContainer.of(field);
|
||||
if(apiFieldMetaDataContainer != null)
|
||||
{
|
||||
return (apiFieldMetaData.apiFieldName);
|
||||
ApiFieldMetaData apiFieldMetaData = apiFieldMetaDataContainer.getApiFieldMetaData(apiName);
|
||||
if(apiFieldMetaData != null && StringUtils.hasContent(apiFieldMetaData.apiFieldName))
|
||||
{
|
||||
return (apiFieldMetaData.apiFieldName);
|
||||
}
|
||||
}
|
||||
|
||||
return (field.getName());
|
||||
|
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* 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.model.metadata.fields;
|
||||
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.api.ApiMiddlewareType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QMiddlewareFieldMetaData;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class ApiFieldMetaDataContainer extends QMiddlewareFieldMetaData
|
||||
{
|
||||
private Map<String, ApiFieldMetaData> apis;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public ApiFieldMetaDataContainer()
|
||||
{
|
||||
setType("api");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public static ApiFieldMetaDataContainer of(QFieldMetaData field)
|
||||
{
|
||||
return ((ApiFieldMetaDataContainer) field.getMiddlewareMetaData(ApiMiddlewareType.NAME));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for apis
|
||||
*******************************************************************************/
|
||||
public Map<String, ApiFieldMetaData> getApis()
|
||||
{
|
||||
return (this.apis);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for apis
|
||||
*******************************************************************************/
|
||||
public ApiFieldMetaData getApiFieldMetaData(String apiName)
|
||||
{
|
||||
if(this.apis == null)
|
||||
{
|
||||
return (null);
|
||||
}
|
||||
|
||||
return (this.apis.get(apiName));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for apis
|
||||
*******************************************************************************/
|
||||
public void setApis(Map<String, ApiFieldMetaData> apis)
|
||||
{
|
||||
this.apis = apis;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for apis
|
||||
*******************************************************************************/
|
||||
public ApiFieldMetaDataContainer withApis(Map<String, ApiFieldMetaData> apis)
|
||||
{
|
||||
this.apis = apis;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for apis
|
||||
*******************************************************************************/
|
||||
public ApiFieldMetaDataContainer withApiFieldMetaData(String apiName, ApiFieldMetaData apiFieldMetaData)
|
||||
{
|
||||
if(this.apis == null)
|
||||
{
|
||||
this.apis = new LinkedHashMap<>();
|
||||
}
|
||||
this.apis.put(apiName, apiFieldMetaData);
|
||||
return (this);
|
||||
}
|
||||
|
||||
}
|
@ -27,8 +27,8 @@ import java.util.List;
|
||||
import com.kingsrook.qqq.api.ApiMiddlewareType;
|
||||
import com.kingsrook.qqq.api.model.APIVersionRange;
|
||||
import com.kingsrook.qqq.api.model.metadata.fields.ApiFieldMetaData;
|
||||
import com.kingsrook.qqq.api.model.metadata.fields.ApiFieldMetaDataContainer;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QMiddlewareTableMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||
|
||||
@ -36,7 +36,7 @@ import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class ApiTableMetaData extends QMiddlewareTableMetaData
|
||||
public class ApiTableMetaData
|
||||
{
|
||||
private String initialVersion;
|
||||
private String finalVersion;
|
||||
@ -48,16 +48,6 @@ public class ApiTableMetaData extends QMiddlewareTableMetaData
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public static ApiTableMetaData of(QTableMetaData table)
|
||||
{
|
||||
return ((ApiTableMetaData) table.getMiddlewareMetaData(ApiMiddlewareType.NAME));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@ -78,16 +68,13 @@ public class ApiTableMetaData extends QMiddlewareTableMetaData
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public void enrich(QTableMetaData table)
|
||||
public void enrich(String apiName, QTableMetaData table)
|
||||
{
|
||||
super.enrich(table);
|
||||
|
||||
if(initialVersion != null)
|
||||
{
|
||||
for(QFieldMetaData field : table.getFields().values())
|
||||
{
|
||||
ApiFieldMetaData apiFieldMetaData = ensureFieldHasApiMiddlewareMetaData(field);
|
||||
ApiFieldMetaData apiFieldMetaData = ensureFieldHasApiMiddlewareMetaData(apiName, field);
|
||||
if(apiFieldMetaData.getInitialVersion() == null)
|
||||
{
|
||||
apiFieldMetaData.setInitialVersion(initialVersion);
|
||||
@ -96,7 +83,7 @@ public class ApiTableMetaData extends QMiddlewareTableMetaData
|
||||
|
||||
for(QFieldMetaData field : CollectionUtils.nonNullList(removedApiFields))
|
||||
{
|
||||
ApiFieldMetaData apiFieldMetaData = ensureFieldHasApiMiddlewareMetaData(field);
|
||||
ApiFieldMetaData apiFieldMetaData = ensureFieldHasApiMiddlewareMetaData(apiName, field);
|
||||
if(apiFieldMetaData.getInitialVersion() == null)
|
||||
{
|
||||
apiFieldMetaData.setInitialVersion(initialVersion);
|
||||
@ -110,25 +97,20 @@ public class ApiTableMetaData extends QMiddlewareTableMetaData
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private static ApiFieldMetaData ensureFieldHasApiMiddlewareMetaData(QFieldMetaData field)
|
||||
private static ApiFieldMetaData ensureFieldHasApiMiddlewareMetaData(String apiName, QFieldMetaData field)
|
||||
{
|
||||
if(field.getMiddlewareMetaData(ApiMiddlewareType.NAME) == null)
|
||||
{
|
||||
field.withMiddlewareMetaData(new ApiFieldMetaData());
|
||||
field.withMiddlewareMetaData(new ApiFieldMetaDataContainer());
|
||||
}
|
||||
|
||||
return (ApiFieldMetaData.of(field));
|
||||
}
|
||||
ApiFieldMetaDataContainer apiFieldMetaDataContainer = ApiFieldMetaDataContainer.of(field);
|
||||
if(apiFieldMetaDataContainer.getApiFieldMetaData(apiName) == null)
|
||||
{
|
||||
apiFieldMetaDataContainer.withApiFieldMetaData(apiName, new ApiFieldMetaData());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public ApiTableMetaData()
|
||||
{
|
||||
setType("api");
|
||||
return (apiFieldMetaDataContainer.getApiFieldMetaData(apiName));
|
||||
}
|
||||
|
||||
|
||||
|
@ -0,0 +1,138 @@
|
||||
/*
|
||||
* 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.model.metadata.tables;
|
||||
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.api.ApiMiddlewareType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QMiddlewareTableMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class ApiTableMetaDataContainer extends QMiddlewareTableMetaData
|
||||
{
|
||||
private Map<String, ApiTableMetaData> apis;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public ApiTableMetaDataContainer()
|
||||
{
|
||||
setType("api");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public static ApiTableMetaDataContainer of(QTableMetaData table)
|
||||
{
|
||||
return ((ApiTableMetaDataContainer) table.getMiddlewareMetaData(ApiMiddlewareType.NAME));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public void enrich(QTableMetaData table)
|
||||
{
|
||||
super.enrich(table);
|
||||
|
||||
for(Map.Entry<String, ApiTableMetaData> entry : CollectionUtils.nonNullMap(apis).entrySet())
|
||||
{
|
||||
entry.getValue().enrich(entry.getKey(), table);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for apis
|
||||
*******************************************************************************/
|
||||
public Map<String, ApiTableMetaData> getApis()
|
||||
{
|
||||
return (this.apis);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for apis
|
||||
*******************************************************************************/
|
||||
public ApiTableMetaData getApiTableMetaData(String apiName)
|
||||
{
|
||||
if(this.apis == null)
|
||||
{
|
||||
return (null);
|
||||
}
|
||||
|
||||
return (this.apis.get(apiName));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for apis
|
||||
*******************************************************************************/
|
||||
public void setApis(Map<String, ApiTableMetaData> apis)
|
||||
{
|
||||
this.apis = apis;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for apis
|
||||
*******************************************************************************/
|
||||
public ApiTableMetaDataContainer withApis(Map<String, ApiTableMetaData> apis)
|
||||
{
|
||||
this.apis = apis;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for apis
|
||||
*******************************************************************************/
|
||||
public ApiTableMetaDataContainer withApiTableMetaData(String apiName, ApiTableMetaData apiTableMetaData)
|
||||
{
|
||||
if(this.apis == null)
|
||||
{
|
||||
this.apis = new LinkedHashMap<>();
|
||||
}
|
||||
this.apis.put(apiName, apiTableMetaData);
|
||||
return (this);
|
||||
}
|
||||
|
||||
}
|
@ -25,8 +25,11 @@ package com.kingsrook.qqq.api;
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.api.model.APIVersion;
|
||||
import com.kingsrook.qqq.api.model.metadata.ApiInstanceMetaData;
|
||||
import com.kingsrook.qqq.api.model.metadata.ApiInstanceMetaDataContainer;
|
||||
import com.kingsrook.qqq.api.model.metadata.fields.ApiFieldMetaData;
|
||||
import com.kingsrook.qqq.api.model.metadata.fields.ApiFieldMetaDataContainer;
|
||||
import com.kingsrook.qqq.api.model.metadata.tables.ApiTableMetaData;
|
||||
import com.kingsrook.qqq.api.model.metadata.tables.ApiTableMetaDataContainer;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterOrderBy;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QAuthenticationType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData;
|
||||
@ -57,6 +60,9 @@ public class TestUtils
|
||||
public static final String TABLE_NAME_LINE_ITEM_EXTRINSIC = "orderLineExtrinsic";
|
||||
public static final String TABLE_NAME_ORDER_EXTRINSIC = "orderExtrinsic";
|
||||
|
||||
public static final String API_NAME = "test-api";
|
||||
public static final String ALTERNATIVE_API_NAME = "person-api";
|
||||
|
||||
public static final String V2022_Q4 = "2022.Q4";
|
||||
public static final String V2023_Q1 = "2023.Q1";
|
||||
public static final String V2023_Q2 = "2023.Q2";
|
||||
@ -85,14 +91,27 @@ public class TestUtils
|
||||
|
||||
qInstance.setAuthentication(new Auth0AuthenticationMetaData().withType(QAuthenticationType.FULLY_ANONYMOUS).withName("anonymous"));
|
||||
|
||||
qInstance.withMiddlewareMetaData(new ApiInstanceMetaData()
|
||||
.withName("TestAPI")
|
||||
.withDescription("QQQ Test API")
|
||||
.withContactEmail("contact@kingsrook.com")
|
||||
.withCurrentVersion(new APIVersion(CURRENT_API_VERSION))
|
||||
.withSupportedVersions(List.of(new APIVersion(V2022_Q4), new APIVersion(V2023_Q1)))
|
||||
.withPastVersions(List.of(new APIVersion(V2022_Q4)))
|
||||
.withFutureVersions(List.of(new APIVersion(V2023_Q2)))
|
||||
qInstance.withMiddlewareMetaData(new ApiInstanceMetaDataContainer()
|
||||
.withApiInstanceMetaData(new ApiInstanceMetaData()
|
||||
.withName(API_NAME)
|
||||
.withPath("/api/")
|
||||
.withLabel("Test API")
|
||||
.withDescription("QQQ Test API")
|
||||
.withContactEmail("contact@kingsrook.com")
|
||||
.withCurrentVersion(new APIVersion(CURRENT_API_VERSION))
|
||||
.withSupportedVersions(List.of(new APIVersion(V2022_Q4), new APIVersion(V2023_Q1)))
|
||||
.withPastVersions(List.of(new APIVersion(V2022_Q4)))
|
||||
.withFutureVersions(List.of(new APIVersion(V2023_Q2))))
|
||||
.withApiInstanceMetaData(new ApiInstanceMetaData()
|
||||
.withName(ALTERNATIVE_API_NAME)
|
||||
.withPath("/person-api/")
|
||||
.withLabel("Person-Only API")
|
||||
.withDescription("QQQ Test API, that only has the Person table.")
|
||||
.withContactEmail("contact@kingsrook.com")
|
||||
.withCurrentVersion(new APIVersion(CURRENT_API_VERSION))
|
||||
.withSupportedVersions(List.of(new APIVersion(V2022_Q4), new APIVersion(V2023_Q1)))
|
||||
.withPastVersions(List.of(new APIVersion(V2022_Q4)))
|
||||
.withFutureVersions(List.of(new APIVersion(V2023_Q2))))
|
||||
);
|
||||
|
||||
return (qInstance);
|
||||
@ -117,20 +136,10 @@ public class TestUtils
|
||||
*******************************************************************************/
|
||||
public static QTableMetaData defineTablePerson()
|
||||
{
|
||||
return new QTableMetaData()
|
||||
QTableMetaData table = new QTableMetaData()
|
||||
.withName(TABLE_NAME_PERSON)
|
||||
.withLabel("Person")
|
||||
.withBackendName(MEMORY_BACKEND_NAME)
|
||||
.withMiddlewareMetaData(new ApiTableMetaData()
|
||||
.withInitialVersion(V2022_Q4)
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// in 2022.Q4, this table had a "shoeCount" field. but for the 2023.Q1 version, we renamed it to noOfShoes! //
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
.withRemovedApiField(new QFieldMetaData("shoeCount", QFieldType.INTEGER).withDisplayFormat(DisplayFormat.COMMAS)
|
||||
.withMiddlewareMetaData(new ApiFieldMetaData().withFinalVersion(V2022_Q4).withReplacedByFieldName("noOfShoes")))
|
||||
|
||||
)
|
||||
.withPrimaryKeyField("id")
|
||||
.withUniqueKey(new UniqueKey("email"))
|
||||
.withField(new QFieldMetaData("id", QFieldType.INTEGER).withIsEditable(false))
|
||||
@ -138,24 +147,48 @@ public class TestUtils
|
||||
.withField(new QFieldMetaData("modifyDate", QFieldType.DATE_TIME).withIsEditable(false))
|
||||
.withField(new QFieldMetaData("firstName", QFieldType.STRING))
|
||||
.withField(new QFieldMetaData("lastName", QFieldType.STRING))
|
||||
.withField(new QFieldMetaData("birthDate", QFieldType.DATE)
|
||||
.withMiddlewareMetaData(new ApiFieldMetaData().withApiFieldName("birthDay"))
|
||||
)
|
||||
.withField(new QFieldMetaData("birthDate", QFieldType.DATE))
|
||||
.withField(new QFieldMetaData("email", QFieldType.STRING))
|
||||
// .withField(new QFieldMetaData("homeStateId", QFieldType.INTEGER).withPossibleValueSourceName(POSSIBLE_VALUE_SOURCE_STATE))
|
||||
// .withField(new QFieldMetaData("favoriteShapeId", QFieldType.INTEGER).withPossibleValueSourceName(POSSIBLE_VALUE_SOURCE_SHAPE))
|
||||
// .withField(new QFieldMetaData("customValue", QFieldType.INTEGER).withPossibleValueSourceName(POSSIBLE_VALUE_SOURCE_CUSTOM))
|
||||
.withField(new QFieldMetaData("noOfShoes", QFieldType.INTEGER).withDisplayFormat(DisplayFormat.COMMAS)
|
||||
.withMiddlewareMetaData(new ApiFieldMetaData().withInitialVersion(V2023_Q1)))
|
||||
.withField(new QFieldMetaData("noOfShoes", QFieldType.INTEGER).withDisplayFormat(DisplayFormat.COMMAS))
|
||||
.withField(new QFieldMetaData("cost", QFieldType.DECIMAL).withDisplayFormat(DisplayFormat.CURRENCY))
|
||||
.withField(new QFieldMetaData("price", QFieldType.DECIMAL).withDisplayFormat(DisplayFormat.CURRENCY));
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// 2 new fields - they'll appear in future versions of the API //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
.withField(new QFieldMetaData("cost", QFieldType.DECIMAL).withDisplayFormat(DisplayFormat.CURRENCY)
|
||||
.withMiddlewareMetaData(new ApiFieldMetaData().withInitialVersion(V2023_Q2)))
|
||||
.withField(new QFieldMetaData("price", QFieldType.DECIMAL).withDisplayFormat(DisplayFormat.CURRENCY)
|
||||
.withMiddlewareMetaData(new ApiFieldMetaData().withIsExcluded(true)))
|
||||
;
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// make some changes to this table in the "main" api (but leave it like the backend in the ALTERNATIVE_API_NAME) //
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
table.withMiddlewareMetaData(new ApiTableMetaDataContainer()
|
||||
.withApiTableMetaData(API_NAME, new ApiTableMetaData()
|
||||
.withInitialVersion(V2022_Q4)
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// in 2022.Q4, this table had a "shoeCount" field. but for the 2023.Q1 version, we renamed it to noOfShoes! //
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
.withRemovedApiField(new QFieldMetaData("shoeCount", QFieldType.INTEGER).withDisplayFormat(DisplayFormat.COMMAS)
|
||||
.withMiddlewareMetaData(new ApiFieldMetaDataContainer().withApiFieldMetaData(API_NAME,
|
||||
new ApiFieldMetaData().withFinalVersion(V2022_Q4).withReplacedByFieldName("noOfShoes"))))
|
||||
)
|
||||
.withApiTableMetaData(ALTERNATIVE_API_NAME, new ApiTableMetaData().withInitialVersion(V2022_Q4)));
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
// change the name for this field for the main api //
|
||||
/////////////////////////////////////////////////////
|
||||
table.getField("birthDate").withMiddlewareMetaData(new ApiFieldMetaDataContainer().withApiFieldMetaData(API_NAME, new ApiFieldMetaData().withApiFieldName("birthDay")));
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// See above - we renamed this field (in the backend) for the 2023_Q1 version //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
table.getField("noOfShoes").withMiddlewareMetaData(new ApiFieldMetaDataContainer().withApiFieldMetaData(API_NAME, new ApiFieldMetaData().withInitialVersion(V2023_Q1)));
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// 2 new fields - one will appear in a future version of the API, the other is always excluded //
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
table.getField("cost").withMiddlewareMetaData(new ApiFieldMetaDataContainer().withApiFieldMetaData(API_NAME, new ApiFieldMetaData().withInitialVersion(V2023_Q2)));
|
||||
table.getField("price").withMiddlewareMetaData(new ApiFieldMetaDataContainer().withApiFieldMetaData(API_NAME, new ApiFieldMetaData().withIsExcluded(true)));
|
||||
|
||||
return (table);
|
||||
}
|
||||
|
||||
|
||||
@ -168,7 +201,7 @@ public class TestUtils
|
||||
return new QTableMetaData()
|
||||
.withName(TABLE_NAME_ORDER)
|
||||
.withBackendName(MEMORY_BACKEND_NAME)
|
||||
.withMiddlewareMetaData(new ApiTableMetaData().withInitialVersion(V2022_Q4))
|
||||
.withMiddlewareMetaData(new ApiTableMetaDataContainer().withApiTableMetaData(TestUtils.API_NAME, new ApiTableMetaData().withInitialVersion(V2022_Q4)))
|
||||
.withPrimaryKeyField("id")
|
||||
.withAssociation(new Association().withName("orderLines").withAssociatedTableName(TABLE_NAME_LINE_ITEM).withJoinName("orderLineItem"))
|
||||
.withAssociation(new Association().withName("extrinsics").withAssociatedTableName(TABLE_NAME_ORDER_EXTRINSIC).withJoinName("orderOrderExtrinsic"))
|
||||
@ -191,7 +224,7 @@ public class TestUtils
|
||||
return new QTableMetaData()
|
||||
.withName(TABLE_NAME_LINE_ITEM)
|
||||
.withBackendName(MEMORY_BACKEND_NAME)
|
||||
.withMiddlewareMetaData(new ApiTableMetaData().withInitialVersion(V2022_Q4))
|
||||
.withMiddlewareMetaData(new ApiTableMetaDataContainer().withApiTableMetaData(TestUtils.API_NAME, new ApiTableMetaData().withInitialVersion(V2022_Q4)))
|
||||
.withPrimaryKeyField("id")
|
||||
.withAssociation(new Association().withName("extrinsics").withAssociatedTableName(TABLE_NAME_LINE_ITEM_EXTRINSIC).withJoinName("lineItemLineItemExtrinsic"))
|
||||
.withField(new QFieldMetaData("id", QFieldType.INTEGER).withIsEditable(false))
|
||||
@ -213,7 +246,7 @@ public class TestUtils
|
||||
return new QTableMetaData()
|
||||
.withName(TABLE_NAME_LINE_ITEM_EXTRINSIC)
|
||||
.withBackendName(MEMORY_BACKEND_NAME)
|
||||
.withMiddlewareMetaData(new ApiTableMetaData().withInitialVersion(V2022_Q4))
|
||||
.withMiddlewareMetaData(new ApiTableMetaDataContainer().withApiTableMetaData(TestUtils.API_NAME, new ApiTableMetaData().withInitialVersion(V2022_Q4)))
|
||||
.withPrimaryKeyField("id")
|
||||
.withField(new QFieldMetaData("id", QFieldType.INTEGER).withIsEditable(false))
|
||||
.withField(new QFieldMetaData("createDate", QFieldType.DATE_TIME).withIsEditable(false))
|
||||
@ -233,7 +266,7 @@ public class TestUtils
|
||||
return new QTableMetaData()
|
||||
.withName(TABLE_NAME_ORDER_EXTRINSIC)
|
||||
.withBackendName(MEMORY_BACKEND_NAME)
|
||||
.withMiddlewareMetaData(new ApiTableMetaData().withInitialVersion(V2022_Q4))
|
||||
.withMiddlewareMetaData(new ApiTableMetaDataContainer().withApiTableMetaData(TestUtils.API_NAME, new ApiTableMetaData().withInitialVersion(V2022_Q4)))
|
||||
.withPrimaryKeyField("id")
|
||||
.withField(new QFieldMetaData("id", QFieldType.INTEGER).withIsEditable(false))
|
||||
.withField(new QFieldMetaData("createDate", QFieldType.DATE_TIME).withIsEditable(false))
|
||||
|
@ -28,6 +28,7 @@ import com.kingsrook.qqq.api.TestUtils;
|
||||
import com.kingsrook.qqq.api.model.actions.GenerateOpenApiSpecInput;
|
||||
import com.kingsrook.qqq.api.model.actions.GenerateOpenApiSpecOutput;
|
||||
import com.kingsrook.qqq.api.model.metadata.tables.ApiTableMetaData;
|
||||
import com.kingsrook.qqq.api.model.metadata.tables.ApiTableMetaDataContainer;
|
||||
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
@ -52,7 +53,7 @@ class GenerateOpenApiSpecActionTest extends BaseTest
|
||||
@Test
|
||||
void test() throws QException
|
||||
{
|
||||
GenerateOpenApiSpecOutput output = new GenerateOpenApiSpecAction().execute(new GenerateOpenApiSpecInput().withVersion(TestUtils.CURRENT_API_VERSION));
|
||||
GenerateOpenApiSpecOutput output = new GenerateOpenApiSpecAction().execute(new GenerateOpenApiSpecInput().withVersion(TestUtils.CURRENT_API_VERSION).withApiName(TestUtils.API_NAME));
|
||||
System.out.println(output.getYaml());
|
||||
}
|
||||
|
||||
@ -71,8 +72,8 @@ class GenerateOpenApiSpecActionTest extends BaseTest
|
||||
.withBackendName(TestUtils.MEMORY_BACKEND_NAME)
|
||||
.withPrimaryKeyField("id")
|
||||
.withField(new QFieldMetaData("id", QFieldType.INTEGER))
|
||||
.withMiddlewareMetaData(new ApiTableMetaData()
|
||||
.withInitialVersion(TestUtils.V2022_Q4)));
|
||||
.withMiddlewareMetaData(new ApiTableMetaDataContainer().withApiTableMetaData(TestUtils.API_NAME, new ApiTableMetaData()
|
||||
.withInitialVersion(TestUtils.V2022_Q4))));
|
||||
|
||||
qInstance.addTable(new QTableMetaData()
|
||||
.withName("hiddenTable")
|
||||
@ -80,16 +81,16 @@ class GenerateOpenApiSpecActionTest extends BaseTest
|
||||
.withPrimaryKeyField("id")
|
||||
.withField(new QFieldMetaData("id", QFieldType.INTEGER))
|
||||
.withIsHidden(true)
|
||||
.withMiddlewareMetaData(new ApiTableMetaData()
|
||||
.withInitialVersion(TestUtils.V2022_Q4)));
|
||||
.withMiddlewareMetaData(new ApiTableMetaDataContainer().withApiTableMetaData(TestUtils.API_NAME, new ApiTableMetaData()
|
||||
.withInitialVersion(TestUtils.V2022_Q4))));
|
||||
|
||||
qInstance.addTable(new QTableMetaData()
|
||||
.withName("excludedTable")
|
||||
.withBackendName(TestUtils.MEMORY_BACKEND_NAME)
|
||||
.withPrimaryKeyField("id")
|
||||
.withField(new QFieldMetaData("id", QFieldType.INTEGER))
|
||||
.withMiddlewareMetaData(new ApiTableMetaData()
|
||||
.withIsExcluded(true)));
|
||||
.withMiddlewareMetaData(new ApiTableMetaDataContainer().withApiTableMetaData(TestUtils.API_NAME, new ApiTableMetaData()
|
||||
.withIsExcluded(true))));
|
||||
|
||||
qInstance.addTable(new QTableMetaData()
|
||||
.withName("tableWithoutApiMetaData")
|
||||
@ -102,17 +103,17 @@ class GenerateOpenApiSpecActionTest extends BaseTest
|
||||
.withBackendName(TestUtils.MEMORY_BACKEND_NAME)
|
||||
.withPrimaryKeyField("id")
|
||||
.withField(new QFieldMetaData("id", QFieldType.INTEGER))
|
||||
.withMiddlewareMetaData(new ApiTableMetaData()
|
||||
.withInitialVersion(TestUtils.V2023_Q2)));
|
||||
.withMiddlewareMetaData(new ApiTableMetaDataContainer().withApiTableMetaData(TestUtils.API_NAME, new ApiTableMetaData()
|
||||
.withInitialVersion(TestUtils.V2023_Q2))));
|
||||
|
||||
qInstance.addTable(new QTableMetaData()
|
||||
.withName("tableWithOnlyPastVersions")
|
||||
.withBackendName(TestUtils.MEMORY_BACKEND_NAME)
|
||||
.withPrimaryKeyField("id")
|
||||
.withField(new QFieldMetaData("id", QFieldType.INTEGER))
|
||||
.withMiddlewareMetaData(new ApiTableMetaData()
|
||||
.withMiddlewareMetaData(new ApiTableMetaDataContainer().withApiTableMetaData(TestUtils.API_NAME, new ApiTableMetaData()
|
||||
.withInitialVersion(TestUtils.V2022_Q4)
|
||||
.withFinalVersion(TestUtils.V2022_Q4)));
|
||||
.withFinalVersion(TestUtils.V2022_Q4))));
|
||||
|
||||
qInstance.addTable(new QTableMetaData()
|
||||
.withName("tableWithNoSupportedCapabilities")
|
||||
@ -120,10 +121,10 @@ class GenerateOpenApiSpecActionTest extends BaseTest
|
||||
.withPrimaryKeyField("id")
|
||||
.withField(new QFieldMetaData("id", QFieldType.INTEGER))
|
||||
.withoutCapabilities(Capability.TABLE_QUERY, Capability.TABLE_GET, Capability.TABLE_INSERT, Capability.TABLE_UPDATE, Capability.TABLE_DELETE)
|
||||
.withMiddlewareMetaData(new ApiTableMetaData()
|
||||
.withInitialVersion(TestUtils.V2022_Q4)));
|
||||
.withMiddlewareMetaData(new ApiTableMetaDataContainer().withApiTableMetaData(TestUtils.API_NAME, new ApiTableMetaData()
|
||||
.withInitialVersion(TestUtils.V2022_Q4))));
|
||||
|
||||
GenerateOpenApiSpecOutput output = new GenerateOpenApiSpecAction().execute(new GenerateOpenApiSpecInput().withVersion(TestUtils.CURRENT_API_VERSION));
|
||||
GenerateOpenApiSpecOutput output = new GenerateOpenApiSpecAction().execute(new GenerateOpenApiSpecInput().withVersion(TestUtils.CURRENT_API_VERSION).withApiName(TestUtils.API_NAME));
|
||||
Set<String> apiPaths = output.getOpenAPI().getPaths().keySet();
|
||||
assertTrue(apiPaths.stream().anyMatch(s -> s.contains("/supportedTable/")));
|
||||
assertTrue(apiPaths.stream().noneMatch(s -> s.contains("/hiddenTable/")));
|
||||
@ -149,11 +150,11 @@ class GenerateOpenApiSpecActionTest extends BaseTest
|
||||
.withBackendName(TestUtils.MEMORY_BACKEND_NAME)
|
||||
.withPrimaryKeyField("id")
|
||||
.withField(new QFieldMetaData("id", QFieldType.INTEGER))
|
||||
.withMiddlewareMetaData(new ApiTableMetaData()
|
||||
.withMiddlewareMetaData(new ApiTableMetaDataContainer().withApiTableMetaData(TestUtils.API_NAME, new ApiTableMetaData()
|
||||
.withApiTableName("externalName")
|
||||
.withInitialVersion(TestUtils.V2022_Q4)));
|
||||
.withInitialVersion(TestUtils.V2022_Q4))));
|
||||
|
||||
GenerateOpenApiSpecOutput output = new GenerateOpenApiSpecAction().execute(new GenerateOpenApiSpecInput().withVersion(TestUtils.CURRENT_API_VERSION));
|
||||
GenerateOpenApiSpecOutput output = new GenerateOpenApiSpecAction().execute(new GenerateOpenApiSpecInput().withVersion(TestUtils.CURRENT_API_VERSION).withApiName(TestUtils.API_NAME));
|
||||
Set<String> apiPaths = output.getOpenAPI().getPaths().keySet();
|
||||
assertTrue(apiPaths.stream().anyMatch(s -> s.contains("/externalName/")));
|
||||
assertTrue(apiPaths.stream().noneMatch(s -> s.contains("/internalName/")));
|
||||
@ -167,9 +168,31 @@ class GenerateOpenApiSpecActionTest extends BaseTest
|
||||
@Test
|
||||
void testBadVersion()
|
||||
{
|
||||
assertThatThrownBy(() -> new GenerateOpenApiSpecAction().execute(new GenerateOpenApiSpecInput().withVersion("NotAVersion")))
|
||||
assertThatThrownBy(() -> new GenerateOpenApiSpecAction().execute(new GenerateOpenApiSpecInput().withApiName(TestUtils.API_NAME)))
|
||||
.isInstanceOf(QException.class)
|
||||
.hasMessageContaining("Missing required input: version");
|
||||
|
||||
assertThatThrownBy(() -> new GenerateOpenApiSpecAction().execute(new GenerateOpenApiSpecInput().withVersion("NotAVersion").withApiName(TestUtils.API_NAME)))
|
||||
.isInstanceOf(QException.class)
|
||||
.hasMessageContaining("not a supported API Version");
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testBadApiName()
|
||||
{
|
||||
assertThatThrownBy(() -> new GenerateOpenApiSpecAction().execute(new GenerateOpenApiSpecInput().withApiName("Not an api")))
|
||||
.isInstanceOf(QException.class)
|
||||
.hasMessageContaining("Could not find apiInstanceMetaData named");
|
||||
|
||||
assertThatThrownBy(() -> new GenerateOpenApiSpecAction().execute(new GenerateOpenApiSpecInput().withVersion(TestUtils.CURRENT_API_VERSION)))
|
||||
.isInstanceOf(QException.class)
|
||||
.hasMessageContaining("Missing required input: apiName");
|
||||
}
|
||||
|
||||
}
|
@ -27,9 +27,12 @@ import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import com.kingsrook.qqq.api.BaseTest;
|
||||
import com.kingsrook.qqq.api.TestUtils;
|
||||
import com.kingsrook.qqq.api.model.actions.GetTableApiFieldsInput;
|
||||
import com.kingsrook.qqq.api.model.metadata.fields.ApiFieldMetaData;
|
||||
import com.kingsrook.qqq.api.model.metadata.fields.ApiFieldMetaDataContainer;
|
||||
import com.kingsrook.qqq.api.model.metadata.tables.ApiTableMetaData;
|
||||
import com.kingsrook.qqq.api.model.metadata.tables.ApiTableMetaDataContainer;
|
||||
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.instances.QInstanceEnricher;
|
||||
@ -57,7 +60,7 @@ class GetTableApiFieldsActionTest extends BaseTest
|
||||
*******************************************************************************/
|
||||
private List<? extends QFieldMetaData> getFields(String tableName, String version) throws QException
|
||||
{
|
||||
return new GetTableApiFieldsAction().execute(new GetTableApiFieldsInput().withTableName(tableName).withVersion(version)).getFields();
|
||||
return new GetTableApiFieldsAction().execute(new GetTableApiFieldsInput().withApiName(TestUtils.API_NAME).withTableName(tableName).withVersion(version)).getFields();
|
||||
}
|
||||
|
||||
|
||||
@ -71,11 +74,11 @@ class GetTableApiFieldsActionTest extends BaseTest
|
||||
QInstance qInstance = QContext.getQInstance();
|
||||
qInstance.addTable(new QTableMetaData()
|
||||
.withName(TABLE_NAME)
|
||||
.withMiddlewareMetaData(new ApiTableMetaData().withInitialVersion("1"))
|
||||
.withMiddlewareMetaData(new ApiTableMetaDataContainer().withApiTableMetaData(TestUtils.API_NAME, new ApiTableMetaData().withInitialVersion("1")))
|
||||
.withField(new QFieldMetaData("a", STRING)) // inherit versionRange from the table
|
||||
.withField(new QFieldMetaData("b", STRING).withMiddlewareMetaData(new ApiFieldMetaData().withInitialVersion("1")))
|
||||
.withField(new QFieldMetaData("c", STRING).withMiddlewareMetaData(new ApiFieldMetaData().withInitialVersion("2")))
|
||||
.withField(new QFieldMetaData("d", STRING).withMiddlewareMetaData(new ApiFieldMetaData().withInitialVersion("3")))
|
||||
.withField(new QFieldMetaData("b", STRING).withMiddlewareMetaData(new ApiFieldMetaDataContainer().withApiFieldMetaData(TestUtils.API_NAME, new ApiFieldMetaData().withInitialVersion("1"))))
|
||||
.withField(new QFieldMetaData("c", STRING).withMiddlewareMetaData(new ApiFieldMetaDataContainer().withApiFieldMetaData(TestUtils.API_NAME, new ApiFieldMetaData().withInitialVersion("2"))))
|
||||
.withField(new QFieldMetaData("d", STRING).withMiddlewareMetaData(new ApiFieldMetaDataContainer().withApiFieldMetaData(TestUtils.API_NAME, new ApiFieldMetaData().withInitialVersion("3"))))
|
||||
);
|
||||
new QInstanceEnricher(qInstance).enrich();
|
||||
|
||||
@ -95,13 +98,13 @@ class GetTableApiFieldsActionTest extends BaseTest
|
||||
QInstance qInstance = QContext.getQInstance();
|
||||
qInstance.addTable(new QTableMetaData()
|
||||
.withName(TABLE_NAME)
|
||||
.withMiddlewareMetaData(new ApiTableMetaData().withInitialVersion("1")
|
||||
.withRemovedApiField(new QFieldMetaData("c", STRING).withMiddlewareMetaData(new ApiFieldMetaData().withInitialVersion("1").withFinalVersion("2")))
|
||||
)
|
||||
.withMiddlewareMetaData(new ApiTableMetaDataContainer().withApiTableMetaData(TestUtils.API_NAME, new ApiTableMetaData().withInitialVersion("1")
|
||||
.withRemovedApiField(new QFieldMetaData("c", STRING).withMiddlewareMetaData(new ApiFieldMetaDataContainer().withApiFieldMetaData(TestUtils.API_NAME, new ApiFieldMetaData().withInitialVersion("1").withFinalVersion("2"))))
|
||||
))
|
||||
.withField(new QFieldMetaData("a", STRING)) // inherit versionRange from the table
|
||||
.withField(new QFieldMetaData("b", STRING).withMiddlewareMetaData(new ApiFieldMetaData().withInitialVersion("1")))
|
||||
.withField(new QFieldMetaData("b", STRING).withMiddlewareMetaData(new ApiFieldMetaDataContainer().withApiFieldMetaData(TestUtils.API_NAME, new ApiFieldMetaData().withInitialVersion("1"))))
|
||||
// we used to have "c" here... now it's in the removed list above!
|
||||
.withField(new QFieldMetaData("d", STRING).withMiddlewareMetaData(new ApiFieldMetaData().withInitialVersion("3")))
|
||||
.withField(new QFieldMetaData("d", STRING).withMiddlewareMetaData(new ApiFieldMetaDataContainer().withApiFieldMetaData(TestUtils.API_NAME, new ApiFieldMetaData().withInitialVersion("3"))))
|
||||
);
|
||||
new QInstanceEnricher(qInstance).enrich();
|
||||
|
||||
|
@ -33,6 +33,7 @@ import com.kingsrook.qqq.api.TestUtils;
|
||||
import com.kingsrook.qqq.api.javalin.QBadRequestException;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
import com.kingsrook.qqq.backend.core.utils.ValueUtils;
|
||||
import org.json.JSONObject;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
@ -62,17 +63,17 @@ class QRecordApiAdapterTest extends BaseTest
|
||||
.withValue("cost", new BigDecimal("3.50"))
|
||||
.withValue("price", new BigDecimal("9.99"));
|
||||
|
||||
Map<String, Serializable> pastApiRecord = QRecordApiAdapter.qRecordToApiMap(person, TestUtils.TABLE_NAME_PERSON, TestUtils.V2022_Q4);
|
||||
Map<String, Serializable> pastApiRecord = QRecordApiAdapter.qRecordToApiMap(person, TestUtils.TABLE_NAME_PERSON, TestUtils.API_NAME, TestUtils.V2022_Q4);
|
||||
assertEquals(2, pastApiRecord.get("shoeCount")); // old field name - not currently in the QTable, but we can still get its value!
|
||||
assertFalse(pastApiRecord.containsKey("noOfShoes")); // current field name - doesn't appear in old api-version
|
||||
assertFalse(pastApiRecord.containsKey("cost")); // a current field name, but also not in this old api version
|
||||
|
||||
Map<String, Serializable> currentApiRecord = QRecordApiAdapter.qRecordToApiMap(person, TestUtils.TABLE_NAME_PERSON, TestUtils.V2023_Q1);
|
||||
Map<String, Serializable> currentApiRecord = QRecordApiAdapter.qRecordToApiMap(person, TestUtils.TABLE_NAME_PERSON, TestUtils.API_NAME, TestUtils.V2023_Q1);
|
||||
assertFalse(currentApiRecord.containsKey("shoeCount")); // old field name - not in this current api version
|
||||
assertEquals(2, currentApiRecord.get("noOfShoes")); // current field name - value here as we expect
|
||||
assertFalse(currentApiRecord.containsKey("cost")); // future field name - not in the current api (we added the field during new dev, and didn't change the api)
|
||||
|
||||
Map<String, Serializable> futureApiRecord = QRecordApiAdapter.qRecordToApiMap(person, TestUtils.TABLE_NAME_PERSON, TestUtils.V2023_Q2);
|
||||
Map<String, Serializable> futureApiRecord = QRecordApiAdapter.qRecordToApiMap(person, TestUtils.TABLE_NAME_PERSON, TestUtils.API_NAME, TestUtils.V2023_Q2);
|
||||
assertFalse(futureApiRecord.containsKey("shoeCount")); // old field name - also not in this future api version
|
||||
assertEquals(2, futureApiRecord.get("noOfShoes")); // current field name - still here.
|
||||
assertEquals(new BigDecimal("3.50"), futureApiRecord.get("cost")); // future field name appears now that we've requested this future api version.
|
||||
@ -82,6 +83,18 @@ class QRecordApiAdapterTest extends BaseTest
|
||||
assertEquals(LocalDate.parse("1980-05-31"), apiRecord.get("birthDay")); // use the apiFieldName
|
||||
assertFalse(apiRecord.containsKey("price")); // excluded field never appears
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// confirm that for the alternative api, we get a record that looks just like the input record (per its api meta data) //
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
for(String version : List.of(TestUtils.V2022_Q4, TestUtils.V2023_Q1, TestUtils.V2023_Q2))
|
||||
{
|
||||
Map<String, Serializable> alternativeApiRecord = QRecordApiAdapter.qRecordToApiMap(person, TestUtils.TABLE_NAME_PERSON, TestUtils.ALTERNATIVE_API_NAME, version);
|
||||
for(String key : person.getValues().keySet())
|
||||
{
|
||||
assertEquals(person.getValueString(key), ValueUtils.getValueAsString(alternativeApiRecord.get(key)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -97,7 +110,7 @@ class QRecordApiAdapterTest extends BaseTest
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
QRecord recordFromOldApi = QRecordApiAdapter.apiJsonObjectToQRecord(new JSONObject("""
|
||||
{"firstName": "Tim", "shoeCount": 2}
|
||||
"""), TestUtils.TABLE_NAME_PERSON, TestUtils.V2022_Q4, true);
|
||||
"""), TestUtils.TABLE_NAME_PERSON, TestUtils.API_NAME, TestUtils.V2022_Q4, true);
|
||||
assertEquals(2, recordFromOldApi.getValueInteger("noOfShoes"));
|
||||
|
||||
///////////////////////////////////////////
|
||||
@ -105,7 +118,7 @@ class QRecordApiAdapterTest extends BaseTest
|
||||
///////////////////////////////////////////
|
||||
QRecord recordFromCurrentApi = QRecordApiAdapter.apiJsonObjectToQRecord(new JSONObject("""
|
||||
{"firstName": "Tim", "noOfShoes": 2}
|
||||
"""), TestUtils.TABLE_NAME_PERSON, TestUtils.V2023_Q1, true);
|
||||
"""), TestUtils.TABLE_NAME_PERSON, TestUtils.API_NAME, TestUtils.V2023_Q1, true);
|
||||
assertEquals(2, recordFromCurrentApi.getValueInteger("noOfShoes"));
|
||||
|
||||
/////////////////////////////////////////////
|
||||
@ -113,7 +126,7 @@ class QRecordApiAdapterTest extends BaseTest
|
||||
/////////////////////////////////////////////
|
||||
QRecord recordFromFutureApi = QRecordApiAdapter.apiJsonObjectToQRecord(new JSONObject("""
|
||||
{"firstName": "Tim", "noOfShoes": 2, "cost": 3.50}
|
||||
"""), TestUtils.TABLE_NAME_PERSON, TestUtils.V2023_Q2, true);
|
||||
"""), TestUtils.TABLE_NAME_PERSON, TestUtils.API_NAME, TestUtils.V2023_Q2, true);
|
||||
assertEquals(2, recordFromFutureApi.getValueInteger("noOfShoes"));
|
||||
assertEquals(new BigDecimal("3.50"), recordFromFutureApi.getValueBigDecimal("cost"));
|
||||
|
||||
@ -122,7 +135,7 @@ class QRecordApiAdapterTest extends BaseTest
|
||||
///////////////////////////////////////////////////////////////////
|
||||
QRecord recordWithApiFieldName = QRecordApiAdapter.apiJsonObjectToQRecord(new JSONObject("""
|
||||
{"firstName": "Tim", "birthDay": "1976-05-28"}
|
||||
"""), TestUtils.TABLE_NAME_PERSON, TestUtils.V2023_Q2, true);
|
||||
"""), TestUtils.TABLE_NAME_PERSON, TestUtils.API_NAME, TestUtils.V2023_Q2, true);
|
||||
assertEquals("1976-05-28", recordWithApiFieldName.getValueString("birthDate"));
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -130,7 +143,7 @@ class QRecordApiAdapterTest extends BaseTest
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
assertThatThrownBy(() -> QRecordApiAdapter.apiJsonObjectToQRecord(new JSONObject("""
|
||||
{"firstName": "Tim", "noOfShoes": 2}
|
||||
"""), TestUtils.TABLE_NAME_PERSON, TestUtils.V2022_Q4, true))
|
||||
"""), TestUtils.TABLE_NAME_PERSON, TestUtils.API_NAME, TestUtils.V2022_Q4, true))
|
||||
.isInstanceOf(QBadRequestException.class)
|
||||
.hasMessageContaining("unrecognized field name: noOfShoes");
|
||||
|
||||
@ -139,7 +152,7 @@ class QRecordApiAdapterTest extends BaseTest
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
assertThatThrownBy(() -> QRecordApiAdapter.apiJsonObjectToQRecord(new JSONObject("""
|
||||
{"firstName": "Tim", "cost": 2}
|
||||
"""), TestUtils.TABLE_NAME_PERSON, TestUtils.V2023_Q1, true))
|
||||
"""), TestUtils.TABLE_NAME_PERSON, TestUtils.API_NAME, TestUtils.V2023_Q1, true))
|
||||
.isInstanceOf(QBadRequestException.class)
|
||||
.hasMessageContaining("unrecognized field name: cost");
|
||||
|
||||
@ -150,7 +163,7 @@ class QRecordApiAdapterTest extends BaseTest
|
||||
{
|
||||
assertThatThrownBy(() -> QRecordApiAdapter.apiJsonObjectToQRecord(new JSONObject("""
|
||||
{"firstName": "Tim", "price": 2}
|
||||
"""), TestUtils.TABLE_NAME_PERSON, version, true))
|
||||
"""), TestUtils.TABLE_NAME_PERSON, TestUtils.API_NAME, version, true))
|
||||
.isInstanceOf(QBadRequestException.class)
|
||||
.hasMessageContaining("unrecognized field name: price");
|
||||
}
|
||||
@ -160,7 +173,7 @@ class QRecordApiAdapterTest extends BaseTest
|
||||
////////////////////////////////////////////
|
||||
QRecord recordWithoutNonEditableFields = QRecordApiAdapter.apiJsonObjectToQRecord(new JSONObject("""
|
||||
{"firstName": "Tim", "birthDay": "1976-05-28", "createDate": "2023-03-31T11:44:28Z", "id": 256}
|
||||
"""), TestUtils.TABLE_NAME_PERSON, TestUtils.V2023_Q1, false);
|
||||
"""), TestUtils.TABLE_NAME_PERSON, TestUtils.API_NAME, TestUtils.V2023_Q1, false);
|
||||
assertFalse(recordWithoutNonEditableFields.getValues().containsKey("createDate"));
|
||||
assertFalse(recordWithoutNonEditableFields.getValues().containsKey("id"));
|
||||
|
||||
@ -169,7 +182,7 @@ class QRecordApiAdapterTest extends BaseTest
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
QRecord recordWithoutNonEditablePrimaryKeyFields = QRecordApiAdapter.apiJsonObjectToQRecord(new JSONObject("""
|
||||
{"firstName": "Tim", "birthDay": "1976-05-28", "createDate": "2023-03-31T11:44:28Z", "id": 256}
|
||||
"""), TestUtils.TABLE_NAME_PERSON, TestUtils.V2023_Q1, true);
|
||||
"""), TestUtils.TABLE_NAME_PERSON, TestUtils.API_NAME, TestUtils.V2023_Q1, true);
|
||||
assertFalse(recordWithoutNonEditablePrimaryKeyFields.getValues().containsKey("createDate"));
|
||||
assertEquals(256, recordWithoutNonEditablePrimaryKeyFields.getValues().get("id"));
|
||||
|
||||
|
@ -22,11 +22,14 @@
|
||||
package com.kingsrook.qqq.api.javalin;
|
||||
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.Month;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.api.BaseTest;
|
||||
import com.kingsrook.qqq.api.TestUtils;
|
||||
import com.kingsrook.qqq.api.model.metadata.tables.ApiTableMetaData;
|
||||
import com.kingsrook.qqq.api.model.metadata.tables.ApiTableMetaDataContainer;
|
||||
import com.kingsrook.qqq.backend.core.actions.tables.GetAction;
|
||||
import com.kingsrook.qqq.backend.core.actions.tables.InsertAction;
|
||||
import com.kingsrook.qqq.backend.core.actions.tables.QueryAction;
|
||||
@ -49,6 +52,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
import com.kingsrook.qqq.backend.core.modules.authentication.implementations.FullyAnonymousAuthenticationModule;
|
||||
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||
import com.kingsrook.qqq.backend.javalin.QJavalinImplementation;
|
||||
import io.javalin.apibuilder.EndpointGroup;
|
||||
import kong.unirest.HttpResponse;
|
||||
import kong.unirest.Unirest;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
@ -91,13 +95,14 @@ class QJavalinApiHandlerTest extends BaseTest
|
||||
.withBackendName(TestUtils.MEMORY_BACKEND_NAME)
|
||||
.withPrimaryKeyField("id")
|
||||
.withField(new QFieldMetaData("id", QFieldType.INTEGER))
|
||||
.withMiddlewareMetaData(new ApiTableMetaData()
|
||||
.withMiddlewareMetaData(new ApiTableMetaDataContainer().withApiTableMetaData(TestUtils.API_NAME, new ApiTableMetaData()
|
||||
.withApiTableName("externalName")
|
||||
.withInitialVersion(TestUtils.V2022_Q4)));
|
||||
.withInitialVersion(TestUtils.V2022_Q4))));
|
||||
|
||||
qJavalinImplementation = new QJavalinImplementation(qInstance);
|
||||
qJavalinImplementation.startJavalinServer(PORT);
|
||||
qJavalinImplementation.getJavalinService().routes(new QJavalinApiHandler(qInstance).getRoutes());
|
||||
EndpointGroup routes = new QJavalinApiHandler(qInstance).getRoutes();
|
||||
qJavalinImplementation.getJavalinService().routes(routes);
|
||||
}
|
||||
|
||||
|
||||
@ -124,7 +129,7 @@ class QJavalinApiHandlerTest extends BaseTest
|
||||
System.out.println(response.getBody());
|
||||
assertThat(response.getBody())
|
||||
.contains("""
|
||||
title: "TestAPI"
|
||||
title: "Test API"
|
||||
""")
|
||||
.contains("""
|
||||
/person/query:
|
||||
@ -274,6 +279,77 @@ class QJavalinApiHandlerTest extends BaseTest
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testQuery200AlternativeApi()
|
||||
{
|
||||
HttpResponse<String> response = Unirest.get(BASE_URL + "/person-api/" + VERSION + "/person/query").asString();
|
||||
assertEquals(HttpStatus.OK_200, response.getStatus());
|
||||
JSONObject jsonObject = new JSONObject(response.getBody());
|
||||
assertEquals(0, jsonObject.getInt("count"));
|
||||
assertEquals(1, jsonObject.getInt("pageNo"));
|
||||
assertEquals(50, jsonObject.getInt("pageSize"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testTableOnlyInOneApi()
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// the person table (which most of our tests are against) is in both api's in this instance (/api/ and /person-api/). //
|
||||
// do a request here for the order table, which is only in /api //
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
HttpResponse<String> response = Unirest.get(BASE_URL + "/api/" + VERSION + "/order/query").asString();
|
||||
assertEquals(HttpStatus.OK_200, response.getStatus());
|
||||
JSONObject jsonObject = new JSONObject(response.getBody());
|
||||
assertEquals(0, jsonObject.getInt("count"));
|
||||
assertEquals(1, jsonObject.getInt("pageNo"));
|
||||
assertEquals(50, jsonObject.getInt("pageSize"));
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// now make sure we get a 404 for it under the /person-api/ api path //
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
response = Unirest.get(BASE_URL + "/person-api/" + VERSION + "/order/query").asString();
|
||||
assertEquals(HttpStatus.NOT_FOUND_404, response.getStatus());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testFieldDifferencesBetweenApis() throws QException
|
||||
{
|
||||
insertPersonRecord(1, "Homer", "Simpson", LocalDate.of(1970, Month.JANUARY, 1));
|
||||
|
||||
/////////////////////////////////////////////////////////////
|
||||
// on the main api, birthDate has been renamed to birthDay //
|
||||
/////////////////////////////////////////////////////////////
|
||||
HttpResponse<String> response = Unirest.get(BASE_URL + "/api/" + VERSION + "/person/1").asString();
|
||||
assertEquals(HttpStatus.OK_200, response.getStatus());
|
||||
JSONObject jsonObject = new JSONObject(response.getBody());
|
||||
assertEquals("1970-01-01", jsonObject.getString("birthDay"));
|
||||
assertFalse(jsonObject.has("birthDate"));
|
||||
|
||||
///////////////////////////////////////////
|
||||
// but it's birthDate on the /person-api //
|
||||
///////////////////////////////////////////
|
||||
response = Unirest.get(BASE_URL + "/person-api/" + VERSION + "/person/1").asString();
|
||||
assertEquals(HttpStatus.OK_200, response.getStatus());
|
||||
jsonObject = new JSONObject(response.getBody());
|
||||
assertEquals("1970-01-01", jsonObject.getString("birthDate"));
|
||||
assertFalse(jsonObject.has("birthDay"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@ -1168,10 +1244,20 @@ class QJavalinApiHandlerTest extends BaseTest
|
||||
**
|
||||
*******************************************************************************/
|
||||
private static void insertPersonRecord(Integer id, String firstName, String lastName) throws QException
|
||||
{
|
||||
insertPersonRecord(id, firstName, lastName, null);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private static void insertPersonRecord(Integer id, String firstName, String lastName, LocalDate birthDate) throws QException
|
||||
{
|
||||
InsertInput insertInput = new InsertInput();
|
||||
insertInput.setTableName(TestUtils.TABLE_NAME_PERSON);
|
||||
insertInput.setRecords(List.of(new QRecord().withValue("id", id).withValue("firstName", firstName).withValue("lastName", lastName)));
|
||||
insertInput.setRecords(List.of(new QRecord().withValue("id", id).withValue("firstName", firstName).withValue("lastName", lastName).withValue("birthDate", birthDate)));
|
||||
new InsertAction().execute(insertInput);
|
||||
}
|
||||
|
||||
|
@ -23,8 +23,10 @@ package com.kingsrook.qqq.api.model.metadata;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.api.TestUtils;
|
||||
import com.kingsrook.qqq.api.model.APIVersion;
|
||||
import com.kingsrook.qqq.api.model.metadata.tables.ApiTableMetaData;
|
||||
import com.kingsrook.qqq.api.model.metadata.tables.ApiTableMetaDataContainer;
|
||||
import com.kingsrook.qqq.backend.core.instances.QInstanceValidator;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
@ -46,15 +48,7 @@ class ApiInstanceMetaDataTest
|
||||
@Test
|
||||
void testValidationPasses()
|
||||
{
|
||||
assertValidationErrors(new ApiInstanceMetaData()
|
||||
.withName("QQQ API")
|
||||
.withDescription("Test API for QQQ")
|
||||
.withContactEmail("contact@kingsrook.com")
|
||||
.withCurrentVersion(new APIVersion("2023.Q1"))
|
||||
.withSupportedVersions(List.of(new APIVersion("2022.Q3"), new APIVersion("2022.Q4"), new APIVersion("2023.Q1")))
|
||||
.withPastVersions(List.of(new APIVersion("2022.Q2"), new APIVersion("2022.Q3"), new APIVersion("2022.Q4")))
|
||||
.withFutureVersions(List.of(new APIVersion("2023.Q2"))),
|
||||
List.of());
|
||||
assertValidationErrors(makeBaselineValidApiInstanceMetaDataWithVersions(), List.of());
|
||||
}
|
||||
|
||||
|
||||
@ -67,6 +61,8 @@ class ApiInstanceMetaDataTest
|
||||
{
|
||||
assertValidationErrors(new ApiInstanceMetaData(), List.of(
|
||||
"Missing name",
|
||||
"Missing label",
|
||||
"Missing path",
|
||||
"Missing description",
|
||||
"Missing contactEmail",
|
||||
"Missing currentVersion",
|
||||
@ -118,11 +114,11 @@ class ApiInstanceMetaDataTest
|
||||
|
||||
qInstance.addTable(new QTableMetaData()
|
||||
.withName("myValidTable")
|
||||
.withMiddlewareMetaData(new ApiTableMetaData().withInitialVersion("2023.Q1")));
|
||||
.withMiddlewareMetaData(new ApiTableMetaDataContainer().withApiTableMetaData(TestUtils.API_NAME, new ApiTableMetaData().withInitialVersion("2023.Q1"))));
|
||||
|
||||
qInstance.addTable(new QTableMetaData()
|
||||
.withName("myInvalidTable")
|
||||
.withMiddlewareMetaData(new ApiTableMetaData().withInitialVersion("2022.Q1")));
|
||||
.withMiddlewareMetaData(new ApiTableMetaDataContainer().withApiTableMetaData(TestUtils.API_NAME, new ApiTableMetaData().withInitialVersion("notAVersion"))));
|
||||
|
||||
assertValidationErrors(qInstance, makeBaselineValidApiInstanceMetaData()
|
||||
.withCurrentVersion(new APIVersion("2023.Q1"))
|
||||
@ -131,7 +127,7 @@ class ApiInstanceMetaDataTest
|
||||
|
||||
qInstance.addTable(new QTableMetaData()
|
||||
.withName("myFutureValidTable")
|
||||
.withMiddlewareMetaData(new ApiTableMetaData().withInitialVersion("2024.Q1")));
|
||||
.withMiddlewareMetaData(new ApiTableMetaDataContainer().withApiTableMetaData(TestUtils.API_NAME, new ApiTableMetaData().withInitialVersion("2024.Q1"))));
|
||||
|
||||
assertValidationErrors(qInstance, makeBaselineValidApiInstanceMetaData()
|
||||
.withCurrentVersion(new APIVersion("2023.Q1"))
|
||||
@ -143,19 +139,46 @@ class ApiInstanceMetaDataTest
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testPathSlashes()
|
||||
{
|
||||
assertValidationErrors(makeBaselineValidApiInstanceMetaDataWithVersions().withPath("myPath/"), List.of("does not start with '/'"));
|
||||
assertValidationErrors(makeBaselineValidApiInstanceMetaDataWithVersions().withPath("/yourPath"), List.of("does not end with '/'"));
|
||||
assertValidationErrors(makeBaselineValidApiInstanceMetaDataWithVersions().withPath("any/path"), List.of("does not start with '/'", "does not end with '/'"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private static ApiInstanceMetaData makeBaselineValidApiInstanceMetaData()
|
||||
{
|
||||
return (new ApiInstanceMetaData()
|
||||
.withName("QQQ API")
|
||||
.withName(TestUtils.API_NAME)
|
||||
.withPath("/api/")
|
||||
.withLabel("QQQ API")
|
||||
.withDescription("Test API for QQQ")
|
||||
.withContactEmail("contact@kingsrook.com"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private static ApiInstanceMetaData makeBaselineValidApiInstanceMetaDataWithVersions()
|
||||
{
|
||||
return (makeBaselineValidApiInstanceMetaData()
|
||||
.withCurrentVersion(new APIVersion("1"))
|
||||
.withSupportedVersions(List.of(new APIVersion("1"))));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@ -172,10 +195,10 @@ class ApiInstanceMetaDataTest
|
||||
*******************************************************************************/
|
||||
private void assertValidationErrors(QInstance qInstance, ApiInstanceMetaData apiInstanceMetaData, List<String> expectedErrors)
|
||||
{
|
||||
qInstance.withMiddlewareMetaData(apiInstanceMetaData);
|
||||
qInstance.withMiddlewareMetaData(new ApiInstanceMetaDataContainer().withApiInstanceMetaData(apiInstanceMetaData));
|
||||
|
||||
QInstanceValidator validator = new QInstanceValidator();
|
||||
apiInstanceMetaData.validate(qInstance, validator);
|
||||
apiInstanceMetaData.validate(apiInstanceMetaData.getName(), qInstance, validator);
|
||||
|
||||
List<String> errors = validator.getErrors();
|
||||
assertEquals(expectedErrors.size(), errors.size(), "Expected # of validation errors (got: " + errors + ")");
|
||||
|
Reference in New Issue
Block a user