From f58a59438baf703160ce27d7bbaa3abbcd49a57d Mon Sep 17 00:00:00 2001 From: Darin Kelkhoff Date: Tue, 1 Mar 2022 18:27:43 -0600 Subject: [PATCH] Checkpoint: Added Update (edit) action; Stub of PossibleValues, displayValues; Load definition from JSON --- .../backend/core/actions/UpdateAction.java | 35 ++++ .../core/adapters/QInstanceAdapter.java | 80 +++++++++ .../core/instances/QInstanceValidator.java | 43 ++++- .../model/actions/update/UpdateRequest.java | 62 +++++++ .../model/actions/update/UpdateResult.java | 40 +++++ .../qqq/backend/core/model/data/QRecord.java | 119 +++++++++---- .../core/model/data/QRecordWithStatus.java | 1 - .../core/model/metadata/QFieldMetaData.java | 34 ++++ .../core/model/metadata/QInstance.java | 55 ++++++ .../possiblevalues/QPossibleValueSource.java | 144 ++++++++++++++++ .../QPossibleValueSourceType.java | 17 ++ .../QAuthenticationModuleDispatcher.java | 17 +- .../interfaces/QBackendModuleInterface.java | 9 + .../modules/interfaces/UpdateInterface.java | 23 +++ .../core/modules/mock/MockBackendModule.java | 11 ++ .../core/modules/mock/MockDeleteAction.java | 2 +- .../core/modules/mock/MockUpdateAction.java | 44 +++++ .../backend/core/utils/ExceptionUtils.java | 5 +- .../qqq/backend/core/utils/JsonUtils.java | 16 ++ .../core/actions/UpdateActionTest.java | 47 +++++ .../core/adapters/QInstanceAdapterTest.java | 75 ++++++++ .../instances/QInstanceValidatorTest.java | 66 ++++++- .../QAuthenticationModuleDispatcherTest.java | 78 +++++++++ .../qqq/backend/core/utils/JsonUtilsTest.java | 4 +- .../qqq/backend/core/utils/TestUtils.java | 22 ++- src/test/resources/personQInstance.json | 156 +++++++++++++++++ .../personQInstanceIncludingBackend.json | 163 ++++++++++++++++++ 27 files changed, 1313 insertions(+), 55 deletions(-) create mode 100644 src/main/java/com/kingsrook/qqq/backend/core/actions/UpdateAction.java create mode 100644 src/main/java/com/kingsrook/qqq/backend/core/adapters/QInstanceAdapter.java create mode 100644 src/main/java/com/kingsrook/qqq/backend/core/model/actions/update/UpdateRequest.java create mode 100644 src/main/java/com/kingsrook/qqq/backend/core/model/actions/update/UpdateResult.java create mode 100644 src/main/java/com/kingsrook/qqq/backend/core/model/metadata/possiblevalues/QPossibleValueSource.java create mode 100644 src/main/java/com/kingsrook/qqq/backend/core/model/metadata/possiblevalues/QPossibleValueSourceType.java create mode 100644 src/main/java/com/kingsrook/qqq/backend/core/modules/interfaces/UpdateInterface.java create mode 100644 src/main/java/com/kingsrook/qqq/backend/core/modules/mock/MockUpdateAction.java create mode 100644 src/test/java/com/kingsrook/qqq/backend/core/actions/UpdateActionTest.java create mode 100644 src/test/java/com/kingsrook/qqq/backend/core/adapters/QInstanceAdapterTest.java create mode 100644 src/test/java/com/kingsrook/qqq/backend/core/modules/QAuthenticationModuleDispatcherTest.java create mode 100644 src/test/resources/personQInstance.json create mode 100644 src/test/resources/personQInstanceIncludingBackend.json diff --git a/src/main/java/com/kingsrook/qqq/backend/core/actions/UpdateAction.java b/src/main/java/com/kingsrook/qqq/backend/core/actions/UpdateAction.java new file mode 100644 index 00000000..82ecac8a --- /dev/null +++ b/src/main/java/com/kingsrook/qqq/backend/core/actions/UpdateAction.java @@ -0,0 +1,35 @@ +/* + * Copyright © 2021-2021. Kingsrook LLC . All Rights Reserved. + */ + +package com.kingsrook.qqq.backend.core.actions; + + +import com.kingsrook.qqq.backend.core.exceptions.QException; +import com.kingsrook.qqq.backend.core.model.actions.update.UpdateRequest; +import com.kingsrook.qqq.backend.core.model.actions.update.UpdateResult; +import com.kingsrook.qqq.backend.core.modules.QBackendModuleDispatcher; +import com.kingsrook.qqq.backend.core.modules.interfaces.QBackendModuleInterface; + + +/******************************************************************************* + ** Action to update one or more records. + ** + *******************************************************************************/ +public class UpdateAction +{ + /******************************************************************************* + ** + *******************************************************************************/ + public UpdateResult execute(UpdateRequest updateRequest) throws QException + { + ActionHelper.validateSession(updateRequest); + + QBackendModuleDispatcher qBackendModuleDispatcher = new QBackendModuleDispatcher(); + QBackendModuleInterface qModule = qBackendModuleDispatcher.getQModule(updateRequest.getBackend()); + // todo pre-customization - just get to modify the request? + UpdateResult updateResult = qModule.getUpdateInterface().execute(updateRequest); + // todo post-customization - can do whatever w/ the result if you want + return updateResult; + } +} diff --git a/src/main/java/com/kingsrook/qqq/backend/core/adapters/QInstanceAdapter.java b/src/main/java/com/kingsrook/qqq/backend/core/adapters/QInstanceAdapter.java new file mode 100644 index 00000000..7e598af5 --- /dev/null +++ b/src/main/java/com/kingsrook/qqq/backend/core/adapters/QInstanceAdapter.java @@ -0,0 +1,80 @@ +/* + * Copyright © 2021-2022. Kingsrook LLC . All Rights Reserved. + */ + +package com.kingsrook.qqq.backend.core.adapters; + + +import java.io.IOException; +import java.util.Map; +import com.fasterxml.jackson.core.type.TypeReference; +import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData; +import com.kingsrook.qqq.backend.core.model.metadata.QInstance; +import com.kingsrook.qqq.backend.core.utils.JsonUtils; +import org.json.JSONObject; + + +/******************************************************************************* + ** Methods for adapting qInstances to serialized (string) formats (e.g., json), + ** and vice versa. + *******************************************************************************/ +public class QInstanceAdapter +{ + + /******************************************************************************* + ** Convert a qInstance to JSON. + ** + *******************************************************************************/ + public String qInstanceToJson(QInstance qInstance) + { + return (JsonUtils.toJson(qInstance)); + } + + + + /******************************************************************************* + ** Convert a qInstance to JSON. + ** + *******************************************************************************/ + public String qInstanceToJsonIncludingBackend(QInstance qInstance) + { + String jsonString = JsonUtils.toJson(qInstance); + JSONObject jsonObject = JsonUtils.toJSONObject(jsonString); + + String backendsJsonString = JsonUtils.toJson(qInstance.getBackends()); + JSONObject backendsJsonObject = JsonUtils.toJSONObject(backendsJsonString); + jsonObject.put("backends", backendsJsonObject); + + return (jsonObject.toString()); + } + + + + /******************************************************************************* + ** Build a qInstance from JSON. + ** + *******************************************************************************/ + public QInstance jsonToQInstance(String json) throws IOException + { + return (JsonUtils.toObject(json, QInstance.class)); + } + + + + /******************************************************************************* + ** Build a qInstance from JSON. + ** + *******************************************************************************/ + public QInstance jsonToQInstanceIncludingBackends(String json) throws IOException + { + QInstance qInstance = JsonUtils.toObject(json, QInstance.class); + JSONObject jsonObject = JsonUtils.toJSONObject(json); + JSONObject backendsJsonObject = jsonObject.getJSONObject("backends"); + Map backends = JsonUtils.toObject(backendsJsonObject.toString(), new TypeReference<>() + { + }); + qInstance.setBackends(backends); + return qInstance; + } + +} diff --git a/src/main/java/com/kingsrook/qqq/backend/core/instances/QInstanceValidator.java b/src/main/java/com/kingsrook/qqq/backend/core/instances/QInstanceValidator.java index 1ab2ee74..302a30b5 100644 --- a/src/main/java/com/kingsrook/qqq/backend/core/instances/QInstanceValidator.java +++ b/src/main/java/com/kingsrook/qqq/backend/core/instances/QInstanceValidator.java @@ -60,27 +60,58 @@ public class QInstanceValidator List errors = new ArrayList<>(); try { - if(assertCondition(errors, CollectionUtils.nullSafeHasContents(qInstance.getBackends()), "At least 1 backend must be defined.")) + if(assertCondition(errors, CollectionUtils.nullSafeHasContents(qInstance.getBackends()), + "At least 1 backend must be defined.")) { qInstance.getBackends().forEach((backendName, backend) -> { - assertCondition(errors, Objects.equals(backendName, backend.getName()), "Inconsistent naming for backend: " + backendName + "/" + backend.getName() + "."); + assertCondition(errors, Objects.equals(backendName, backend.getName()), + "Inconsistent naming for backend: " + backendName + "/" + backend.getName() + "."); }); } - if(assertCondition(errors, CollectionUtils.nullSafeHasContents(qInstance.getTables()), "At least 1 table must be defined.")) + ///////////////////////// + // validate the tables // + ///////////////////////// + if(assertCondition(errors, CollectionUtils.nullSafeHasContents(qInstance.getTables()), + "At least 1 table must be defined.")) { qInstance.getTables().forEach((tableName, table) -> { - assertCondition(errors, Objects.equals(tableName, table.getName()), "Inconsistent naming for table: " + tableName + "/" + table.getName() + "."); + assertCondition(errors, Objects.equals(tableName, table.getName()), + "Inconsistent naming for table: " + tableName + "/" + table.getName() + "."); - if(assertCondition(errors, StringUtils.hasContent(table.getBackendName()), "Missing backend name for table " + tableName + ".")) + //////////////////////////////////////// + // validate the backend for the table // + //////////////////////////////////////// + if(assertCondition(errors, StringUtils.hasContent(table.getBackendName()), + "Missing backend name for table " + tableName + ".")) { if(CollectionUtils.nullSafeHasContents(qInstance.getBackends())) { - assertCondition(errors, qInstance.getBackendForTable(tableName) != null, "Unrecognized backend " + table.getBackendName() + " for table " + tableName + "."); + assertCondition(errors, qInstance.getBackendForTable(tableName) != null, + "Unrecognized backend " + table.getBackendName() + " for table " + tableName + "."); } } + + ////////////////////////////////// + // validate fields in the table // + ////////////////////////////////// + if(assertCondition(errors, CollectionUtils.nullSafeHasContents(table.getFields()), + "At least 1 field must be defined in table " + tableName + ".")) + { + table.getFields().forEach((fieldName, field) -> + { + assertCondition(errors, Objects.equals(fieldName, field.getName()), + "Inconsistent naming in table " + tableName + " for field " + fieldName + "/" + field.getName() + "."); + + if(field.getPossibleValueSourceName() != null) + { + assertCondition(errors, qInstance.getPossibleValueSource(field.getPossibleValueSourceName()) != null, + "Unrecognized possibleValueSourceName " + field.getPossibleValueSourceName() + " in table " + tableName + " for field " + fieldName + "."); + } + }); + } }); } } diff --git a/src/main/java/com/kingsrook/qqq/backend/core/model/actions/update/UpdateRequest.java b/src/main/java/com/kingsrook/qqq/backend/core/model/actions/update/UpdateRequest.java new file mode 100644 index 00000000..3756df72 --- /dev/null +++ b/src/main/java/com/kingsrook/qqq/backend/core/model/actions/update/UpdateRequest.java @@ -0,0 +1,62 @@ +/* + * Copyright © 2021-2022. Kingsrook LLC . All Rights Reserved. + */ + +package com.kingsrook.qqq.backend.core.model.actions.update; + + +import java.util.List; +import com.kingsrook.qqq.backend.core.model.actions.AbstractQTableRequest; +import com.kingsrook.qqq.backend.core.model.data.QRecord; +import com.kingsrook.qqq.backend.core.model.metadata.QInstance; + + +/******************************************************************************* + ** Request data handler for the update action + ** + *******************************************************************************/ +public class UpdateRequest extends AbstractQTableRequest +{ + private List records; + + + + /******************************************************************************* + ** + *******************************************************************************/ + public UpdateRequest() + { + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + public UpdateRequest(QInstance instance) + { + super(instance); + } + + + + /******************************************************************************* + ** Getter for records + ** + *******************************************************************************/ + public List getRecords() + { + return records; + } + + + + /******************************************************************************* + ** Setter for records + ** + *******************************************************************************/ + public void setRecords(List records) + { + this.records = records; + } +} diff --git a/src/main/java/com/kingsrook/qqq/backend/core/model/actions/update/UpdateResult.java b/src/main/java/com/kingsrook/qqq/backend/core/model/actions/update/UpdateResult.java new file mode 100644 index 00000000..f0ad3d8c --- /dev/null +++ b/src/main/java/com/kingsrook/qqq/backend/core/model/actions/update/UpdateResult.java @@ -0,0 +1,40 @@ +/* + * Copyright © 2021-2022. Kingsrook LLC . All Rights Reserved. + */ + +package com.kingsrook.qqq.backend.core.model.actions.update; + + +import java.util.List; +import com.kingsrook.qqq.backend.core.model.actions.AbstractQResult; +import com.kingsrook.qqq.backend.core.model.data.QRecordWithStatus; + + +/******************************************************************************* + * Result for an update action + * + *******************************************************************************/ +public class UpdateResult extends AbstractQResult +{ + List records; + + + + /******************************************************************************* + ** + *******************************************************************************/ + public List getRecords() + { + return records; + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + public void setRecords(List records) + { + this.records = records; + } +} diff --git a/src/main/java/com/kingsrook/qqq/backend/core/model/data/QRecord.java b/src/main/java/com/kingsrook/qqq/backend/core/model/data/QRecord.java index 95b69e28..b3f92f7c 100644 --- a/src/main/java/com/kingsrook/qqq/backend/core/model/data/QRecord.java +++ b/src/main/java/com/kingsrook/qqq/backend/core/model/data/QRecord.java @@ -13,12 +13,18 @@ import java.util.Map; /******************************************************************************* * Data Record within qqq. e.g., a single row from a database. * + * Actual values (e.g., as stored in the backend system) are in the `values` + * map. Keys in this map are fieldNames from the QTableMetaData. + * + * "Display values" (e.g., labels for possible values, or formatted numbers + * (e.g., quantities with commas)) are in the displayValues map. *******************************************************************************/ public class QRecord { private String tableName; - private Serializable primaryKey; - private Map values; + //x private Serializable primaryKey; + private Map values = new LinkedHashMap<>(); + private Map displayValues = new LinkedHashMap<>(); @@ -27,11 +33,6 @@ public class QRecord *******************************************************************************/ public void setValue(String fieldName, Serializable value) { - if(values == null) - { - values = new LinkedHashMap<>(); - } - values.put(fieldName, value); } @@ -48,6 +49,27 @@ public class QRecord + /******************************************************************************* + ** + *******************************************************************************/ + public void setDisplayValue(String fieldName, String displayValue) + { + displayValues.put(fieldName, displayValue); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + public QRecord withDisplayValue(String fieldName, String displayValue) + { + setDisplayValue(fieldName, displayValue); + return (this); + } + + + /******************************************************************************* ** Getter for tableName ** @@ -82,37 +104,37 @@ public class QRecord - /******************************************************************************* - ** Getter for primaryKey - ** - *******************************************************************************/ - public Serializable getPrimaryKey() - { - return primaryKey; - } + //x /******************************************************************************* + //x ** Getter for primaryKey + //x ** + //x *******************************************************************************/ + //x public Serializable getPrimaryKey() + //x { + //x return primaryKey; + //x } - /******************************************************************************* - ** Setter for primaryKey - ** - *******************************************************************************/ - public void setPrimaryKey(Serializable primaryKey) - { - this.primaryKey = primaryKey; - } + //x /******************************************************************************* + //x ** Setter for primaryKey + //x ** + //x *******************************************************************************/ + //x public void setPrimaryKey(Serializable primaryKey) + //x { + //x this.primaryKey = primaryKey; + //x } - /******************************************************************************* - ** Setter for primaryKey - ** - *******************************************************************************/ - public QRecord withPrimaryKey(Serializable primaryKey) - { - this.primaryKey = primaryKey; - return (this); - } + //x /******************************************************************************* + //x ** Setter for primaryKey + //x ** + //x *******************************************************************************/ + //x public QRecord withPrimaryKey(Serializable primaryKey) + //x { + //x this.primaryKey = primaryKey; + //x return (this); + //x } @@ -149,6 +171,39 @@ public class QRecord + /******************************************************************************* + ** Getter for displayValues + ** + *******************************************************************************/ + public Map getDisplayValues() + { + return displayValues; + } + + + + /******************************************************************************* + ** Setter for displayValues + ** + *******************************************************************************/ + public void setDisplayValues(Map displayValues) + { + this.displayValues = displayValues; + } + + + + /******************************************************************************* + ** Getter for a single field's value + ** + *******************************************************************************/ + public String getDisplayValue(String fieldName) + { + return (displayValues.get(fieldName)); + } + + + /******************************************************************************* ** Getter for a single field's value ** diff --git a/src/main/java/com/kingsrook/qqq/backend/core/model/data/QRecordWithStatus.java b/src/main/java/com/kingsrook/qqq/backend/core/model/data/QRecordWithStatus.java index 72600357..22f42466 100644 --- a/src/main/java/com/kingsrook/qqq/backend/core/model/data/QRecordWithStatus.java +++ b/src/main/java/com/kingsrook/qqq/backend/core/model/data/QRecordWithStatus.java @@ -36,7 +36,6 @@ public class QRecordWithStatus extends QRecord public QRecordWithStatus(QRecord record) { super.setTableName(record.getTableName()); - super.setPrimaryKey(record.getPrimaryKey()); super.setValues(record.getValues()); } diff --git a/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/QFieldMetaData.java b/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/QFieldMetaData.java index e709256e..d8ac1a5e 100644 --- a/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/QFieldMetaData.java +++ b/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/QFieldMetaData.java @@ -16,6 +16,8 @@ public class QFieldMetaData private String backendName; private QFieldType type; + private String possibleValueSourceName; + /******************************************************************************* @@ -165,4 +167,36 @@ public class QFieldMetaData this.backendName = backendName; return (this); } + + + + /******************************************************************************* + ** + *******************************************************************************/ + public String getPossibleValueSourceName() + { + return possibleValueSourceName; + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + public void setPossibleValueSourceName(String possibleValueSourceName) + { + this.possibleValueSourceName = possibleValueSourceName; + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + public QFieldMetaData withPossibleValueSourceName(String possibleValueSourceName) + { + this.possibleValueSourceName = possibleValueSourceName; + return (this); + } + } diff --git a/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/QInstance.java b/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/QInstance.java index 21509d86..9eb86158 100644 --- a/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/QInstance.java +++ b/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/QInstance.java @@ -11,6 +11,7 @@ import java.util.List; import java.util.Map; import com.fasterxml.jackson.annotation.JsonIgnore; import com.kingsrook.qqq.backend.core.instances.QInstanceValidationKey; +import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.QPossibleValueSource; import com.kingsrook.qqq.backend.core.model.metadata.processes.QFunctionMetaData; import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData; @@ -30,9 +31,11 @@ public class QInstance private QAuthenticationMetaData authentication = null; private Map tables = new HashMap<>(); + private Map> possibleValueSources = new HashMap<>(); private Map processes = new HashMap<>(); // todo - lock down the object (no more changes allowed) after it's been validated? + @JsonIgnore private boolean hasBeenValidated = false; @@ -147,6 +150,36 @@ public class QInstance + /******************************************************************************* + ** + *******************************************************************************/ + public void addPossibleValueSource(QPossibleValueSource possibleValueSource) + { + this.possibleValueSources.put(possibleValueSource.getName(), possibleValueSource); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + public void addPossibleValueSource(String name, QPossibleValueSource possibleValueSource) + { + this.possibleValueSources.put(name, possibleValueSource); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + public QPossibleValueSource getPossibleValueSource(String name) + { + return (this.possibleValueSources.get(name)); + } + + + /******************************************************************************* ** *******************************************************************************/ @@ -227,6 +260,28 @@ public class QInstance + /******************************************************************************* + ** Getter for possibleValueSources + ** + *******************************************************************************/ + public Map> getPossibleValueSources() + { + return possibleValueSources; + } + + + + /******************************************************************************* + ** Setter for possibleValueSources + ** + *******************************************************************************/ + public void setPossibleValueSources(Map> possibleValueSources) + { + this.possibleValueSources = possibleValueSources; + } + + + /******************************************************************************* ** Getter for processes ** diff --git a/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/possiblevalues/QPossibleValueSource.java b/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/possiblevalues/QPossibleValueSource.java new file mode 100644 index 00000000..9be1252e --- /dev/null +++ b/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/possiblevalues/QPossibleValueSource.java @@ -0,0 +1,144 @@ +/* + * Copyright © 2021-2022. Kingsrook LLC . All Rights Reserved. + */ + +package com.kingsrook.qqq.backend.core.model.metadata.possiblevalues; + + +import java.util.ArrayList; +import java.util.List; + + +/******************************************************************************* + ** Meta-data to represent a single field in a table. + ** + *******************************************************************************/ +public class QPossibleValueSource +{ + private String name; + private QPossibleValueSourceType type; + + // should these be in sub-types?? + private List enumValues; + + + + /******************************************************************************* + ** + *******************************************************************************/ + public QPossibleValueSource() + { + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + public String getName() + { + return name; + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + public void setName(String name) + { + this.name = name; + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + public QPossibleValueSource withName(String name) + { + this.name = name; + return (this); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + public QPossibleValueSourceType getType() + { + return type; + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + public void setType(QPossibleValueSourceType type) + { + this.type = type; + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + public QPossibleValueSource withType(QPossibleValueSourceType type) + { + this.type = type; + return (this); + } + + + + /******************************************************************************* + ** Getter for enumValues + ** + *******************************************************************************/ + public List getEnumValues() + { + return enumValues; + } + + + + /******************************************************************************* + ** Setter for enumValues + ** + *******************************************************************************/ + public void setEnumValues(List enumValues) + { + this.enumValues = enumValues; + } + + + + /******************************************************************************* + ** Fluent setter for enumValues + ** + *******************************************************************************/ + public QPossibleValueSource withEnumValues(List enumValues) + { + this.enumValues = enumValues; + return this; + } + + + + /******************************************************************************* + ** Fluent adder for enumValues + ** + *******************************************************************************/ + public QPossibleValueSource addEnumValue(T enumValue) + { + if(this.enumValues == null) + { + this.enumValues = new ArrayList<>(); + } + this.enumValues.add(enumValue); + return this; + } +} diff --git a/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/possiblevalues/QPossibleValueSourceType.java b/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/possiblevalues/QPossibleValueSourceType.java new file mode 100644 index 00000000..5f29f088 --- /dev/null +++ b/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/possiblevalues/QPossibleValueSourceType.java @@ -0,0 +1,17 @@ +/* + * Copyright © 2021-2021. Kingsrook LLC . All Rights Reserved. + */ + +package com.kingsrook.qqq.backend.core.model.metadata.possiblevalues; + + +/******************************************************************************* + ** Possible types (e.g, kinds of data sources) for a possible value source. + ** + *******************************************************************************/ +public enum QPossibleValueSourceType +{ + ENUM, + TABLE, + CUSTOM +} diff --git a/src/main/java/com/kingsrook/qqq/backend/core/modules/QAuthenticationModuleDispatcher.java b/src/main/java/com/kingsrook/qqq/backend/core/modules/QAuthenticationModuleDispatcher.java index 60bda692..3aaba3e9 100644 --- a/src/main/java/com/kingsrook/qqq/backend/core/modules/QAuthenticationModuleDispatcher.java +++ b/src/main/java/com/kingsrook/qqq/backend/core/modules/QAuthenticationModuleDispatcher.java @@ -49,12 +49,22 @@ public class QAuthenticationModuleDispatcher throw (new QModuleDispatchException("No authentication meta data defined.")); } + return getQModule(authenticationMetaData.getType()); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + public QAuthenticationModuleInterface getQModule(String authenticationType) throws QModuleDispatchException + { try { - String className = authenticationTypeToModuleClassNameMap.get(authenticationMetaData.getType()); + String className = authenticationTypeToModuleClassNameMap.get(authenticationType); if(className == null) { - throw (new QModuleDispatchException("Unrecognized authentication type [" + authenticationMetaData.getType() + "] in dispatcher.")); + throw (new QModuleDispatchException("Unrecognized authentication type [" + authenticationType + "] in dispatcher.")); } Class moduleClass = Class.forName(className); @@ -66,7 +76,8 @@ public class QAuthenticationModuleDispatcher } catch(Exception e) { - throw (new QModuleDispatchException("Error getting authentication module of type: " + authenticationMetaData.getType(), e)); + throw (new QModuleDispatchException("Error getting authentication module of type: " + authenticationType, e)); } } + } diff --git a/src/main/java/com/kingsrook/qqq/backend/core/modules/interfaces/QBackendModuleInterface.java b/src/main/java/com/kingsrook/qqq/backend/core/modules/interfaces/QBackendModuleInterface.java index ed4d2827..f5073697 100644 --- a/src/main/java/com/kingsrook/qqq/backend/core/modules/interfaces/QBackendModuleInterface.java +++ b/src/main/java/com/kingsrook/qqq/backend/core/modules/interfaces/QBackendModuleInterface.java @@ -32,6 +32,15 @@ public interface QBackendModuleInterface return null; } + /******************************************************************************* + ** + *******************************************************************************/ + default UpdateInterface getUpdateInterface() + { + throwNotImplemented("Update"); + return null; + } + /******************************************************************************* ** *******************************************************************************/ diff --git a/src/main/java/com/kingsrook/qqq/backend/core/modules/interfaces/UpdateInterface.java b/src/main/java/com/kingsrook/qqq/backend/core/modules/interfaces/UpdateInterface.java new file mode 100644 index 00000000..724bfc73 --- /dev/null +++ b/src/main/java/com/kingsrook/qqq/backend/core/modules/interfaces/UpdateInterface.java @@ -0,0 +1,23 @@ +/* + * Copyright © 2021-2021. Kingsrook LLC . All Rights Reserved. + */ + +package com.kingsrook.qqq.backend.core.modules.interfaces; + + +import com.kingsrook.qqq.backend.core.exceptions.QException; +import com.kingsrook.qqq.backend.core.model.actions.update.UpdateRequest; +import com.kingsrook.qqq.backend.core.model.actions.update.UpdateResult; + + +/******************************************************************************* + ** Interface for the update action. + ** + *******************************************************************************/ +public interface UpdateInterface +{ + /******************************************************************************* + ** + *******************************************************************************/ + UpdateResult execute(UpdateRequest updateRequest) throws QException; +} diff --git a/src/main/java/com/kingsrook/qqq/backend/core/modules/mock/MockBackendModule.java b/src/main/java/com/kingsrook/qqq/backend/core/modules/mock/MockBackendModule.java index 964d5d55..0c829173 100644 --- a/src/main/java/com/kingsrook/qqq/backend/core/modules/mock/MockBackendModule.java +++ b/src/main/java/com/kingsrook/qqq/backend/core/modules/mock/MockBackendModule.java @@ -9,6 +9,7 @@ import com.kingsrook.qqq.backend.core.modules.interfaces.DeleteInterface; import com.kingsrook.qqq.backend.core.modules.interfaces.InsertInterface; import com.kingsrook.qqq.backend.core.modules.interfaces.QBackendModuleInterface; import com.kingsrook.qqq.backend.core.modules.interfaces.QueryInterface; +import com.kingsrook.qqq.backend.core.modules.interfaces.UpdateInterface; /******************************************************************************* @@ -41,6 +42,16 @@ public class MockBackendModule implements QBackendModuleInterface } + /******************************************************************************* + ** + *******************************************************************************/ + @Override + public UpdateInterface getUpdateInterface() + { + return (new MockUpdateAction()); + } + + /******************************************************************************* ** *******************************************************************************/ diff --git a/src/main/java/com/kingsrook/qqq/backend/core/modules/mock/MockDeleteAction.java b/src/main/java/com/kingsrook/qqq/backend/core/modules/mock/MockDeleteAction.java index 81fdef1f..59663803 100644 --- a/src/main/java/com/kingsrook/qqq/backend/core/modules/mock/MockDeleteAction.java +++ b/src/main/java/com/kingsrook/qqq/backend/core/modules/mock/MockDeleteAction.java @@ -31,7 +31,7 @@ public class MockDeleteAction implements DeleteInterface rs.setRecords(deleteRequest.getPrimaryKeys().stream().map(primaryKey -> { - QRecord qRecord = new QRecord().withTableName(deleteRequest.getTableName()).withPrimaryKey(primaryKey); + QRecord qRecord = new QRecord().withTableName(deleteRequest.getTableName()).withValue("id", primaryKey); return new QRecordWithStatus(qRecord); }).toList()); diff --git a/src/main/java/com/kingsrook/qqq/backend/core/modules/mock/MockUpdateAction.java b/src/main/java/com/kingsrook/qqq/backend/core/modules/mock/MockUpdateAction.java new file mode 100644 index 00000000..94e7712b --- /dev/null +++ b/src/main/java/com/kingsrook/qqq/backend/core/modules/mock/MockUpdateAction.java @@ -0,0 +1,44 @@ +/* + * Copyright © 2021-2021. Kingsrook LLC . All Rights Reserved. + */ + +package com.kingsrook.qqq.backend.core.modules.mock; + + +import com.kingsrook.qqq.backend.core.exceptions.QException; +import com.kingsrook.qqq.backend.core.model.actions.update.UpdateRequest; +import com.kingsrook.qqq.backend.core.model.actions.update.UpdateResult; +import com.kingsrook.qqq.backend.core.model.data.QRecordWithStatus; +import com.kingsrook.qqq.backend.core.modules.interfaces.UpdateInterface; + + +/******************************************************************************* + ** Mocked up version of update action. + ** + *******************************************************************************/ +public class MockUpdateAction implements UpdateInterface +{ + + /******************************************************************************* + ** + *******************************************************************************/ + public UpdateResult execute(UpdateRequest updateRequest) throws QException + { + try + { + UpdateResult rs = new UpdateResult(); + + rs.setRecords(updateRequest.getRecords().stream().map(qRecord -> + { + return new QRecordWithStatus(qRecord); + }).toList()); + + return rs; + } + catch(Exception e) + { + throw new QException("Error executing update: " + e.getMessage(), e); + } + } + +} diff --git a/src/main/java/com/kingsrook/qqq/backend/core/utils/ExceptionUtils.java b/src/main/java/com/kingsrook/qqq/backend/core/utils/ExceptionUtils.java index af8fc8e8..6f031933 100644 --- a/src/main/java/com/kingsrook/qqq/backend/core/utils/ExceptionUtils.java +++ b/src/main/java/com/kingsrook/qqq/backend/core/utils/ExceptionUtils.java @@ -24,10 +24,9 @@ public class ExceptionUtils return (null); } - if(e.getClass().equals(targetClass)) + if(targetClass.isInstance(e)) { - //noinspection unchecked - return ((T) e); + return targetClass.cast(e); } if(e.getCause() == null) diff --git a/src/main/java/com/kingsrook/qqq/backend/core/utils/JsonUtils.java b/src/main/java/com/kingsrook/qqq/backend/core/utils/JsonUtils.java index 05a2f3db..bdc1b4dd 100644 --- a/src/main/java/com/kingsrook/qqq/backend/core/utils/JsonUtils.java +++ b/src/main/java/com/kingsrook/qqq/backend/core/utils/JsonUtils.java @@ -7,6 +7,7 @@ package com.kingsrook.qqq.backend.core.utils; import java.io.IOException; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectWriter; import com.fasterxml.jackson.databind.SerializationFeature; @@ -91,6 +92,21 @@ public class JsonUtils + /******************************************************************************* + ** De-serialize a json string into an object of the specified class. + ** + ** Internally using jackson - so jackson annotations apply! + ** + *******************************************************************************/ + public static T toObject(String json, TypeReference typeReference) throws IOException + { + ObjectMapper objectMapper = newObjectMapper(); + T t = objectMapper.readValue(json, typeReference); + return t; + } + + + /******************************************************************************* ** De-serialize a json string into a JSONObject (string must start with "{") ** diff --git a/src/test/java/com/kingsrook/qqq/backend/core/actions/UpdateActionTest.java b/src/test/java/com/kingsrook/qqq/backend/core/actions/UpdateActionTest.java new file mode 100644 index 00000000..5ad5a990 --- /dev/null +++ b/src/test/java/com/kingsrook/qqq/backend/core/actions/UpdateActionTest.java @@ -0,0 +1,47 @@ +/* + * Copyright © 2021-2021. Kingsrook LLC . All Rights Reserved. + */ + +package com.kingsrook.qqq.backend.core.actions; + + +import java.util.ArrayList; +import java.util.List; +import com.kingsrook.qqq.backend.core.exceptions.QException; +import com.kingsrook.qqq.backend.core.model.actions.update.UpdateRequest; +import com.kingsrook.qqq.backend.core.model.actions.update.UpdateResult; +import com.kingsrook.qqq.backend.core.model.data.QRecord; +import com.kingsrook.qqq.backend.core.utils.TestUtils; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertNotNull; + + +/******************************************************************************* + ** Unit test for UpdateAction + ** + *******************************************************************************/ +class UpdateActionTest +{ + + /******************************************************************************* + ** At the core level, there isn't much that can be asserted, as it uses the + ** mock implementation - just confirming that all of the "wiring" works. + ** + *******************************************************************************/ + @Test + public void test() throws QException + { + UpdateRequest request = new UpdateRequest(TestUtils.defineInstance()); + request.setSession(TestUtils.getMockSession()); + request.setTableName("person"); + List records =new ArrayList<>(); + QRecord record = new QRecord(); + record.setValue("id", "47"); + record.setValue("firstName", "James"); + records.add(record); + request.setRecords(records); + UpdateResult result = new UpdateAction().execute(request); + assertNotNull(result); + } + +} diff --git a/src/test/java/com/kingsrook/qqq/backend/core/adapters/QInstanceAdapterTest.java b/src/test/java/com/kingsrook/qqq/backend/core/adapters/QInstanceAdapterTest.java new file mode 100644 index 00000000..e8dd95f2 --- /dev/null +++ b/src/test/java/com/kingsrook/qqq/backend/core/adapters/QInstanceAdapterTest.java @@ -0,0 +1,75 @@ +/* + * Copyright © 2021-2022. Kingsrook LLC . All Rights Reserved. + */ + +package com.kingsrook.qqq.backend.core.adapters; + + +import java.io.File; +import java.io.IOException; +import com.kingsrook.qqq.backend.core.model.metadata.QInstance; +import com.kingsrook.qqq.backend.core.utils.TestUtils; +import org.apache.commons.io.FileUtils; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + + +/******************************************************************************* + ** + *******************************************************************************/ +class QInstanceAdapterTest +{ + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void qInstanceToJson() + { + QInstance qInstance = TestUtils.defineInstance(); + String json = new QInstanceAdapter().qInstanceToJson(qInstance); + System.out.println(json); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void qInstanceToJsonIncludingBackend() + { + QInstance qInstance = TestUtils.defineInstance(); + String json = new QInstanceAdapter().qInstanceToJsonIncludingBackend(qInstance); + System.out.println(json); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void jsonToQInstance() throws IOException + { + String json = FileUtils.readFileToString(new File("src/test/resources/personQInstance.json")); + QInstance qInstance = new QInstanceAdapter().jsonToQInstance(json); + System.out.println(qInstance); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void jsonToQInstanceIncludingBackend() throws IOException + { + String json = FileUtils.readFileToString(new File("src/test/resources/personQInstanceIncludingBackend.json")); + QInstance qInstance = new QInstanceAdapter().jsonToQInstanceIncludingBackends(json); + System.out.println(qInstance); + assertNotNull(qInstance.getBackends()); + assertTrue(qInstance.getBackends().size() > 0); + } +} \ No newline at end of file diff --git a/src/test/java/com/kingsrook/qqq/backend/core/instances/QInstanceValidatorTest.java b/src/test/java/com/kingsrook/qqq/backend/core/instances/QInstanceValidatorTest.java index 230fd7e9..8b1c55fa 100644 --- a/src/test/java/com/kingsrook/qqq/backend/core/instances/QInstanceValidatorTest.java +++ b/src/test/java/com/kingsrook/qqq/backend/core/instances/QInstanceValidatorTest.java @@ -35,7 +35,7 @@ class QInstanceValidatorTest /******************************************************************************* - ** Test an instane with null backends - should throw. + ** Test an instance with null backends - should throw. ** *******************************************************************************/ @Test @@ -57,7 +57,7 @@ class QInstanceValidatorTest /******************************************************************************* - ** Test an instane with empty map of backends - should throw. + ** Test an instance with empty map of backends - should throw. ** *******************************************************************************/ @Test @@ -79,7 +79,7 @@ class QInstanceValidatorTest /******************************************************************************* - ** Test an instane with null tables - should throw. + ** Test an instance with null tables - should throw. ** *******************************************************************************/ @Test @@ -101,7 +101,7 @@ class QInstanceValidatorTest /******************************************************************************* - ** Test an instane with empty map of tables - should throw. + ** Test an instance with empty map of tables - should throw. ** *******************************************************************************/ @Test @@ -123,7 +123,7 @@ class QInstanceValidatorTest /******************************************************************************* - ** Test an instane where a table and a backend each have a name attribute that + ** Test an instance where a table and a backend each have a name attribute that ** doesn't match the key that those objects have in the instance's maps - should throw. ** *******************************************************************************/ @@ -191,6 +191,62 @@ class QInstanceValidatorTest + /******************************************************************************* + ** Test that a table with no fields fails. + ** + *******************************************************************************/ + @Test + public void test_validateTableWithNoFields() + { + try + { + QInstance qInstance = TestUtils.defineInstance(); + qInstance.getTable("person").setFields(null); + new QInstanceValidator().validate(qInstance); + fail("Should have thrown validationException"); + } + catch(QInstanceValidationException e) + { + assertReason("At least 1 field", e); + } + + try + { + QInstance qInstance = TestUtils.defineInstance(); + qInstance.getTable("person").setFields(new HashMap<>()); + new QInstanceValidator().validate(qInstance); + fail("Should have thrown validationException"); + } + catch(QInstanceValidationException e) + { + assertReason("At least 1 field", e); + } + } + + + + /******************************************************************************* + ** Test that if a field specifies a backend that doesn't exist, that it fails. + ** + *******************************************************************************/ + @Test + public void test_validateFieldWithMissingPossibleValueSource() + { + try + { + QInstance qInstance = TestUtils.defineInstance(); + qInstance.getTable("person").getField("homeState").setPossibleValueSourceName("not a real possible value source"); + new QInstanceValidator().validate(qInstance); + fail("Should have thrown validationException"); + } + catch(QInstanceValidationException e) + { + assertReason("Unrecognized possibleValueSourceName", e); + } + } + + + /******************************************************************************* ** utility method for asserting that a specific reason string is found within ** the list of reasons in the QInstanceValidationException. diff --git a/src/test/java/com/kingsrook/qqq/backend/core/modules/QAuthenticationModuleDispatcherTest.java b/src/test/java/com/kingsrook/qqq/backend/core/modules/QAuthenticationModuleDispatcherTest.java new file mode 100644 index 00000000..e617a963 --- /dev/null +++ b/src/test/java/com/kingsrook/qqq/backend/core/modules/QAuthenticationModuleDispatcherTest.java @@ -0,0 +1,78 @@ +/* + * Copyright © 2021-2021. Kingsrook LLC . All Rights Reserved. + */ + +package com.kingsrook.qqq.backend.core.modules; + + +import com.kingsrook.qqq.backend.core.exceptions.QModuleDispatchException; +import com.kingsrook.qqq.backend.core.model.metadata.QAuthenticationMetaData; +import com.kingsrook.qqq.backend.core.modules.interfaces.QAuthenticationModuleInterface; +import com.kingsrook.qqq.backend.core.utils.TestUtils; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + + +/******************************************************************************* + ** Unit test for QModuleDispatcher + ** + *******************************************************************************/ +class QAuthenticationModuleDispatcherTest +{ + + /******************************************************************************* + ** Test success case - a valid backend. + ** + *******************************************************************************/ + @Test + public void test_getQAuthenticationModule() throws QModuleDispatchException + { + QAuthenticationModuleInterface mock = new QAuthenticationModuleDispatcher().getQModule(TestUtils.defineAuthentication()); + assertNotNull(mock); + } + + + + /******************************************************************************* + ** Test success case - a valid backend. + ** + *******************************************************************************/ + @Test + public void test_getQAuthenticationModuleByType_valid() throws QModuleDispatchException + { + QAuthenticationModuleInterface mock = new QAuthenticationModuleDispatcher().getQModule("mock"); + assertNotNull(mock); + } + + + + /******************************************************************************* + ** Test failure case, a backend name that doesn't exist + ** + *******************************************************************************/ + @Test + public void test_getQAuthenticationModule_typeNotFound() + { + assertThrows(QModuleDispatchException.class, () -> + { + new QAuthenticationModuleDispatcher().getQModule("aTypeThatWontExist"); + }); + } + + + + /******************************************************************************* + ** Test failure case, null argument + ** + *******************************************************************************/ + @Test + public void test_getQAuthenticationModule_nullArgument() + { + assertThrows(QModuleDispatchException.class, () -> + { + new QAuthenticationModuleDispatcher().getQModule((QAuthenticationMetaData) null); + }); + } + +} diff --git a/src/test/java/com/kingsrook/qqq/backend/core/utils/JsonUtilsTest.java b/src/test/java/com/kingsrook/qqq/backend/core/utils/JsonUtilsTest.java index 3929bf57..a70b4a8d 100644 --- a/src/test/java/com/kingsrook/qqq/backend/core/utils/JsonUtilsTest.java +++ b/src/test/java/com/kingsrook/qqq/backend/core/utils/JsonUtilsTest.java @@ -44,7 +44,7 @@ class JsonUtilsTest { QRecord qRecord = getQRecord(); String json = JsonUtils.toJson(qRecord); - assertEquals("{\"tableName\":\"foo\",\"primaryKey\":1,\"values\":{\"foo\":\"Foo\",\"bar\":3.14159}}", json); + assertEquals("{\"tableName\":\"foo\",\"values\":{\"foo\":\"Foo\",\"bar\":3.14159},\"displayValues\":{}}", json); } @@ -188,7 +188,7 @@ class JsonUtilsTest { QRecord qRecord = new QRecord(); qRecord.setTableName("foo"); - qRecord.setPrimaryKey(1); + qRecord.setValue("id", 1); Map values = new LinkedHashMap<>(); qRecord.setValues(values); values.put("foo", "Foo"); diff --git a/src/test/java/com/kingsrook/qqq/backend/core/utils/TestUtils.java b/src/test/java/com/kingsrook/qqq/backend/core/utils/TestUtils.java index 85126407..577d4dd3 100644 --- a/src/test/java/com/kingsrook/qqq/backend/core/utils/TestUtils.java +++ b/src/test/java/com/kingsrook/qqq/backend/core/utils/TestUtils.java @@ -15,6 +15,8 @@ import com.kingsrook.qqq.backend.core.model.metadata.QFieldMetaData; import com.kingsrook.qqq.backend.core.model.metadata.QFieldType; import com.kingsrook.qqq.backend.core.model.metadata.QInstance; import com.kingsrook.qqq.backend.core.model.metadata.QTableMetaData; +import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.QPossibleValueSource; +import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.QPossibleValueSourceType; import com.kingsrook.qqq.backend.core.model.metadata.processes.QFunctionInputMetaData; import com.kingsrook.qqq.backend.core.model.metadata.processes.QFunctionMetaData; import com.kingsrook.qqq.backend.core.model.metadata.processes.QFunctionOutputMetaData; @@ -42,17 +44,32 @@ public class TestUtils qInstance.setAuthentication(defineAuthentication()); qInstance.addBackend(defineBackend()); qInstance.addTable(defineTablePerson()); + qInstance.addPossibleValueSource(defineStatesPossibleValueSource()); qInstance.addProcess(defineProcessGreetPeople()); return (qInstance); } + /******************************************************************************* + ** Define the "states" possible value source used in standard tests + ** + *******************************************************************************/ + private static QPossibleValueSource defineStatesPossibleValueSource() + { + return new QPossibleValueSource() + .withName("state") + .withType(QPossibleValueSourceType.ENUM) + .withEnumValues(List.of("IL", "MO")); + } + + + /******************************************************************************* ** Define the authentication used in standard tests - using 'mock' type. ** *******************************************************************************/ - private static QAuthenticationMetaData defineAuthentication() + public static QAuthenticationMetaData defineAuthentication() { return new QAuthenticationMetaData() .withName("mock") @@ -89,7 +106,8 @@ public class TestUtils .withField(new QFieldMetaData("firstName", QFieldType.STRING)) .withField(new QFieldMetaData("lastName", QFieldType.STRING)) .withField(new QFieldMetaData("birthDate", QFieldType.DATE)) - .withField(new QFieldMetaData("email", QFieldType.STRING)); + .withField(new QFieldMetaData("email", QFieldType.STRING)) + .withField(new QFieldMetaData("homeState", QFieldType.STRING).withPossibleValueSourceName("state")); } diff --git a/src/test/resources/personQInstance.json b/src/test/resources/personQInstance.json new file mode 100644 index 00000000..250e5f57 --- /dev/null +++ b/src/test/resources/personQInstance.json @@ -0,0 +1,156 @@ +{ + "authentication": { + "name": "mock", + "type": "mock", + "values": null + }, + "tables": { + "person": { + "name": "person", + "label": "Person", + "backendName": "default", + "primaryKeyField": "id", + "fields": { + "id": { + "name": "id", + "label": null, + "backendName": null, + "type": "INTEGER", + "possibleValueSourceName": null + }, + "createDate": { + "name": "createDate", + "label": null, + "backendName": null, + "type": "DATE_TIME", + "possibleValueSourceName": null + }, + "modifyDate": { + "name": "modifyDate", + "label": null, + "backendName": null, + "type": "DATE_TIME", + "possibleValueSourceName": null + }, + "firstName": { + "name": "firstName", + "label": null, + "backendName": null, + "type": "STRING", + "possibleValueSourceName": null + }, + "lastName": { + "name": "lastName", + "label": null, + "backendName": null, + "type": "STRING", + "possibleValueSourceName": null + }, + "birthDate": { + "name": "birthDate", + "label": null, + "backendName": null, + "type": "DATE", + "possibleValueSourceName": null + }, + "email": { + "name": "email", + "label": null, + "backendName": null, + "type": "STRING", + "possibleValueSourceName": null + }, + "homeState": { + "name": "homeState", + "label": null, + "backendName": null, + "type": "STRING", + "possibleValueSourceName": "state" + } + } + } + }, + "possibleValueSources": { + "state": { + "name": "state", + "type": "ENUM", + "enumValues": [ + "IL", + "MO" + ] + } + }, + "processes": { + "greet": { + "name": "greet", + "tableName": "person", + "functionList": [ + { + "name": "prepare", + "label": null, + "inputMetaData": { + "recordListMetaData": { + "tableName": "person", + "fields": null + }, + "fieldList": [ + { + "name": "greetingPrefix", + "label": null, + "backendName": null, + "type": "STRING", + "possibleValueSourceName": null + }, + { + "name": "greetingSuffix", + "label": null, + "backendName": null, + "type": "STRING", + "possibleValueSourceName": null + } + ] + }, + "outputMetaData": { + "recordListMetaData": { + "tableName": "person", + "fields": { + "fullGreeting": { + "name": "fullGreeting", + "label": null, + "backendName": null, + "type": "STRING", + "possibleValueSourceName": null + } + } + }, + "fieldList": [ + { + "name": "outputMessage", + "label": null, + "backendName": null, + "type": "STRING", + "possibleValueSourceName": null + } + ] + }, + "code": { + "name": "com.kingsrook.qqq.backend.core.interfaces.mock.MockFunctionBody", + "codeType": "JAVA", + "codeUsage": "FUNCTION" + }, + "outputView": { + "messageField": "outputMessage", + "recordListView": { + "fieldNames": [ + "id", + "firstName", + "lastName", + "fullGreeting" + ] + } + } + } + ] + } + } +} \ No newline at end of file diff --git a/src/test/resources/personQInstanceIncludingBackend.json b/src/test/resources/personQInstanceIncludingBackend.json new file mode 100644 index 00000000..74095833 --- /dev/null +++ b/src/test/resources/personQInstanceIncludingBackend.json @@ -0,0 +1,163 @@ +{ + "tables": { + "person": { + "primaryKeyField": "id", + "name": "person", + "backendName": "default", + "label": "Person", + "fields": { + "firstName": { + "name": "firstName", + "backendName": null, + "label": null, + "type": "STRING", + "possibleValueSourceName": null + }, + "lastName": { + "name": "lastName", + "backendName": null, + "label": null, + "type": "STRING", + "possibleValueSourceName": null + }, + "modifyDate": { + "name": "modifyDate", + "backendName": null, + "label": null, + "type": "DATE_TIME", + "possibleValueSourceName": null + }, + "homeState": { + "name": "homeState", + "backendName": null, + "label": null, + "type": "STRING", + "possibleValueSourceName": "state" + }, + "id": { + "name": "id", + "backendName": null, + "label": null, + "type": "INTEGER", + "possibleValueSourceName": null + }, + "birthDate": { + "name": "birthDate", + "backendName": null, + "label": null, + "type": "DATE", + "possibleValueSourceName": null + }, + "email": { + "name": "email", + "backendName": null, + "label": null, + "type": "STRING", + "possibleValueSourceName": null + }, + "createDate": { + "name": "createDate", + "backendName": null, + "label": null, + "type": "DATE_TIME", + "possibleValueSourceName": null + } + } + } + }, + "processes": { + "greet": { + "functionList": [ + { + "code": { + "codeUsage": "FUNCTION", + "codeType": "JAVA", + "name": "com.kingsrook.qqq.backend.core.interfaces.mock.MockFunctionBody" + }, + "inputMetaData": { + "recordListMetaData": { + "fields": null, + "tableName": "person" + }, + "fieldList": [ + { + "name": "greetingPrefix", + "backendName": null, + "label": null, + "type": "STRING", + "possibleValueSourceName": null + }, + { + "name": "greetingSuffix", + "backendName": null, + "label": null, + "type": "STRING", + "possibleValueSourceName": null + } + ] + }, + "outputMetaData": { + "recordListMetaData": { + "fields": { + "fullGreeting": { + "name": "fullGreeting", + "backendName": null, + "label": null, + "type": "STRING", + "possibleValueSourceName": null + } + }, + "tableName": "person" + }, + "fieldList": [ + { + "name": "outputMessage", + "backendName": null, + "label": null, + "type": "STRING", + "possibleValueSourceName": null + } + ] + }, + "outputView": { + "messageField": "outputMessage", + "recordListView": { + "fieldNames": [ + "id", + "firstName", + "lastName", + "fullGreeting" + ] + } + }, + "name": "prepare", + "label": null + } + ], + "name": "greet", + "tableName": "person" + } + }, + "possibleValueSources": { + "state": { + "name": "state", + "type": "ENUM", + "enumValues": [ + "IL", + "MO" + ] + } + }, + "backends": { + "default": { + "values": null, + "name": "default", + "type": "mock" + } + }, + "authentication": { + "values": null, + "name": "mock", + "type": "mock" + } +} \ No newline at end of file