mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-18 13:10:44 +00:00
Recursively add all association component schemas; add recordCount to bulk api action logs
This commit is contained in:
@ -27,9 +27,11 @@ import java.time.LocalDate;
|
|||||||
import java.time.temporal.ChronoUnit;
|
import java.time.temporal.ChronoUnit;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
import com.kingsrook.qqq.api.model.APIVersion;
|
import com.kingsrook.qqq.api.model.APIVersion;
|
||||||
import com.kingsrook.qqq.api.model.APIVersionRange;
|
import com.kingsrook.qqq.api.model.APIVersionRange;
|
||||||
import com.kingsrook.qqq.api.model.actions.GenerateOpenApiSpecInput;
|
import com.kingsrook.qqq.api.model.actions.GenerateOpenApiSpecInput;
|
||||||
@ -181,6 +183,8 @@ public class GenerateOpenApiSpecAction extends AbstractQActionFunction<GenerateO
|
|||||||
* Each input primary key will also be included in the corresponding response object.
|
* Each input primary key will also be included in the corresponding response object.
|
||||||
""";
|
""";
|
||||||
|
|
||||||
|
private Set<String> neededTableSchemas = new HashSet<>();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
@ -386,23 +390,9 @@ public class GenerateOpenApiSpecAction extends AbstractQActionFunction<GenerateO
|
|||||||
//////////////////////////////////////
|
//////////////////////////////////////
|
||||||
// build the schemas for this table //
|
// build the schemas for this table //
|
||||||
//////////////////////////////////////
|
//////////////////////////////////////
|
||||||
LinkedHashMap<String, Schema> tableFields = new LinkedHashMap<>();
|
Schema tableSchema = buildTableSchema(apiInstanceMetaData, table, tableApiFields);
|
||||||
Schema tableSchema = new Schema()
|
|
||||||
.withType("object")
|
|
||||||
.withProperties(tableFields);
|
|
||||||
componentSchemas.put(tableApiName, tableSchema);
|
componentSchemas.put(tableApiName, tableSchema);
|
||||||
|
|
||||||
for(QFieldMetaData field : tableApiFields)
|
|
||||||
{
|
|
||||||
Schema fieldSchema = getFieldSchema(table, field);
|
|
||||||
tableFields.put(ApiFieldMetaData.getEffectiveApiFieldName(apiInstanceMetaData.getName(), field), fieldSchema);
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////
|
|
||||||
// recursively add associations //
|
|
||||||
//////////////////////////////////
|
|
||||||
addAssociations(apiName, table, tableSchema);
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
// table as a search result (the base search result, plus the table itself) //
|
// table as a search result (the base search result, plus the table itself) //
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
@ -665,6 +655,8 @@ public class GenerateOpenApiSpecAction extends AbstractQActionFunction<GenerateO
|
|||||||
componentResponses.put("error" + HttpStatus.TOO_MANY_REQUESTS.getCode(), buildStandardErrorResponse("Too Many Requests. Your application has issued too many API requests in too short of a time frame."));
|
componentResponses.put("error" + HttpStatus.TOO_MANY_REQUESTS.getCode(), buildStandardErrorResponse("Too Many Requests. Your application has issued too many API requests in too short of a time frame."));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ensureAllNeededTableSchemasExist(apiInstanceMetaData, version, componentSchemas);
|
||||||
|
|
||||||
GenerateOpenApiSpecOutput output = new GenerateOpenApiSpecOutput();
|
GenerateOpenApiSpecOutput output = new GenerateOpenApiSpecOutput();
|
||||||
output.setOpenAPI(openAPI);
|
output.setOpenAPI(openAPI);
|
||||||
output.setYaml(YamlUtils.toYaml(openAPI));
|
output.setYaml(YamlUtils.toYaml(openAPI));
|
||||||
@ -674,6 +666,76 @@ public class GenerateOpenApiSpecAction extends AbstractQActionFunction<GenerateO
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** written for the use-case of, generating a single table's api, but it has
|
||||||
|
** associations that it references, so we need their schemas too - so, make
|
||||||
|
** sure they are all added to the componentSchemas map.
|
||||||
|
*******************************************************************************/
|
||||||
|
private void ensureAllNeededTableSchemasExist(ApiInstanceMetaData apiInstanceMetaData, String version, LinkedHashMap<String, Schema> componentSchemas) throws QException
|
||||||
|
{
|
||||||
|
String apiName = apiInstanceMetaData.getName();
|
||||||
|
|
||||||
|
boolean addedAny;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
// mmm, kinda odd loops, to avoid concurrent modification, and so-forth //
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
addedAny = false;
|
||||||
|
for(String neededTableSchema : neededTableSchemas)
|
||||||
|
{
|
||||||
|
if(!componentSchemas.containsKey(neededTableSchema))
|
||||||
|
{
|
||||||
|
LOG.debug("Adding needed schema: " + neededTableSchema);
|
||||||
|
QTableMetaData table = QContext.getQInstance().getTable(neededTableSchema);
|
||||||
|
|
||||||
|
ApiTableMetaDataContainer apiTableMetaDataContainer = ApiTableMetaDataContainer.of(table);
|
||||||
|
ApiTableMetaData apiTableMetaData = apiTableMetaDataContainer.getApiTableMetaData(apiName);
|
||||||
|
|
||||||
|
String tableApiName = StringUtils.hasContent(apiTableMetaData.getApiTableName()) ? apiTableMetaData.getApiTableName() : table.getName();
|
||||||
|
|
||||||
|
List<QFieldMetaData> tableApiFields = new GetTableApiFieldsAction().execute(new GetTableApiFieldsInput()
|
||||||
|
.withTableName(table.getName())
|
||||||
|
.withVersion(version)
|
||||||
|
.withApiName(apiName)).getFields();
|
||||||
|
|
||||||
|
componentSchemas.put(tableApiName, buildTableSchema(apiInstanceMetaData, table, tableApiFields));
|
||||||
|
addedAny = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while(addedAny);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private Schema buildTableSchema(ApiInstanceMetaData apiInstanceMetaData, QTableMetaData table, List<QFieldMetaData> tableApiFields)
|
||||||
|
{
|
||||||
|
LinkedHashMap<String, Schema> tableFields = new LinkedHashMap<>();
|
||||||
|
Schema tableSchema = new Schema()
|
||||||
|
.withType("object")
|
||||||
|
.withProperties(tableFields);
|
||||||
|
|
||||||
|
for(QFieldMetaData field : tableApiFields)
|
||||||
|
{
|
||||||
|
Schema fieldSchema = getFieldSchema(table, field);
|
||||||
|
tableFields.put(ApiFieldMetaData.getEffectiveApiFieldName(apiInstanceMetaData.getName(), field), fieldSchema);
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////
|
||||||
|
// recursively add associations //
|
||||||
|
//////////////////////////////////
|
||||||
|
addAssociations(apiInstanceMetaData.getName(), table, tableSchema);
|
||||||
|
|
||||||
|
return (tableSchema);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
@ -800,7 +862,7 @@ public class GenerateOpenApiSpecAction extends AbstractQActionFunction<GenerateO
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
private static void addAssociations(String apiName, QTableMetaData table, Schema tableSchema)
|
private void addAssociations(String apiName, QTableMetaData table, Schema tableSchema)
|
||||||
{
|
{
|
||||||
for(Association association : CollectionUtils.nonNullList(table.getAssociations()))
|
for(Association association : CollectionUtils.nonNullList(table.getAssociations()))
|
||||||
{
|
{
|
||||||
@ -809,6 +871,8 @@ public class GenerateOpenApiSpecAction extends AbstractQActionFunction<GenerateO
|
|||||||
ApiTableMetaData associatedApiTableMetaData = ObjectUtils.tryElse(() -> ApiTableMetaDataContainer.of(associatedTable).getApiTableMetaData(apiName), new ApiTableMetaData());
|
ApiTableMetaData associatedApiTableMetaData = ObjectUtils.tryElse(() -> ApiTableMetaDataContainer.of(associatedTable).getApiTableMetaData(apiName), new ApiTableMetaData());
|
||||||
String associatedTableApiName = StringUtils.hasContent(associatedApiTableMetaData.getApiTableName()) ? associatedApiTableMetaData.getApiTableName() : associatedTableName;
|
String associatedTableApiName = StringUtils.hasContent(associatedApiTableMetaData.getApiTableName()) ? associatedApiTableMetaData.getApiTableName() : associatedTableName;
|
||||||
|
|
||||||
|
neededTableSchemas.add(associatedTable.getName());
|
||||||
|
|
||||||
tableSchema.getProperties().put(association.getName(), new Schema()
|
tableSchema.getProperties().put(association.getName(), new Schema()
|
||||||
.withType("array")
|
.withType("array")
|
||||||
.withItems(new Schema().withRef("#/components/schemas/" + associatedTableApiName)));
|
.withItems(new Schema().withRef("#/components/schemas/" + associatedTableApiName)));
|
||||||
@ -823,8 +887,8 @@ public class GenerateOpenApiSpecAction extends AbstractQActionFunction<GenerateO
|
|||||||
private Schema getFieldSchema(QTableMetaData table, QFieldMetaData field)
|
private Schema getFieldSchema(QTableMetaData table, QFieldMetaData field)
|
||||||
{
|
{
|
||||||
Schema fieldSchema = new Schema()
|
Schema fieldSchema = new Schema()
|
||||||
.withType(getFieldType(table.getField(field.getName())))
|
.withType(getFieldType(field))
|
||||||
.withFormat(getFieldFormat(table.getField(field.getName())))
|
.withFormat(getFieldFormat(field))
|
||||||
.withDescription(field.getLabel() + " for the " + table.getLabel() + ".");
|
.withDescription(field.getLabel() + " for the " + table.getLabel() + ".");
|
||||||
|
|
||||||
if(!field.getIsEditable())
|
if(!field.getIsEditable())
|
||||||
|
@ -1504,7 +1504,7 @@ public class QJavalinApiHandler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QJavalinAccessLogger.logEndSuccess();
|
QJavalinAccessLogger.logEndSuccess(logPair("recordCount", insertInput.getRecords().size()));
|
||||||
context.status(HttpStatus.Code.MULTI_STATUS.getCode());
|
context.status(HttpStatus.Code.MULTI_STATUS.getCode());
|
||||||
String resultString = JsonUtils.toJson(response);
|
String resultString = JsonUtils.toJson(response);
|
||||||
context.result(resultString);
|
context.result(resultString);
|
||||||
@ -1636,7 +1636,7 @@ public class QJavalinApiHandler
|
|||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
QJavalinAccessLogger.logEndSuccess();
|
QJavalinAccessLogger.logEndSuccess(logPair("recordCount", updateInput.getRecords().size()));
|
||||||
context.status(HttpStatus.Code.MULTI_STATUS.getCode());
|
context.status(HttpStatus.Code.MULTI_STATUS.getCode());
|
||||||
String resultString = JsonUtils.toJson(response);
|
String resultString = JsonUtils.toJson(response);
|
||||||
context.result(resultString);
|
context.result(resultString);
|
||||||
@ -1777,7 +1777,7 @@ public class QJavalinApiHandler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QJavalinAccessLogger.logEndSuccess();
|
QJavalinAccessLogger.logEndSuccess(logPair("recordCount", deleteInput.getPrimaryKeys().size()));
|
||||||
context.status(HttpStatus.Code.MULTI_STATUS.getCode());
|
context.status(HttpStatus.Code.MULTI_STATUS.getCode());
|
||||||
String resultString = JsonUtils.toJson(response);
|
String resultString = JsonUtils.toJson(response);
|
||||||
context.result(resultString);
|
context.result(resultString);
|
||||||
|
@ -25,8 +25,11 @@ package com.kingsrook.qqq.api.actions;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import com.kingsrook.qqq.api.BaseTest;
|
import com.kingsrook.qqq.api.BaseTest;
|
||||||
import com.kingsrook.qqq.api.TestUtils;
|
import com.kingsrook.qqq.api.TestUtils;
|
||||||
|
import com.kingsrook.qqq.api.model.APIVersion;
|
||||||
import com.kingsrook.qqq.api.model.actions.GenerateOpenApiSpecInput;
|
import com.kingsrook.qqq.api.model.actions.GenerateOpenApiSpecInput;
|
||||||
import com.kingsrook.qqq.api.model.actions.GenerateOpenApiSpecOutput;
|
import com.kingsrook.qqq.api.model.actions.GenerateOpenApiSpecOutput;
|
||||||
|
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.ApiTableMetaData;
|
||||||
import com.kingsrook.qqq.api.model.metadata.tables.ApiTableMetaDataContainer;
|
import com.kingsrook.qqq.api.model.metadata.tables.ApiTableMetaDataContainer;
|
||||||
import com.kingsrook.qqq.backend.core.context.QContext;
|
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||||
@ -53,8 +56,46 @@ class GenerateOpenApiSpecActionTest extends BaseTest
|
|||||||
@Test
|
@Test
|
||||||
void test() throws QException
|
void test() throws QException
|
||||||
{
|
{
|
||||||
GenerateOpenApiSpecOutput output = new GenerateOpenApiSpecAction().execute(new GenerateOpenApiSpecInput().withVersion(TestUtils.CURRENT_API_VERSION).withApiName(TestUtils.API_NAME));
|
for(ApiInstanceMetaData apiInstanceMetaData : ApiInstanceMetaDataContainer.of(QContext.getQInstance()).getApis().values())
|
||||||
System.out.println(output.getYaml());
|
{
|
||||||
|
for(APIVersion supportedVersion : apiInstanceMetaData.getSupportedVersions())
|
||||||
|
{
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
// just making sure we don't throw on any apis in the test instance //
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
GenerateOpenApiSpecOutput output = new GenerateOpenApiSpecAction().execute(new GenerateOpenApiSpecInput()
|
||||||
|
.withVersion(supportedVersion.toString())
|
||||||
|
.withApiName(apiInstanceMetaData.getName()));
|
||||||
|
// System.out.println(output.getYaml());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testSingleTable() throws QException
|
||||||
|
{
|
||||||
|
for(ApiInstanceMetaData apiInstanceMetaData : ApiInstanceMetaDataContainer.of(QContext.getQInstance()).getApis().values())
|
||||||
|
{
|
||||||
|
for(APIVersion supportedVersion : apiInstanceMetaData.getSupportedVersions())
|
||||||
|
{
|
||||||
|
for(QTableMetaData table : QContext.getQInstance().getTables().values())
|
||||||
|
{
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
// just making sure we don't throw on any apis in the test instance //
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
GenerateOpenApiSpecOutput output = new GenerateOpenApiSpecAction().execute(new GenerateOpenApiSpecInput()
|
||||||
|
.withTableName(table.getName())
|
||||||
|
.withVersion(supportedVersion.toString())
|
||||||
|
.withApiName(apiInstanceMetaData.getName()));
|
||||||
|
// System.out.println(output.getYaml());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user