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
index ad560f1f..c8fcd9dd 100644
--- 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
@@ -45,9 +45,8 @@ import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
/*******************************************************************************
-
- $api.query("order", null);
- $api.query($utils.newQueryInput().withTable("order").withLimit(1).withShouldGenerateDisplayValues())
+ ** Object made available to scripts for access to qqq api (e.g., query, insert,
+ ** etc, plus object constructors).
*******************************************************************************/
public class ScriptApi implements Serializable
{
diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/tables/query/QFilterCriteria.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/tables/query/QFilterCriteria.java
index 7e394a0f..e096343e 100644
--- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/tables/query/QFilterCriteria.java
+++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/tables/query/QFilterCriteria.java
@@ -207,6 +207,16 @@ public class QFilterCriteria implements Serializable, Cloneable
+ /*******************************************************************************
+ **
+ *******************************************************************************/
+ public QFilterCriteria withOperator(String operatorName)
+ {
+ return withOperator(QCriteriaOperator.valueOf(operatorName.toUpperCase()));
+ }
+
+
+
/*******************************************************************************
** Getter for values
**
diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/tables/query/QueryInput.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/tables/query/QueryInput.java
index a0e3e643..c95fc9db 100644
--- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/tables/query/QueryInput.java
+++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/tables/query/QueryInput.java
@@ -337,4 +337,92 @@ public class QueryInput extends AbstractTableActionInput
return (this);
}
+
+
+ /*******************************************************************************
+ ** Fluent setter for filter
+ *******************************************************************************/
+ public QueryInput withFilter(QQueryFilter filter)
+ {
+ this.filter = filter;
+ return (this);
+ }
+
+
+
+ /*******************************************************************************
+ ** Fluent setter for skip
+ *******************************************************************************/
+ public QueryInput withSkip(Integer skip)
+ {
+ this.skip = skip;
+ return (this);
+ }
+
+
+
+ /*******************************************************************************
+ ** Fluent setter for limit
+ *******************************************************************************/
+ public QueryInput withLimit(Integer limit)
+ {
+ this.limit = limit;
+ return (this);
+ }
+
+
+
+ /*******************************************************************************
+ ** Fluent setter for recordPipe
+ *******************************************************************************/
+ public QueryInput withRecordPipe(RecordPipe recordPipe)
+ {
+ this.recordPipe = recordPipe;
+ return (this);
+ }
+
+
+
+ /*******************************************************************************
+ ** Fluent setter for shouldTranslatePossibleValues
+ *******************************************************************************/
+ public QueryInput withShouldTranslatePossibleValues(boolean shouldTranslatePossibleValues)
+ {
+ this.shouldTranslatePossibleValues = shouldTranslatePossibleValues;
+ return (this);
+ }
+
+
+
+ /*******************************************************************************
+ ** Fluent setter for shouldGenerateDisplayValues
+ *******************************************************************************/
+ public QueryInput withShouldGenerateDisplayValues(boolean shouldGenerateDisplayValues)
+ {
+ this.shouldGenerateDisplayValues = shouldGenerateDisplayValues;
+ return (this);
+ }
+
+
+
+ /*******************************************************************************
+ ** Fluent setter for shouldFetchHeavyFields
+ *******************************************************************************/
+ public QueryInput withShouldFetchHeavyFields(boolean shouldFetchHeavyFields)
+ {
+ this.shouldFetchHeavyFields = shouldFetchHeavyFields;
+ return (this);
+ }
+
+
+
+ /*******************************************************************************
+ **
+ *******************************************************************************/
+ @Override
+ public QueryInput withTableName(String tableName)
+ {
+ super.withTableName(tableName);
+ return (this);
+ }
}
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 7a6b2e82..5403cd0f 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
@@ -66,6 +66,10 @@ import com.kingsrook.qqq.backend.core.processes.implementations.scripts.StoreScr
*******************************************************************************/
public class ScriptsMetaDataProvider
{
+ public static final String RUN_RECORD_SCRIPT_PROCESS_NAME = "runRecordScript";
+ public static final String STORE_SCRIPT_REVISION_PROCESS_NAME = "storeScriptRevision";
+
+
/*******************************************************************************
**
@@ -89,7 +93,7 @@ public class ScriptsMetaDataProvider
private QProcessMetaData defineStoreScriptRevisionProcess()
{
return (new QProcessMetaData()
- .withName("storeScriptRevision")
+ .withName(STORE_SCRIPT_REVISION_PROCESS_NAME)
.withStepList(List.of(
new QBackendStepMetaData()
.withName("main")
@@ -105,7 +109,7 @@ public class ScriptsMetaDataProvider
private QProcessMetaData defineRunRecordScriptProcess()
{
QProcessMetaData processMetaData = StreamedETLWithFrontendProcess.processMetaDataBuilder()
- .withName("runRecordScript")
+ .withName(RUN_RECORD_SCRIPT_PROCESS_NAME)
.withLabel("Run Script")
.withIcon(new QIcon().withName("data_object"))
.withSupportsFullValidation(false)
diff --git a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/scripts/ScriptApiTest.java b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/scripts/ScriptApiTest.java
new file mode 100644
index 00000000..a2208185
--- /dev/null
+++ b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/scripts/ScriptApiTest.java
@@ -0,0 +1,90 @@
+/*
+ * 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.util.List;
+import java.util.UUID;
+import com.kingsrook.qqq.backend.core.BaseTest;
+import com.kingsrook.qqq.backend.core.exceptions.QException;
+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.data.QRecord;
+import com.kingsrook.qqq.backend.core.utils.TestUtils;
+import org.junit.jupiter.api.Test;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+
+/*******************************************************************************
+ ** Unit test for com.kingsrook.qqq.backend.core.actions.scripts.ScriptApi
+ *******************************************************************************/
+class ScriptApiTest extends BaseTest
+{
+
+ /*******************************************************************************
+ **
+ *******************************************************************************/
+ @Test
+ void test() throws QException
+ {
+ ScriptApi api = new ScriptApi();
+ assertThat(api.newFilterCriteria()).isInstanceOf(QFilterCriteria.class);
+ assertThat(api.newFilterOrderBy()).isInstanceOf(QFilterOrderBy.class);
+ assertThat(api.newQueryFilter()).isInstanceOf(QQueryFilter.class);
+ assertThat(api.newRecord()).isInstanceOf(QRecord.class);
+ assertThat(api.newQueryInput()).isInstanceOf(QueryInput.class);
+
+ String tableName = TestUtils.TABLE_NAME_PERSON_MEMORY;
+ String uuid = UUID.randomUUID().toString();
+ api.insert(tableName, new QRecord().withValue("firstName", uuid));
+ List queryResult = api.query(api.newQueryInput()
+ .withTableName(tableName)
+ .withFilter(api.newQueryFilter()
+ .withCriteria(api.newFilterCriteria()
+ .withFieldName("firstName")
+ .withOperator("EQUALS")
+ .withValues(List.of(uuid)))));
+ assertEquals(1, queryResult.size());
+ assertEquals(uuid, queryResult.get(0).getValueString("firstName"));
+
+ String newUUID = UUID.randomUUID().toString();
+ api.update(tableName, api.newRecord().withValue("id", queryResult.get(0).getValue("id")).withValue("lastName", newUUID));
+ QQueryFilter filter = api.newQueryFilter()
+ .withCriteria(api.newFilterCriteria()
+ .withFieldName("lastName")
+ .withOperator("EQUALS")
+ .withValues(List.of(newUUID)));
+ queryResult = api.query(tableName, filter);
+ assertEquals(1, queryResult.size());
+ assertEquals(newUUID, queryResult.get(0).getValueString("lastName"));
+
+ api.delete(tableName, queryResult.get(0).getValue("id"));
+ queryResult = api.query(tableName, filter);
+ assertEquals(0, queryResult.size());
+
+ api.delete(tableName, filter);
+ }
+
+}
\ No newline at end of file
diff --git a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/processes/implementations/scripts/RunRecordScriptTest.java b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/processes/implementations/scripts/RunRecordScriptTest.java
new file mode 100644
index 00000000..3977efb1
--- /dev/null
+++ b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/processes/implementations/scripts/RunRecordScriptTest.java
@@ -0,0 +1,63 @@
+/*
+ * 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.processes.implementations.scripts;
+
+
+import com.kingsrook.qqq.backend.core.BaseTest;
+import com.kingsrook.qqq.backend.core.actions.processes.RunProcessAction;
+import com.kingsrook.qqq.backend.core.context.QContext;
+import com.kingsrook.qqq.backend.core.exceptions.QException;
+import com.kingsrook.qqq.backend.core.model.actions.processes.RunProcessInput;
+import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
+import com.kingsrook.qqq.backend.core.model.scripts.ScriptsMetaDataProvider;
+import com.kingsrook.qqq.backend.core.utils.TestUtils;
+import com.kingsrook.qqq.backend.core.utils.collections.MapBuilder;
+import org.junit.jupiter.api.Test;
+
+
+/*******************************************************************************
+ ** Test full process of RunRecordScript (should its Extract and Load classes).
+ *******************************************************************************/
+class RunRecordScriptTest extends BaseTest
+{
+
+ /*******************************************************************************
+ **
+ *******************************************************************************/
+ @Test
+ void test() throws QException
+ {
+ QInstance qInstance = QContext.getQInstance();
+ new ScriptsMetaDataProvider().defineAll(qInstance, TestUtils.MEMORY_BACKEND_NAME, null);
+
+ RunProcessInput runProcessInput = new RunProcessInput();
+ runProcessInput.setProcessName(ScriptsMetaDataProvider.RUN_RECORD_SCRIPT_PROCESS_NAME);
+ runProcessInput.setFrontendStepBehavior(RunProcessInput.FrontendStepBehavior.SKIP);
+ runProcessInput.setValues(MapBuilder.of(
+ "recordIds", "1,2,3",
+ "tableName", TestUtils.TABLE_NAME_PERSON_MEMORY,
+ "scriptId", 1
+ ));
+ new RunProcessAction().execute(runProcessInput);
+ }
+
+}
\ No newline at end of file
diff --git a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/processes/implementations/scripts/StoreScriptRevisionProcessStepTest.java b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/processes/implementations/scripts/StoreScriptRevisionProcessStepTest.java
new file mode 100644
index 00000000..aee18116
--- /dev/null
+++ b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/processes/implementations/scripts/StoreScriptRevisionProcessStepTest.java
@@ -0,0 +1,97 @@
+/*
+ * 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.processes.implementations.scripts;
+
+
+import java.util.List;
+import java.util.stream.Collectors;
+import com.kingsrook.qqq.backend.core.BaseTest;
+import com.kingsrook.qqq.backend.core.context.QContext;
+import com.kingsrook.qqq.backend.core.exceptions.QException;
+import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInput;
+import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepOutput;
+import com.kingsrook.qqq.backend.core.model.data.QRecord;
+import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
+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.ScriptsMetaDataProvider;
+import com.kingsrook.qqq.backend.core.utils.TestUtils;
+import com.kingsrook.qqq.backend.core.utils.collections.MapBuilder;
+import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+
+/*******************************************************************************
+ ** Unit test for StoreScriptRevisionProcessStep
+ *******************************************************************************/
+class StoreScriptRevisionProcessStepTest extends BaseTest
+{
+
+ /*******************************************************************************
+ **
+ *******************************************************************************/
+ @Test
+ void test() throws QException
+ {
+ QInstance qInstance = QContext.getQInstance();
+ new ScriptsMetaDataProvider().defineAll(qInstance, TestUtils.MEMORY_BACKEND_NAME, null);
+
+ Integer scriptId = 1701;
+ String scriptContents = "logger.log('Hi');";
+
+ TestUtils.insertRecords(qInstance, qInstance.getTable(Script.TABLE_NAME), List.of(new QRecord().withValue("id", 1701)));
+ List scripts = TestUtils.queryTable(Script.TABLE_NAME);
+ assertNull(scripts.get(0).getValueInteger("currentScriptRevisionId"));
+
+ new StoreScriptRevisionProcessStep().run(new RunBackendStepInput().withValues(MapBuilder.of(
+ "scriptId", scriptId,
+ "contents", scriptContents
+ )), new RunBackendStepOutput());
+
+ scripts = TestUtils.queryTable(Script.TABLE_NAME);
+ assertEquals(1, scripts.get(0).getValueInteger("currentScriptRevisionId"));
+
+ List scriptRevisions = TestUtils.queryTable(ScriptRevision.TABLE_NAME);
+ QRecord scriptRevision = scriptRevisions.get(0);
+ assertEquals(1701, scriptRevision.getValueInteger("scriptId"));
+ assertEquals(1, scriptRevision.getValueInteger("sequenceNo"));
+ assertEquals("Initial version", scriptRevision.getValueString("commitMessage"));
+ assertEquals(scriptContents, scriptRevision.getValueString("contents"));
+
+ new StoreScriptRevisionProcessStep().run(new RunBackendStepInput().withValues(MapBuilder.of(
+ "scriptId", scriptId,
+ "contents", scriptContents
+ )), new RunBackendStepOutput());
+
+ scripts = TestUtils.queryTable(Script.TABLE_NAME);
+ assertEquals(2, scripts.get(0).getValueInteger("currentScriptRevisionId"));
+
+ scriptRevisions = TestUtils.queryTable(ScriptRevision.TABLE_NAME).stream().filter(r -> r.getValueInteger("id").equals(2)).collect(Collectors.toList());
+ scriptRevision = scriptRevisions.get(0);
+ assertEquals(1701, scriptRevision.getValueInteger("scriptId"));
+ assertEquals(2, scriptRevision.getValueInteger("sequenceNo"));
+ assertEquals("No commit message given", scriptRevision.getValueString("commitMessage"));
+ assertEquals(scriptContents, scriptRevision.getValueString("contents"));
+ }
+
+}
\ No newline at end of file