From 68686c0e17712154d7d61b838f044a891fd588a3 Mon Sep 17 00:00:00 2001 From: Darin Kelkhoff Date: Mon, 6 Mar 2023 09:40:15 -0600 Subject: [PATCH] Checkpoint --- .../RunRecordScriptsAutomationHandler.java | 89 +++++++ .../scripts/RunAdHocRecordScriptAction.java | 138 +++++++--- .../core/actions/scripts/ScriptApi.java | 237 ++++++++++++++++++ .../core/actions/scripts/ScriptApiUtils.java | 111 -------- .../scripts/RunAdHocRecordScriptInput.java | 98 +++++--- .../code/AdHocScriptCodeReference.java | 72 ++++++ ...esPossibleValueSourceMetaDataProvider.java | 12 +- .../scripts/ScriptsMetaDataProvider.java | 25 ++ .../RunAdHocRecordScriptActionTest.java | 2 +- 9 files changed, 601 insertions(+), 183 deletions(-) create mode 100644 qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/automation/RunRecordScriptsAutomationHandler.java create mode 100644 qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/scripts/ScriptApi.java delete mode 100644 qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/scripts/ScriptApiUtils.java diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/automation/RunRecordScriptsAutomationHandler.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/automation/RunRecordScriptsAutomationHandler.java new file mode 100644 index 00000000..dfb75ca6 --- /dev/null +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/automation/RunRecordScriptsAutomationHandler.java @@ -0,0 +1,89 @@ +/* + * 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 . + */ + +package com.kingsrook.qqq.backend.core.actions.automation; + + +import com.kingsrook.qqq.backend.core.actions.scripts.RunAdHocRecordScriptAction; +import com.kingsrook.qqq.backend.core.actions.tables.QueryAction; +import com.kingsrook.qqq.backend.core.context.QContext; +import com.kingsrook.qqq.backend.core.exceptions.QException; +import com.kingsrook.qqq.backend.core.logging.QLogger; +import com.kingsrook.qqq.backend.core.model.actions.scripts.RunAdHocRecordScriptInput; +import com.kingsrook.qqq.backend.core.model.actions.scripts.RunAdHocRecordScriptOutput; +import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator; +import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria; +import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter; +import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput; +import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryJoin; +import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput; +import com.kingsrook.qqq.backend.core.model.automation.RecordAutomationInput; +import com.kingsrook.qqq.backend.core.model.data.QRecord; +import com.kingsrook.qqq.backend.core.model.metadata.code.AdHocScriptCodeReference; +import com.kingsrook.qqq.backend.core.model.scripts.Script; +import com.kingsrook.qqq.backend.core.model.scripts.ScriptRevision; +import com.kingsrook.qqq.backend.core.model.scripts.ScriptType; +import com.kingsrook.qqq.backend.core.utils.CollectionUtils; +import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair; + + +/******************************************************************************* + ** + *******************************************************************************/ +public class RunRecordScriptsAutomationHandler extends RecordAutomationHandler +{ + private static final QLogger LOG = QLogger.getLogger(RunRecordScriptsAutomationHandler.class); + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Override + public void execute(RecordAutomationInput recordAutomationInput) throws QException + { + String tableName = recordAutomationInput.getTableName(); + QueryInput queryInput = new QueryInput(); + queryInput.setTableName(ScriptRevision.TABLE_NAME); + queryInput.setFilter(new QQueryFilter( + new QFilterCriteria("script.tableName", QCriteriaOperator.EQUALS, tableName), + new QFilterCriteria("scriptType.name", QCriteriaOperator.EQUALS, "Record Script") // todo... no. something about post-insert/update? + )); + queryInput.withQueryJoin(new QueryJoin(Script.TABLE_NAME).withBaseTableOrAlias(ScriptRevision.TABLE_NAME).withJoinMetaData(QContext.getQInstance().getJoin("currentScriptRevision"))); + queryInput.withQueryJoin(new QueryJoin(ScriptType.TABLE_NAME).withBaseTableOrAlias(Script.TABLE_NAME)); + + QueryOutput queryOutput = new QueryAction().execute(queryInput); + for(QRecord scriptRevision : CollectionUtils.nonNullList(queryOutput.getRecords())) + { + // todo - refresh the records if more than 1 script + + LOG.info("Running script against records", logPair("scriptRevisionId", scriptRevision.getValue("id")), logPair("scriptId", scriptRevision.getValue("scriptIdd"))); + RunAdHocRecordScriptInput input = new RunAdHocRecordScriptInput(); + input.setCodeReference(new AdHocScriptCodeReference().withScriptRevisionRecord(scriptRevision)); + input.setTableName(tableName); + input.setRecordList(recordAutomationInput.getRecordList()); + RunAdHocRecordScriptOutput output = new RunAdHocRecordScriptOutput(); + new RunAdHocRecordScriptAction().run(input, output); + } + + } + +} diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/scripts/RunAdHocRecordScriptAction.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/scripts/RunAdHocRecordScriptAction.java index 4ec61c9a..5c00eae3 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/scripts/RunAdHocRecordScriptAction.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/scripts/RunAdHocRecordScriptAction.java @@ -23,25 +23,38 @@ package com.kingsrook.qqq.backend.core.actions.scripts; import java.io.Serializable; +import java.util.ArrayList; import java.util.HashMap; +import java.util.Map; import java.util.Objects; import com.kingsrook.qqq.backend.core.actions.ActionHelper; import com.kingsrook.qqq.backend.core.actions.scripts.logging.QCodeExecutionLoggerInterface; import com.kingsrook.qqq.backend.core.actions.scripts.logging.ScriptExecutionLoggerInterface; import com.kingsrook.qqq.backend.core.actions.scripts.logging.StoreScriptLogAndScriptLogLineExecutionLogger; import com.kingsrook.qqq.backend.core.actions.tables.GetAction; +import com.kingsrook.qqq.backend.core.actions.tables.QueryAction; +import com.kingsrook.qqq.backend.core.context.QContext; import com.kingsrook.qqq.backend.core.exceptions.QException; +import com.kingsrook.qqq.backend.core.logging.QLogger; import com.kingsrook.qqq.backend.core.model.actions.scripts.ExecuteCodeInput; import com.kingsrook.qqq.backend.core.model.actions.scripts.ExecuteCodeOutput; import com.kingsrook.qqq.backend.core.model.actions.scripts.RunAdHocRecordScriptInput; import com.kingsrook.qqq.backend.core.model.actions.scripts.RunAdHocRecordScriptOutput; import com.kingsrook.qqq.backend.core.model.actions.tables.get.GetInput; import com.kingsrook.qqq.backend.core.model.actions.tables.get.GetOutput; -import com.kingsrook.qqq.backend.core.model.data.QRecord; +import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator; +import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria; +import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter; +import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput; +import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryJoin; +import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput; +import com.kingsrook.qqq.backend.core.model.metadata.code.AdHocScriptCodeReference; import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference; import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeType; +import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData; import com.kingsrook.qqq.backend.core.model.scripts.Script; import com.kingsrook.qqq.backend.core.model.scripts.ScriptRevision; +import com.kingsrook.qqq.backend.core.utils.CollectionUtils; /******************************************************************************* @@ -49,7 +62,10 @@ import com.kingsrook.qqq.backend.core.model.scripts.ScriptRevision; *******************************************************************************/ public class RunAdHocRecordScriptAction { - // todo! private Map scriptRevisionCache = new HashMap<>(); + private static final QLogger LOG = QLogger.getLogger(RunAdHocRecordScriptAction.class); + + private Map scriptRevisionCacheByScriptRevisionId = new HashMap<>(); + private Map scriptRevisionCacheByScriptId = new HashMap<>(); @@ -60,18 +76,43 @@ public class RunAdHocRecordScriptAction { ActionHelper.validateSession(input); + ///////////////////////// + // figure out the code // + ///////////////////////// ScriptRevision scriptRevision = getScriptRevision(input); + if(scriptRevision == null) + { + throw (new QException("Script revision was not found.")); + } - GetInput getInput = new GetInput(); - getInput.setTableName(input.getTableName()); - getInput.setPrimaryKey(input.getRecordPrimaryKey()); - GetOutput getOutput = new GetAction().execute(getInput); - QRecord record = getOutput.getRecord(); - // todo err if not found + //////////////////////////// + // figure out the records // + //////////////////////////// + QTableMetaData table = QContext.getQInstance().getTable(input.getTableName()); + if(CollectionUtils.nullSafeIsEmpty(input.getRecordList())) + { + QueryInput queryInput = new QueryInput(); + queryInput.setTableName(input.getTableName()); + queryInput.setFilter(new QQueryFilter(new QFilterCriteria(table.getPrimaryKeyField(), QCriteriaOperator.IN, input.getRecordPrimaryKeyList()))); + QueryOutput queryOutput = new QueryAction().execute(queryInput); + input.setRecordList(queryOutput.getRecords()); + } + if(CollectionUtils.nullSafeIsEmpty(input.getRecordList())) + { + //////////////////////////////////////// + // just return if nothing found? idk // + //////////////////////////////////////// + LOG.info("No records supplied as input (or found via primary keys); exiting with noop"); + return; + } + + ///////////// + // run it! // + ///////////// ExecuteCodeInput executeCodeInput = new ExecuteCodeInput(); executeCodeInput.setInput(new HashMap<>(Objects.requireNonNullElseGet(input.getInputValues(), HashMap::new))); - executeCodeInput.getInput().put("record", record); + executeCodeInput.getInput().put("records", new ArrayList<>(input.getRecordList())); executeCodeInput.setContext(new HashMap<>()); if(input.getOutputObject() != null) { @@ -82,10 +123,8 @@ public class RunAdHocRecordScriptAction { executeCodeInput.getContext().put("scriptUtils", input.getScriptUtils()); } - else - { - executeCodeInput.getContext().put("scriptUtils", new ScriptApiUtils()); - } + + executeCodeInput.getContext().put("api", new ScriptApi()); executeCodeInput.setCodeReference(new QCodeReference().withInlineCode(scriptRevision.getContents()).withCodeType(QCodeType.JAVA_SCRIPT)); // todo - code type as attribute of script!! @@ -116,34 +155,57 @@ public class RunAdHocRecordScriptAction *******************************************************************************/ private ScriptRevision getScriptRevision(RunAdHocRecordScriptInput input) throws QException { - // todo if(!scriptRevisionCache.containsKey(input.getCodeReference())) + AdHocScriptCodeReference codeReference = input.getCodeReference(); + if(codeReference.getScriptRevisionRecord() != null) { - Serializable scriptId = input.getCodeReference().getScriptId(); - /* - if(scriptId == null) - { - throw (new QNotFoundException("The input record [" + input.getCodeReference().getScriptId() + "][" + input.getCodeReference().getRecordPrimaryKey() - + "] does not have a script specified for [" + input.getCodeReference().getFieldName() + "]")); - } - - */ - - Script script = getScript(input, scriptId); - /* todo - if(script.getCurrentScriptRevisionId() == null) - { - throw (new QNotFoundException("The script for record [" + input.getCodeReference().getRecordTable() + "][" + input.getCodeReference().getRecordPrimaryKey() - + "] (scriptId=" + scriptId + ") does not have a current version.")); - } - - */ - - ScriptRevision scriptRevision = getCurrentScriptRevision(input, script.getCurrentScriptRevisionId()); - // scriptRevisionCache.put(input.getCodeReference(), scriptRevision); - return scriptRevision; + return (new ScriptRevision(codeReference.getScriptRevisionRecord())); } - // return scriptRevisionCache.get(input.getCodeReference()); + if(codeReference.getScriptRevisionId() != null) + { + if(!scriptRevisionCacheByScriptRevisionId.containsKey(codeReference.getScriptRevisionId())) + { + GetInput getInput = new GetInput(); + getInput.setTableName(ScriptRevision.TABLE_NAME); + getInput.setPrimaryKey(codeReference.getScriptRevisionId()); + GetOutput getOutput = new GetAction().execute(getInput); + if(getOutput.getRecord() != null) + { + scriptRevisionCacheByScriptRevisionId.put(codeReference.getScriptRevisionId(), new ScriptRevision(getOutput.getRecord())); + } + else + { + scriptRevisionCacheByScriptRevisionId.put(codeReference.getScriptRevisionId(), null); + } + } + + return (scriptRevisionCacheByScriptRevisionId.get(codeReference.getScriptRevisionId())); + } + + if(codeReference.getScriptId() != null) + { + if(!scriptRevisionCacheByScriptId.containsKey(codeReference.getScriptId())) + { + QueryInput queryInput = new QueryInput(); + queryInput.setTableName(ScriptRevision.TABLE_NAME); + queryInput.setFilter(new QQueryFilter(new QFilterCriteria("script.id", QCriteriaOperator.EQUALS, codeReference.getScriptId()))); + queryInput.withQueryJoin(new QueryJoin(Script.TABLE_NAME).withBaseTableOrAlias(ScriptRevision.TABLE_NAME).withJoinMetaData(QContext.getQInstance().getJoin("currentScriptRevision"))); + QueryOutput queryOutput = new QueryAction().execute(queryInput); + + if(CollectionUtils.nullSafeHasContents(queryOutput.getRecords())) + { + scriptRevisionCacheByScriptId.put(codeReference.getScriptId(), new ScriptRevision(queryOutput.getRecords().get(0))); + } + else + { + scriptRevisionCacheByScriptId.put(codeReference.getScriptId(), null); + } + } + + return (scriptRevisionCacheByScriptId.get(codeReference.getScriptId())); + } + + throw (new QException("Code reference did not contain a scriptRevision, scriptRevisionId, or scriptId")); } diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/scripts/ScriptApi.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/scripts/ScriptApi.java new file mode 100644 index 00000000..ad560f1f --- /dev/null +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/scripts/ScriptApi.java @@ -0,0 +1,237 @@ +/* + * 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 . + */ + +package com.kingsrook.qqq.backend.core.actions.scripts; + + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +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.DeleteAction; +import com.kingsrook.qqq.backend.core.actions.tables.InsertAction; +import com.kingsrook.qqq.backend.core.actions.tables.QueryAction; +import com.kingsrook.qqq.backend.core.actions.tables.UpdateAction; +import com.kingsrook.qqq.backend.core.context.QContext; +import com.kingsrook.qqq.backend.core.exceptions.QException; +import com.kingsrook.qqq.backend.core.model.actions.tables.delete.DeleteInput; +import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput; +import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria; +import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterOrderBy; +import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter; +import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput; +import com.kingsrook.qqq.backend.core.model.actions.tables.update.UpdateInput; +import com.kingsrook.qqq.backend.core.model.data.QRecord; +import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData; + + +/******************************************************************************* + + $api.query("order", null); + $api.query($utils.newQueryInput().withTable("order").withLimit(1).withShouldGenerateDisplayValues()) + *******************************************************************************/ +public class ScriptApi implements Serializable +{ + + /******************************************************************************* + ** + *******************************************************************************/ + public QueryInput newQueryInput() + { + return (new QueryInput()); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + public QQueryFilter newQueryFilter() + { + return (new QQueryFilter()); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + public QFilterCriteria newFilterCriteria() + { + return (new QFilterCriteria()); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + public QFilterOrderBy newFilterOrderBy() + { + return (new QFilterOrderBy()); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + public QRecord newRecord() + { + return (new QRecord()); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + public List query(String tableName, QQueryFilter filter) throws QException + { + QueryInput queryInput = new QueryInput(); + queryInput.setTableName(tableName); + queryInput.setFilter(filter); + PermissionsHelper.checkTablePermissionThrowing(queryInput, TablePermissionSubType.READ); + return (new QueryAction().execute(queryInput).getRecords()); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + public List query(QueryInput queryInput) throws QException + { + PermissionsHelper.checkTablePermissionThrowing(queryInput, TablePermissionSubType.READ); + return (new QueryAction().execute(queryInput).getRecords()); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + public void insert(String tableName, QRecord record) throws QException + { + insert(tableName, List.of(record)); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + public void insert(String tableName, List recordList) throws QException + { + InsertInput insertInput = new InsertInput(); + insertInput.setTableName(tableName); + insertInput.setRecords(recordList); + PermissionsHelper.checkTablePermissionThrowing(insertInput, TablePermissionSubType.INSERT); + new InsertAction().execute(insertInput); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + public void update(String tableName, QRecord record) throws QException + { + update(tableName, List.of(record)); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + public void update(String tableName, List recordList) throws QException + { + UpdateInput updateInput = new UpdateInput(); + updateInput.setTableName(tableName); + updateInput.setRecords(recordList); + PermissionsHelper.checkTablePermissionThrowing(updateInput, TablePermissionSubType.EDIT); + new UpdateAction().execute(updateInput); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + public void delete(String tableName, Serializable primaryKey) throws QException + { + delete(tableName, List.of(primaryKey)); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + public void delete(String tableName, QRecord record) throws QException + { + delete(tableName, List.of(record)); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + public void delete(String tableName, List recordOrPrimaryKeyList) throws QException + { + QTableMetaData table = QContext.getQInstance().getTable(tableName); + DeleteInput deleteInput = new DeleteInput(); + deleteInput.setTableName(tableName); + List primaryKeyList = new ArrayList<>(); + for(Object o : recordOrPrimaryKeyList) + { + if(o instanceof QRecord qRecord) + { + primaryKeyList.add(qRecord.getValue(table.getPrimaryKeyField())); + } + else + { + primaryKeyList.add((Serializable) o); + } + } + deleteInput.setPrimaryKeys(primaryKeyList); + PermissionsHelper.checkTablePermissionThrowing(deleteInput, TablePermissionSubType.DELETE); + new DeleteAction().execute(deleteInput); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + public void delete(String tableName, QQueryFilter filter) throws QException + { + DeleteInput deleteInput = new DeleteInput(); + deleteInput.setTableName(tableName); + deleteInput.setQueryFilter(filter); + PermissionsHelper.checkTablePermissionThrowing(deleteInput, TablePermissionSubType.DELETE); + new DeleteAction().execute(deleteInput); + } + +} diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/scripts/ScriptApiUtils.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/scripts/ScriptApiUtils.java deleted file mode 100644 index d4b5631e..00000000 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/scripts/ScriptApiUtils.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * 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 . - */ - -package com.kingsrook.qqq.backend.core.actions.scripts; - - -import java.io.Serializable; -import java.util.List; -import com.kingsrook.qqq.backend.core.actions.tables.QueryAction; -import com.kingsrook.qqq.backend.core.actions.tables.UpdateAction; -import com.kingsrook.qqq.backend.core.exceptions.QException; -import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter; -import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput; -import com.kingsrook.qqq.backend.core.model.actions.tables.update.UpdateInput; -import com.kingsrook.qqq.backend.core.model.data.QRecord; - - -/******************************************************************************* - - $utils.query("order", null); - $utils.query($utils.newQueryInput().withTable("order").withLimit(1).withShouldGenerateDisplayValues()) - *******************************************************************************/ -public class ScriptApiUtils implements Serializable -{ - - /******************************************************************************* - ** - *******************************************************************************/ - public QueryInput newQueryInput() - { - return (new QueryInput()); - } - - - - /******************************************************************************* - ** - *******************************************************************************/ - public QRecord newQRecord() - { - return (new QRecord()); - } - - - - /******************************************************************************* - ** - *******************************************************************************/ - public List query(String table, QQueryFilter filter) throws QException - { - QueryInput queryInput = new QueryInput(); - queryInput.setTableName(table); - queryInput.setFilter(filter); - return (new QueryAction().execute(queryInput).getRecords()); - } - - - - /******************************************************************************* - ** - *******************************************************************************/ - public List query(QueryInput queryInput) throws QException - { - return (new QueryAction().execute(queryInput).getRecords()); - } - - - - /******************************************************************************* - ** - *******************************************************************************/ - public void update(String table, List recordList) throws QException - { - UpdateInput updateInput = new UpdateInput(); - updateInput.setTableName(table); - updateInput.setRecords(recordList); - new UpdateAction().execute(updateInput); - } - - - - /******************************************************************************* - ** - *******************************************************************************/ - public void update(String table, QRecord record) throws QException - { - UpdateInput updateInput = new UpdateInput(); - updateInput.setTableName(table); - updateInput.setRecords(List.of(record)); - new UpdateAction().execute(updateInput); - } - -} diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/scripts/RunAdHocRecordScriptInput.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/scripts/RunAdHocRecordScriptInput.java index 971ff4c0..cf097f4f 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/scripts/RunAdHocRecordScriptInput.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/scripts/RunAdHocRecordScriptInput.java @@ -23,9 +23,11 @@ package com.kingsrook.qqq.backend.core.model.actions.scripts; import java.io.Serializable; +import java.util.List; import java.util.Map; import com.kingsrook.qqq.backend.core.actions.scripts.logging.QCodeExecutionLoggerInterface; import com.kingsrook.qqq.backend.core.model.actions.AbstractTableActionInput; +import com.kingsrook.qqq.backend.core.model.data.QRecord; import com.kingsrook.qqq.backend.core.model.metadata.code.AdHocScriptCodeReference; @@ -36,7 +38,8 @@ public class RunAdHocRecordScriptInput extends AbstractTableActionInput { private AdHocScriptCodeReference codeReference; private Map inputValues; - private Serializable recordPrimaryKey; + private List recordPrimaryKeyList; // can either supply recordList, or recordPrimaryKeyList + private List recordList; private String tableName; private QCodeExecutionLoggerInterface logger; @@ -207,37 +210,6 @@ public class RunAdHocRecordScriptInput extends AbstractTableActionInput - /******************************************************************************* - ** Getter for recordPrimaryKey - *******************************************************************************/ - public Serializable getRecordPrimaryKey() - { - return (this.recordPrimaryKey); - } - - - - /******************************************************************************* - ** Setter for recordPrimaryKey - *******************************************************************************/ - public void setRecordPrimaryKey(Serializable recordPrimaryKey) - { - this.recordPrimaryKey = recordPrimaryKey; - } - - - - /******************************************************************************* - ** Fluent setter for recordPrimaryKey - *******************************************************************************/ - public RunAdHocRecordScriptInput withRecordPrimaryKey(Serializable recordPrimaryKey) - { - this.recordPrimaryKey = recordPrimaryKey; - return (this); - } - - - /******************************************************************************* ** Getter for tableName *******************************************************************************/ @@ -267,4 +239,66 @@ public class RunAdHocRecordScriptInput extends AbstractTableActionInput return (this); } + + + /******************************************************************************* + ** Getter for recordList + *******************************************************************************/ + public List getRecordList() + { + return (this.recordList); + } + + + + /******************************************************************************* + ** Setter for recordList + *******************************************************************************/ + public void setRecordList(List recordList) + { + this.recordList = recordList; + } + + + + /******************************************************************************* + ** Fluent setter for recordList + *******************************************************************************/ + public RunAdHocRecordScriptInput withRecordList(List recordList) + { + this.recordList = recordList; + return (this); + } + + + + /******************************************************************************* + ** Getter for recordPrimaryKeyList + *******************************************************************************/ + public List getRecordPrimaryKeyList() + { + return (this.recordPrimaryKeyList); + } + + + + /******************************************************************************* + ** Setter for recordPrimaryKeyList + *******************************************************************************/ + public void setRecordPrimaryKeyList(List recordPrimaryKeyList) + { + this.recordPrimaryKeyList = recordPrimaryKeyList; + } + + + + /******************************************************************************* + ** Fluent setter for recordPrimaryKeyList + *******************************************************************************/ + public RunAdHocRecordScriptInput withRecordPrimaryKeyList(List recordPrimaryKeyList) + { + this.recordPrimaryKeyList = recordPrimaryKeyList; + return (this); + } + } diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/code/AdHocScriptCodeReference.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/code/AdHocScriptCodeReference.java index bab3cc69..02441950 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/code/AdHocScriptCodeReference.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/code/AdHocScriptCodeReference.java @@ -22,12 +22,22 @@ package com.kingsrook.qqq.backend.core.model.metadata.code; +import com.kingsrook.qqq.backend.core.model.data.QRecord; + + /******************************************************************************* ** *******************************************************************************/ public class AdHocScriptCodeReference extends QCodeReference { + //////////////////////////////////////////////////////////////////////////////// + // can supply scriptId (in which case, current revisionId will be looked up), // + // or revisionId (in which case, record will be looked up) // + // or, the record. // + //////////////////////////////////////////////////////////////////////////////// private Integer scriptId; + private Integer scriptRevisionId; + private QRecord scriptRevisionRecord; @@ -60,4 +70,66 @@ public class AdHocScriptCodeReference extends QCodeReference return (this); } + + + /******************************************************************************* + ** Getter for scriptRevisionId + *******************************************************************************/ + public Integer getScriptRevisionId() + { + return (this.scriptRevisionId); + } + + + + /******************************************************************************* + ** Setter for scriptRevisionId + *******************************************************************************/ + public void setScriptRevisionId(Integer scriptRevisionId) + { + this.scriptRevisionId = scriptRevisionId; + } + + + + /******************************************************************************* + ** Fluent setter for scriptRevisionId + *******************************************************************************/ + public AdHocScriptCodeReference withScriptRevisionId(Integer scriptRevisionId) + { + this.scriptRevisionId = scriptRevisionId; + return (this); + } + + + + /******************************************************************************* + ** Getter for scriptRevisionRecord + *******************************************************************************/ + public QRecord getScriptRevisionRecord() + { + return (this.scriptRevisionRecord); + } + + + + /******************************************************************************* + ** Setter for scriptRevisionRecord + *******************************************************************************/ + public void setScriptRevisionRecord(QRecord scriptRevisionRecord) + { + this.scriptRevisionRecord = scriptRevisionRecord; + } + + + + /******************************************************************************* + ** Fluent setter for scriptRevisionRecord + *******************************************************************************/ + public AdHocScriptCodeReference withScriptRevisionRecord(QRecord scriptRevisionRecord) + { + this.scriptRevisionRecord = scriptRevisionRecord; + return (this); + } + } diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/tables/TablesPossibleValueSourceMetaDataProvider.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/tables/TablesPossibleValueSourceMetaDataProvider.java index bb8f6a26..27cce6df 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/tables/TablesPossibleValueSourceMetaDataProvider.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/tables/TablesPossibleValueSourceMetaDataProvider.java @@ -23,12 +23,16 @@ package com.kingsrook.qqq.backend.core.model.metadata.tables; import java.util.ArrayList; +import java.util.Comparator; import java.util.List; +import com.kingsrook.qqq.backend.core.instances.QInstanceEnricher; import com.kingsrook.qqq.backend.core.model.metadata.QInstance; import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.PVSValueFormatAndFields; import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.QPossibleValue; 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.utils.StringUtils; +import org.apache.commons.lang.BooleanUtils; /******************************************************************************* @@ -53,9 +57,15 @@ public class TablesPossibleValueSourceMetaDataProvider List> enumValues = new ArrayList<>(); for(QTableMetaData table : qInstance.getTables().values()) { - enumValues.add(new QPossibleValue<>(table.getName(), table.getLabel())); + if(BooleanUtils.isNotTrue(table.getIsHidden())) + { + String label = StringUtils.hasContent(table.getLabel()) ? table.getLabel() : QInstanceEnricher.nameToLabel(table.getName()); + enumValues.add(new QPossibleValue<>(table.getName(), label)); + } } + enumValues.sort(Comparator.comparing(QPossibleValue::getLabel)); + possibleValueSource.withEnumValues(enumValues); return (possibleValueSource); } diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/scripts/ScriptsMetaDataProvider.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/scripts/ScriptsMetaDataProvider.java index 7029df3c..356230c4 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/scripts/ScriptsMetaDataProvider.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/scripts/ScriptsMetaDataProvider.java @@ -81,6 +81,7 @@ public class ScriptsMetaDataProvider .withName("storeScriptRevision") .withStepList(List.of( new QBackendStepMetaData() + .withName("main") .withCode(new QCodeReference(StoreScriptRevisionProcessStep.class)) ))); } @@ -118,6 +119,30 @@ public class ScriptsMetaDataProvider .withJoinOn(new JoinOn("id", "scriptLogId")) .withOrderBy(new QFilterOrderBy("id")) .withInferredName()); + + instance.addJoin(new QJoinMetaData() + .withType(JoinType.ONE_TO_MANY) + .withLeftTable(Script.TABLE_NAME) + .withRightTable(ScriptRevision.TABLE_NAME) + .withJoinOn(new JoinOn("id", "scriptId")) + .withOrderBy(new QFilterOrderBy("id")) + .withInferredName()); + + instance.addJoin(new QJoinMetaData() + .withType(JoinType.ONE_TO_ONE) + .withLeftTable(Script.TABLE_NAME) + .withRightTable(ScriptRevision.TABLE_NAME) + .withJoinOn(new JoinOn("currentScriptRevisionId", "id")) + .withName("currentScriptRevision")); + + instance.addJoin(new QJoinMetaData() + .withType(JoinType.ONE_TO_MANY) + .withLeftTable(ScriptType.TABLE_NAME) + .withRightTable(Script.TABLE_NAME) + .withJoinOn(new JoinOn("id", "scriptTypeId")) + .withOrderBy(new QFilterOrderBy("id")) + .withInferredName()); + } diff --git a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/scripts/RunAdHocRecordScriptActionTest.java b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/scripts/RunAdHocRecordScriptActionTest.java index b8edad0f..2dbf8eb9 100644 --- a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/scripts/RunAdHocRecordScriptActionTest.java +++ b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/scripts/RunAdHocRecordScriptActionTest.java @@ -67,7 +67,7 @@ class RunAdHocRecordScriptActionTest extends BaseTest """); RunAdHocRecordScriptInput runAdHocRecordScriptInput = new RunAdHocRecordScriptInput(); - runAdHocRecordScriptInput.setRecordPrimaryKey(1); + runAdHocRecordScriptInput.setRecordPrimaryKeyList(List.of(1)); runAdHocRecordScriptInput.setTableName(TestUtils.TABLE_NAME_PERSON_MEMORY); runAdHocRecordScriptInput.setCodeReference(new AdHocScriptCodeReference().withScriptId(scriptId)); runAdHocRecordScriptInput.setLogger(new Log4jCodeExecutionLogger());