mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-18 05:01:07 +00:00
Initial version of scripts, javascript
This commit is contained in:
1
pom.xml
1
pom.xml
@ -33,6 +33,7 @@
|
|||||||
<module>qqq-backend-module-api</module>
|
<module>qqq-backend-module-api</module>
|
||||||
<module>qqq-backend-module-filesystem</module>
|
<module>qqq-backend-module-filesystem</module>
|
||||||
<module>qqq-backend-module-rdbms</module>
|
<module>qqq-backend-module-rdbms</module>
|
||||||
|
<module>qqq-language-support-javascript</module>
|
||||||
<module>qqq-middleware-picocli</module>
|
<module>qqq-middleware-picocli</module>
|
||||||
<module>qqq-middleware-javalin</module>
|
<module>qqq-middleware-javalin</module>
|
||||||
<module>qqq-middleware-lambda</module>
|
<module>qqq-middleware-lambda</module>
|
||||||
|
@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.backend.core.actions.scripts;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.scripts.logging.Log4jCodeExecutionLogger;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.scripts.logging.QCodeExecutionLoggerInterface;
|
||||||
|
import com.kingsrook.qqq.backend.core.exceptions.QCodeException;
|
||||||
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
|
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.metadata.code.QCodeReference;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public class ExecuteCodeAction
|
||||||
|
{
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@SuppressWarnings("checkstyle:indentation")
|
||||||
|
public void run(ExecuteCodeInput input, ExecuteCodeOutput output) throws QException, QCodeException
|
||||||
|
{
|
||||||
|
QCodeReference codeReference = input.getCodeReference();
|
||||||
|
|
||||||
|
QCodeExecutionLoggerInterface executionLogger = input.getExecutionLogger();
|
||||||
|
if(executionLogger == null)
|
||||||
|
{
|
||||||
|
executionLogger = getDefaultExecutionLogger();
|
||||||
|
}
|
||||||
|
executionLogger.acceptExecutionStart(input);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
String languageExecutor = switch(codeReference.getCodeType())
|
||||||
|
{
|
||||||
|
case JAVA -> "com.kingsrook.qqq.backend.core.actions.scripts.QJavaExecutor";
|
||||||
|
case JAVA_SCRIPT -> "com.kingsrook.qqq.languages.javascript.QJavaScriptExecutor";
|
||||||
|
};
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
Class<? extends QCodeExecutor> executorClass = (Class<? extends QCodeExecutor>) Class.forName(languageExecutor);
|
||||||
|
QCodeExecutor qCodeExecutor = executorClass.getConstructor().newInstance();
|
||||||
|
|
||||||
|
Serializable codeOutput = qCodeExecutor.execute(codeReference, input.getContext(), executionLogger);
|
||||||
|
output.setOutput(codeOutput);
|
||||||
|
executionLogger.acceptExecutionEnd(codeOutput);
|
||||||
|
}
|
||||||
|
catch(QCodeException qCodeException)
|
||||||
|
{
|
||||||
|
executionLogger.acceptException(qCodeException);
|
||||||
|
throw (qCodeException);
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
executionLogger.acceptException(e);
|
||||||
|
throw (new QException("Error executing code [" + codeReference + "]", e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private QCodeExecutionLoggerInterface getDefaultExecutionLogger()
|
||||||
|
{
|
||||||
|
return (new Log4jCodeExecutionLogger());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.backend.core.actions.scripts;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Map;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.scripts.logging.QCodeExecutionLoggerInterface;
|
||||||
|
import com.kingsrook.qqq.backend.core.exceptions.QCodeException;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public interface QCodeExecutor
|
||||||
|
{
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
Serializable execute(QCodeReference codeReference, Map<String, Serializable> context, QCodeExecutionLoggerInterface executionLogger) throws QCodeException;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.backend.core.actions.scripts;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.customizers.QCodeLoader;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.scripts.logging.QCodeExecutionLoggerInterface;
|
||||||
|
import com.kingsrook.qqq.backend.core.exceptions.QCodeException;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public class QJavaExecutor implements QCodeExecutor
|
||||||
|
{
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Override
|
||||||
|
public Serializable execute(QCodeReference codeReference, Map<String, Serializable> input, QCodeExecutionLoggerInterface executionLogger) throws QCodeException
|
||||||
|
{
|
||||||
|
Map<String, Object> context = new HashMap<>(input);
|
||||||
|
if(!context.containsKey("logger"))
|
||||||
|
{
|
||||||
|
context.put("logger", executionLogger);
|
||||||
|
}
|
||||||
|
|
||||||
|
Serializable output;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Function<Map<String, Object>, Serializable> function = QCodeLoader.getFunction(codeReference);
|
||||||
|
output = function.apply(context);
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
QCodeException qCodeException = new QCodeException("Error executing script", e);
|
||||||
|
throw (qCodeException);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (output);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,113 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.backend.core.actions.scripts;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.scripts.logging.HeaderAndDetailTableCodeExecutionLogger;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.tables.GetAction;
|
||||||
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
|
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.RunAssociatedScriptInput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.scripts.RunAssociatedScriptOutput;
|
||||||
|
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.metadata.code.QCodeReference;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeType;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.scripts.Script;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.scripts.ScriptRevision;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public class RunAssociatedScriptAction
|
||||||
|
{
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void run(RunAssociatedScriptInput input, RunAssociatedScriptOutput output) throws QException
|
||||||
|
{
|
||||||
|
Serializable scriptId = getScriptId(input);
|
||||||
|
Script script = getScript(input, scriptId);
|
||||||
|
ScriptRevision scriptRevision = getCurrentScriptRevision(input, script.getCurrentScriptRevisionId());
|
||||||
|
|
||||||
|
ExecuteCodeInput executeCodeInput = new ExecuteCodeInput(input.getInstance());
|
||||||
|
executeCodeInput.setSession(input.getSession());
|
||||||
|
executeCodeInput.setContext(new HashMap<>(input.getInputValues()));
|
||||||
|
executeCodeInput.setCodeReference(new QCodeReference().withInlineCode(scriptRevision.getContents()).withCodeType(QCodeType.JAVA_SCRIPT));
|
||||||
|
executeCodeInput.setExecutionLogger(new HeaderAndDetailTableCodeExecutionLogger(scriptRevision.getScriptId(), scriptRevision.getId()));
|
||||||
|
ExecuteCodeOutput executeCodeOutput = new ExecuteCodeOutput();
|
||||||
|
new ExecuteCodeAction().run(executeCodeInput, executeCodeOutput);
|
||||||
|
|
||||||
|
output.setOutput(executeCodeOutput.getOutput());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private ScriptRevision getCurrentScriptRevision(RunAssociatedScriptInput input, Serializable scriptRevisionId) throws QException
|
||||||
|
{
|
||||||
|
GetInput getInput = new GetInput(input.getInstance());
|
||||||
|
getInput.setSession(input.getSession());
|
||||||
|
getInput.setTableName("scriptRevision");
|
||||||
|
getInput.setPrimaryKey(scriptRevisionId);
|
||||||
|
GetOutput getOutput = new GetAction().execute(getInput);
|
||||||
|
return (new ScriptRevision(getOutput.getRecord()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private Script getScript(RunAssociatedScriptInput input, Serializable scriptId) throws QException
|
||||||
|
{
|
||||||
|
GetInput getInput = new GetInput(input.getInstance());
|
||||||
|
getInput.setSession(input.getSession());
|
||||||
|
getInput.setTableName("script");
|
||||||
|
getInput.setPrimaryKey(scriptId);
|
||||||
|
GetOutput getOutput = new GetAction().execute(getInput);
|
||||||
|
return (new Script(getOutput.getRecord()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private Serializable getScriptId(RunAssociatedScriptInput input) throws QException
|
||||||
|
{
|
||||||
|
GetInput getInput = new GetInput(input.getInstance());
|
||||||
|
getInput.setSession(input.getSession());
|
||||||
|
getInput.setTableName(input.getCodeReference().getRecordTable());
|
||||||
|
getInput.setPrimaryKey(input.getCodeReference().getRecordPrimaryKey());
|
||||||
|
GetOutput getOutput = new GetAction().execute(getInput);
|
||||||
|
return (getOutput.getRecord().getValue(input.getCodeReference().getFieldName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,206 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.backend.core.actions.scripts;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.tables.GetAction;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.tables.InsertAction;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.tables.QueryAction;
|
||||||
|
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.scripts.StoreAssociatedScriptInput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.scripts.StoreAssociatedScriptOutput;
|
||||||
|
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.actions.tables.insert.InsertInput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertOutput;
|
||||||
|
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.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.query.QueryOutput;
|
||||||
|
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.AssociatedScript;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public class StoreAssociatedScriptAction
|
||||||
|
{
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void run(StoreAssociatedScriptInput input, StoreAssociatedScriptOutput output) throws QException
|
||||||
|
{
|
||||||
|
QTableMetaData table = input.getTable();
|
||||||
|
Optional<AssociatedScript> optAssociatedScript = table.getAssociatedScripts().stream().filter(as -> as.getFieldName().equals(input.getFieldName())).findFirst();
|
||||||
|
if(optAssociatedScript.isEmpty())
|
||||||
|
{
|
||||||
|
throw (new QException("Field to update associated script for is not an associated script field."));
|
||||||
|
}
|
||||||
|
AssociatedScript associatedScript = optAssociatedScript.get();
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////
|
||||||
|
// get the record that the script is to be associated with //
|
||||||
|
/////////////////////////////////////////////////////////////
|
||||||
|
QRecord associatedRecord;
|
||||||
|
{
|
||||||
|
GetInput getInput = new GetInput(input.getInstance());
|
||||||
|
getInput.setSession(input.getSession());
|
||||||
|
getInput.setTableName(input.getTableName());
|
||||||
|
getInput.setPrimaryKey(input.getRecordPrimaryKey());
|
||||||
|
GetOutput getOutput = new GetAction().execute(getInput);
|
||||||
|
associatedRecord = getOutput.getRecord();
|
||||||
|
}
|
||||||
|
if(associatedRecord == null)
|
||||||
|
{
|
||||||
|
throw (new QException("Record to associated with script was not found."));
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////
|
||||||
|
// check if there's currently a script referenced by the record //
|
||||||
|
//////////////////////////////////////////////////////////////////
|
||||||
|
Serializable existingScriptId = associatedRecord.getValueString(input.getFieldName());
|
||||||
|
QRecord script;
|
||||||
|
Integer nextSequenceNo = 1;
|
||||||
|
if(existingScriptId == null)
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// get the script type - that'll be part of the new script's name //
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
GetInput getInput = new GetInput(input.getInstance());
|
||||||
|
getInput.setSession(input.getSession());
|
||||||
|
getInput.setTableName("scriptType");
|
||||||
|
getInput.setPrimaryKey(associatedScript.getScriptTypeId());
|
||||||
|
GetOutput getOutput = new GetAction().execute(getInput);
|
||||||
|
QRecord scriptType = getOutput.getRecord();
|
||||||
|
|
||||||
|
/////////////////////////
|
||||||
|
// insert a new script //
|
||||||
|
/////////////////////////
|
||||||
|
script = new QRecord();
|
||||||
|
script.setValue("scriptTypeId", associatedScript.getScriptTypeId());
|
||||||
|
script.setValue("name", associatedRecord.getRecordLabel() + " - " + scriptType.getRecordLabel());
|
||||||
|
InsertInput insertInput = new InsertInput(input.getInstance());
|
||||||
|
insertInput.setSession(input.getSession());
|
||||||
|
insertInput.setTableName("script");
|
||||||
|
insertInput.setRecords(List.of(script));
|
||||||
|
InsertOutput insertOutput = new InsertAction().execute(insertInput);
|
||||||
|
script = insertOutput.getRecords().get(0);
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////
|
||||||
|
// update the associated record to point at the new script //
|
||||||
|
/////////////////////////////////////////////////////////////
|
||||||
|
UpdateInput updateInput = new UpdateInput(input.getInstance());
|
||||||
|
updateInput.setSession(input.getSession());
|
||||||
|
updateInput.setTableName(input.getTableName());
|
||||||
|
updateInput.setRecords(List.of(new QRecord()
|
||||||
|
.withValue(table.getPrimaryKeyField(), associatedRecord.getValue(table.getPrimaryKeyField()))
|
||||||
|
.withValue(input.getFieldName(), script.getValue("id"))
|
||||||
|
));
|
||||||
|
new UpdateAction().execute(updateInput);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
////////////////////////////////////////
|
||||||
|
// get the existing script, to update //
|
||||||
|
////////////////////////////////////////
|
||||||
|
GetInput getInput = new GetInput(input.getInstance());
|
||||||
|
getInput.setSession(input.getSession());
|
||||||
|
getInput.setTableName("script");
|
||||||
|
getInput.setPrimaryKey(existingScriptId);
|
||||||
|
GetOutput getOutput = new GetAction().execute(getInput);
|
||||||
|
script = getOutput.getRecord();
|
||||||
|
|
||||||
|
QueryInput queryInput = new QueryInput(input.getInstance());
|
||||||
|
queryInput.setSession(input.getSession());
|
||||||
|
queryInput.setTableName("scriptRevision");
|
||||||
|
queryInput.setFilter(new QQueryFilter()
|
||||||
|
.withCriteria(new QFilterCriteria("scriptId", QCriteriaOperator.EQUALS, List.of(script.getValue("id"))))
|
||||||
|
.withOrderBy(new QFilterOrderBy("sequenceNo", false))
|
||||||
|
);
|
||||||
|
queryInput.setLimit(1);
|
||||||
|
QueryOutput queryOutput = new QueryAction().execute(queryInput);
|
||||||
|
if(!queryOutput.getRecords().isEmpty())
|
||||||
|
{
|
||||||
|
nextSequenceNo = queryOutput.getRecords().get(0).getValueInteger("sequenceNo") + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////
|
||||||
|
// insert a new script revision //
|
||||||
|
//////////////////////////////////
|
||||||
|
String commitMessage = input.getCommitMessage();
|
||||||
|
if(!StringUtils.hasContent(commitMessage))
|
||||||
|
{
|
||||||
|
if(nextSequenceNo == 1)
|
||||||
|
{
|
||||||
|
commitMessage = "Initial version";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
commitMessage = "No commit message given";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QRecord scriptRevision = new QRecord()
|
||||||
|
.withValue("scriptId", script.getValue("id"))
|
||||||
|
.withValue("contents", input.getCode())
|
||||||
|
.withValue("commitMessage", commitMessage)
|
||||||
|
.withValue("sequenceNo", nextSequenceNo);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
scriptRevision.setValue("author", input.getSession().getUser().getFullName());
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
scriptRevision.setValue("author", "Unknown");
|
||||||
|
}
|
||||||
|
|
||||||
|
InsertInput insertInput = new InsertInput(input.getInstance());
|
||||||
|
insertInput.setSession(input.getSession());
|
||||||
|
insertInput.setTableName("scriptRevision");
|
||||||
|
insertInput.setRecords(List.of(scriptRevision));
|
||||||
|
InsertOutput insertOutput = new InsertAction().execute(insertInput);
|
||||||
|
scriptRevision = insertOutput.getRecords().get(0);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////
|
||||||
|
// update the script to point at the new revision //
|
||||||
|
////////////////////////////////////////////////////
|
||||||
|
script.setValue("currentScriptRevisionId", scriptRevision.getValue("id"));
|
||||||
|
UpdateInput updateInput = new UpdateInput(input.getInstance());
|
||||||
|
updateInput.setSession(input.getSession());
|
||||||
|
updateInput.setTableName("script");
|
||||||
|
updateInput.setRecords(List.of(script));
|
||||||
|
new UpdateAction().execute(updateInput);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.backend.core.actions.scripts;
|
||||||
|
|
||||||
|
|
||||||
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.scripts.TestScriptInput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.scripts.TestScriptOutput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public class TestScriptAction
|
||||||
|
{
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void run(TestScriptInput input, TestScriptOutput output) throws QException
|
||||||
|
{
|
||||||
|
QTableMetaData table = input.getTable();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,221 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.backend.core.actions.scripts.logging;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.tables.InsertAction;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.tables.UpdateAction;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.scripts.ExecuteCodeInput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertOutput;
|
||||||
|
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.utils.CollectionUtils;
|
||||||
|
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Implementation of a code execution logger that logs into a header and child
|
||||||
|
** table
|
||||||
|
*******************************************************************************/
|
||||||
|
public class HeaderAndDetailTableCodeExecutionLogger implements QCodeExecutionLoggerInterface
|
||||||
|
{
|
||||||
|
private static final Logger LOG = LogManager.getLogger(HeaderAndDetailTableCodeExecutionLogger.class);
|
||||||
|
|
||||||
|
private QRecord header;
|
||||||
|
private List<QRecord> children = new ArrayList<>();
|
||||||
|
private ExecuteCodeInput executeCodeInput;
|
||||||
|
|
||||||
|
private Serializable scriptId;
|
||||||
|
private Serializable scriptRevisionId;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Constructor
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public HeaderAndDetailTableCodeExecutionLogger(Serializable scriptId, Serializable scriptRevisionId)
|
||||||
|
{
|
||||||
|
this.scriptId = scriptId;
|
||||||
|
this.scriptRevisionId = scriptRevisionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private QRecord buildHeaderRecord(ExecuteCodeInput executeCodeInput)
|
||||||
|
{
|
||||||
|
return (new QRecord()
|
||||||
|
.withValue("scriptId", scriptId)
|
||||||
|
.withValue("scriptRevisionId", scriptRevisionId)
|
||||||
|
.withValue("startTimestamp", Instant.now())
|
||||||
|
.withValue("input", truncate(executeCodeInput.getContext().toString())));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
protected QRecord buildDetailLogRecord(String logLine)
|
||||||
|
{
|
||||||
|
return (new QRecord()
|
||||||
|
.withValue("scriptLogId", header.getValue("id"))
|
||||||
|
.withValue("timestamp", Instant.now())
|
||||||
|
.withValue("text", truncate(logLine)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private String truncate(String logLine)
|
||||||
|
{
|
||||||
|
return StringUtils.safeTruncate(logLine, 1000, "...");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private void updateHeaderAtEnd(Serializable output, Exception exception)
|
||||||
|
{
|
||||||
|
Instant startTimestamp = (Instant) header.getValue("startTimestamp");
|
||||||
|
Instant endTimestamp = Instant.now();
|
||||||
|
header.setValue("endTimestamp", endTimestamp);
|
||||||
|
header.setValue("runTimeMillis", startTimestamp.until(endTimestamp, ChronoUnit.MILLIS));
|
||||||
|
|
||||||
|
if(exception != null)
|
||||||
|
{
|
||||||
|
header.setValue("hadError", true);
|
||||||
|
header.setValue("error", exception.getMessage());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
header.setValue("hadError", false);
|
||||||
|
header.setValue("output", truncate(String.valueOf(output)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Override
|
||||||
|
public void acceptExecutionStart(ExecuteCodeInput executeCodeInput)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
this.executeCodeInput = executeCodeInput;
|
||||||
|
QRecord scriptLog = buildHeaderRecord(executeCodeInput);
|
||||||
|
|
||||||
|
InsertInput insertInput = new InsertInput(executeCodeInput.getInstance());
|
||||||
|
insertInput.setSession(executeCodeInput.getSession());
|
||||||
|
insertInput.setTableName("scriptLog");
|
||||||
|
insertInput.setRecords(List.of(scriptLog));
|
||||||
|
InsertOutput insertOutput = new InsertAction().execute(insertInput);
|
||||||
|
this.header = insertOutput.getRecords().get(0);
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
LOG.warn("Error starting storage of script log", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Override
|
||||||
|
public void acceptLogLine(String logLine)
|
||||||
|
{
|
||||||
|
children.add(buildDetailLogRecord(logLine));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Override
|
||||||
|
public void acceptException(Exception exception)
|
||||||
|
{
|
||||||
|
store(null, exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Override
|
||||||
|
public void acceptExecutionEnd(Serializable output)
|
||||||
|
{
|
||||||
|
store(output, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private void store(Serializable output, Exception exception)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
updateHeaderAtEnd(output, exception);
|
||||||
|
UpdateInput updateInput = new UpdateInput(executeCodeInput.getInstance());
|
||||||
|
updateInput.setSession(executeCodeInput.getSession());
|
||||||
|
updateInput.setTableName("scriptLog");
|
||||||
|
updateInput.setRecords(List.of(header));
|
||||||
|
new UpdateAction().execute(updateInput);
|
||||||
|
|
||||||
|
if(CollectionUtils.nullSafeHasContents(children))
|
||||||
|
{
|
||||||
|
InsertInput insertInput = new InsertInput(executeCodeInput.getInstance());
|
||||||
|
insertInput.setSession(executeCodeInput.getSession());
|
||||||
|
insertInput.setTableName("scriptLogLine");
|
||||||
|
insertInput.setRecords(children);
|
||||||
|
new InsertAction().execute(insertInput);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
LOG.warn("Error storing script log", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.backend.core.actions.scripts.logging;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.UUID;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.scripts.ExecuteCodeInput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
|
||||||
|
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||||
|
import com.kingsrook.qqq.backend.core.utils.ValueUtils;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Implementation of a code execution logger that just logs to LOG 4j
|
||||||
|
*******************************************************************************/
|
||||||
|
public class Log4jCodeExecutionLogger implements QCodeExecutionLoggerInterface
|
||||||
|
{
|
||||||
|
private static final Logger LOG = LogManager.getLogger(Log4jCodeExecutionLogger.class);
|
||||||
|
|
||||||
|
private QCodeReference qCodeReference;
|
||||||
|
private String uuid = UUID.randomUUID().toString();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Override
|
||||||
|
public void acceptExecutionStart(ExecuteCodeInput executeCodeInput)
|
||||||
|
{
|
||||||
|
this.qCodeReference = executeCodeInput.getCodeReference();
|
||||||
|
|
||||||
|
String contextString = StringUtils.safeTruncate(ValueUtils.getValueAsString(executeCodeInput.getContext()), 250, "...");
|
||||||
|
LOG.info("Starting script execution: " + qCodeReference.getName() + ", uuid: " + uuid + ", with context: " + contextString);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Override
|
||||||
|
public void acceptLogLine(String logLine)
|
||||||
|
{
|
||||||
|
LOG.info("Script log: " + uuid + ": " + logLine);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Override
|
||||||
|
public void acceptException(Exception exception)
|
||||||
|
{
|
||||||
|
LOG.info("Script Exception: " + uuid, exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Override
|
||||||
|
public void acceptExecutionEnd(Serializable output)
|
||||||
|
{
|
||||||
|
String outputString = StringUtils.safeTruncate(ValueUtils.getValueAsString(output), 250, "...");
|
||||||
|
LOG.info("Finished script execution: " + qCodeReference.getName() + ", uuid: " + uuid + ", with output: " + outputString);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.backend.core.actions.scripts.logging;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.scripts.ExecuteCodeInput;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Implementation of a code execution logger that just noop's every action.
|
||||||
|
*******************************************************************************/
|
||||||
|
public class NoopCodeExecutionLogger implements QCodeExecutionLoggerInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Override
|
||||||
|
public void acceptExecutionStart(ExecuteCodeInput executeCodeInput)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Override
|
||||||
|
public void acceptLogLine(String logLine)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Override
|
||||||
|
public void acceptException(Exception exception)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Override
|
||||||
|
public void acceptExecutionEnd(Serializable output)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.backend.core.actions.scripts.logging;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.scripts.ExecuteCodeInput;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public interface QCodeExecutionLoggerInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
void acceptExecutionStart(ExecuteCodeInput executeCodeInput);
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
void acceptLogLine(String logLine);
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
default void log(String message)
|
||||||
|
{
|
||||||
|
acceptLogLine(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
void acceptException(Exception exception);
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
void acceptExecutionEnd(Serializable output);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.backend.core.exceptions;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Exception thrown while generating reports
|
||||||
|
*
|
||||||
|
*******************************************************************************/
|
||||||
|
public class QCodeException extends QException
|
||||||
|
{
|
||||||
|
private String context;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Constructor of message
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public QCodeException(String message)
|
||||||
|
{
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Constructor of message & cause
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public QCodeException(String message, Throwable cause)
|
||||||
|
{
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for context
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getContext()
|
||||||
|
{
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for context
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setContext(String context)
|
||||||
|
{
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -608,7 +608,7 @@ public class QInstanceEnricher
|
|||||||
** <li>TLAAndAnotherTLA -> tla_and_another_tla</li>
|
** <li>TLAAndAnotherTLA -> tla_and_another_tla</li>
|
||||||
** </ul>
|
** </ul>
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
static String inferBackendName(String fieldName)
|
public static String inferBackendName(String fieldName)
|
||||||
{
|
{
|
||||||
////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// build a list of words in the name, then join them with _ and lower-case the result //
|
// build a list of words in the name, then join them with _ and lower-case the result //
|
||||||
|
@ -0,0 +1,172 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.backend.core.model.actions.scripts;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.scripts.logging.QCodeExecutionLoggerInterface;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.AbstractActionInput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public class ExecuteCodeInput extends AbstractActionInput
|
||||||
|
{
|
||||||
|
private QCodeReference codeReference;
|
||||||
|
private Map<String, Serializable> context;
|
||||||
|
private QCodeExecutionLoggerInterface executionLogger;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Constructor
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public ExecuteCodeInput(QInstance qInstance)
|
||||||
|
{
|
||||||
|
super(qInstance);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for codeReference
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public QCodeReference getCodeReference()
|
||||||
|
{
|
||||||
|
return codeReference;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for codeReference
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setCodeReference(QCodeReference codeReference)
|
||||||
|
{
|
||||||
|
this.codeReference = codeReference;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for codeReference
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public ExecuteCodeInput withCodeReference(QCodeReference codeReference)
|
||||||
|
{
|
||||||
|
this.codeReference = codeReference;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for context
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Map<String, Serializable> getContext()
|
||||||
|
{
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for context
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setContext(Map<String, Serializable> context)
|
||||||
|
{
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for context
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public ExecuteCodeInput withContext(Map<String, Serializable> context)
|
||||||
|
{
|
||||||
|
this.context = context;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for context
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public ExecuteCodeInput withContext(String key, Serializable value)
|
||||||
|
{
|
||||||
|
if(this.context == null)
|
||||||
|
{
|
||||||
|
context = new HashMap<>();
|
||||||
|
}
|
||||||
|
this.context.put(key, value);
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for executionLogger
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public QCodeExecutionLoggerInterface getExecutionLogger()
|
||||||
|
{
|
||||||
|
return executionLogger;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for executionLogger
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setExecutionLogger(QCodeExecutionLoggerInterface executionLogger)
|
||||||
|
{
|
||||||
|
this.executionLogger = executionLogger;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for executionLogger
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public ExecuteCodeInput withExecutionLogger(QCodeExecutionLoggerInterface executionLogger)
|
||||||
|
{
|
||||||
|
this.executionLogger = executionLogger;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.backend.core.model.actions.scripts;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public class ExecuteCodeOutput
|
||||||
|
{
|
||||||
|
private Serializable output;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for output
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Serializable getOutput()
|
||||||
|
{
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for output
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setOutput(Serializable output)
|
||||||
|
{
|
||||||
|
this.output = output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for output
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public ExecuteCodeOutput withOutput(Serializable output)
|
||||||
|
{
|
||||||
|
this.output = output;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,117 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.backend.core.model.actions.scripts;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.AbstractTableActionInput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.code.AssociatedScriptCodeReference;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public class RunAssociatedScriptInput extends AbstractTableActionInput
|
||||||
|
{
|
||||||
|
private AssociatedScriptCodeReference codeReference;
|
||||||
|
private Map<String, String> inputValues;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public RunAssociatedScriptInput(QInstance qInstance)
|
||||||
|
{
|
||||||
|
super(qInstance);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for codeReference
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public AssociatedScriptCodeReference getCodeReference()
|
||||||
|
{
|
||||||
|
return codeReference;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for codeReference
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setCodeReference(AssociatedScriptCodeReference codeReference)
|
||||||
|
{
|
||||||
|
this.codeReference = codeReference;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for codeReference
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public RunAssociatedScriptInput withCodeReference(AssociatedScriptCodeReference codeReference)
|
||||||
|
{
|
||||||
|
this.codeReference = codeReference;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for inputValues
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Map<String, String> getInputValues()
|
||||||
|
{
|
||||||
|
return inputValues;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for inputValues
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setInputValues(Map<String, String> inputValues)
|
||||||
|
{
|
||||||
|
this.inputValues = inputValues;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for inputValues
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public RunAssociatedScriptInput withInputValues(Map<String, String> inputValues)
|
||||||
|
{
|
||||||
|
this.inputValues = inputValues;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.backend.core.model.actions.scripts;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.AbstractActionOutput;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public class RunAssociatedScriptOutput extends AbstractActionOutput
|
||||||
|
{
|
||||||
|
private Serializable output;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for output
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Serializable getOutput()
|
||||||
|
{
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for output
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setOutput(Serializable output)
|
||||||
|
{
|
||||||
|
this.output = output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for output
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public RunAssociatedScriptOutput withOutput(Serializable output)
|
||||||
|
{
|
||||||
|
this.output = output;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,188 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.backend.core.model.actions.scripts;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.AbstractTableActionInput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public class StoreAssociatedScriptInput extends AbstractTableActionInput
|
||||||
|
{
|
||||||
|
private String fieldName;
|
||||||
|
private Serializable recordPrimaryKey;
|
||||||
|
|
||||||
|
private String code;
|
||||||
|
private String commitMessage;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Constructor
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public StoreAssociatedScriptInput(QInstance instance)
|
||||||
|
{
|
||||||
|
super(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for fieldName
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getFieldName()
|
||||||
|
{
|
||||||
|
return fieldName;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for fieldName
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setFieldName(String fieldName)
|
||||||
|
{
|
||||||
|
this.fieldName = fieldName;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for fieldName
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public StoreAssociatedScriptInput withFieldName(String fieldName)
|
||||||
|
{
|
||||||
|
this.fieldName = fieldName;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for recordPrimaryKey
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Serializable getRecordPrimaryKey()
|
||||||
|
{
|
||||||
|
return recordPrimaryKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for recordPrimaryKey
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setRecordPrimaryKey(Serializable recordPrimaryKey)
|
||||||
|
{
|
||||||
|
this.recordPrimaryKey = recordPrimaryKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for recordPrimaryKey
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public StoreAssociatedScriptInput withRecordPrimaryKey(Serializable recordPrimaryKey)
|
||||||
|
{
|
||||||
|
this.recordPrimaryKey = recordPrimaryKey;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for code
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getCode()
|
||||||
|
{
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for code
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setCode(String code)
|
||||||
|
{
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for code
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public StoreAssociatedScriptInput withCode(String code)
|
||||||
|
{
|
||||||
|
this.code = code;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for commitMessage
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getCommitMessage()
|
||||||
|
{
|
||||||
|
return commitMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for commitMessage
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setCommitMessage(String commitMessage)
|
||||||
|
{
|
||||||
|
this.commitMessage = commitMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for commitMessage
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public StoreAssociatedScriptInput withCommitMessage(String commitMessage)
|
||||||
|
{
|
||||||
|
this.commitMessage = commitMessage;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.backend.core.model.actions.scripts;
|
||||||
|
|
||||||
|
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.AbstractActionOutput;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public class StoreAssociatedScriptOutput extends AbstractActionOutput
|
||||||
|
{
|
||||||
|
}
|
@ -0,0 +1,187 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.backend.core.model.actions.scripts;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Map;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.AbstractTableActionInput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public class TestScriptInput extends AbstractTableActionInput
|
||||||
|
{
|
||||||
|
private Serializable recordPrimaryKey;
|
||||||
|
private String code;
|
||||||
|
private Serializable scriptTypeId;
|
||||||
|
private Map<String, String> inputValues;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public TestScriptInput(QInstance qInstance)
|
||||||
|
{
|
||||||
|
super(qInstance);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for recordPrimaryKey
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Serializable getRecordPrimaryKey()
|
||||||
|
{
|
||||||
|
return recordPrimaryKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for recordPrimaryKey
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setRecordPrimaryKey(Serializable recordPrimaryKey)
|
||||||
|
{
|
||||||
|
this.recordPrimaryKey = recordPrimaryKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for recordPrimaryKey
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public TestScriptInput withRecordPrimaryKey(Serializable recordPrimaryKey)
|
||||||
|
{
|
||||||
|
this.recordPrimaryKey = recordPrimaryKey;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for inputValues
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Map<String, String> getInputValues()
|
||||||
|
{
|
||||||
|
return inputValues;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for inputValues
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setInputValues(Map<String, String> inputValues)
|
||||||
|
{
|
||||||
|
this.inputValues = inputValues;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for inputValues
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public TestScriptInput withInputValues(Map<String, String> inputValues)
|
||||||
|
{
|
||||||
|
this.inputValues = inputValues;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for code
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getCode()
|
||||||
|
{
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for code
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setCode(String code)
|
||||||
|
{
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for code
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public TestScriptInput withCode(String code)
|
||||||
|
{
|
||||||
|
this.code = code;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for scriptTypeId
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Serializable getScriptTypeId()
|
||||||
|
{
|
||||||
|
return scriptTypeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for scriptTypeId
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setScriptTypeId(Serializable scriptTypeId)
|
||||||
|
{
|
||||||
|
this.scriptTypeId = scriptTypeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for scriptTypeId
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public TestScriptInput withScriptTypeId(Serializable scriptTypeId)
|
||||||
|
{
|
||||||
|
this.scriptTypeId = scriptTypeId;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.backend.core.model.actions.scripts;
|
||||||
|
|
||||||
|
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.AbstractActionOutput;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public class TestScriptOutput extends AbstractActionOutput
|
||||||
|
{
|
||||||
|
}
|
@ -0,0 +1,175 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.backend.core.model.data;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalTime;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Optional;
|
||||||
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
|
import com.kingsrook.qqq.backend.core.utils.ListingHash;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Base class for enums that are interoperable with QRecords.
|
||||||
|
*******************************************************************************/
|
||||||
|
public interface QRecordEnum
|
||||||
|
{
|
||||||
|
ListingHash<Class<? extends QRecordEnum>, QRecordEntityField> fieldMapping = new ListingHash<>();
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Convert this entity to a QRecord.
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
default QRecord toQRecord() throws QException
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
QRecord qRecord = new QRecord();
|
||||||
|
|
||||||
|
List<QRecordEntityField> fieldList = getFieldList(this.getClass());
|
||||||
|
for(QRecordEntityField qRecordEntityField : fieldList)
|
||||||
|
{
|
||||||
|
qRecord.setValue(qRecordEntityField.getFieldName(), (Serializable) qRecordEntityField.getGetter().invoke(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
return (qRecord);
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
throw (new QException("Error building qRecord from entity.", e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public static List<QRecordEntityField> getFieldList(Class<? extends QRecordEnum> c)
|
||||||
|
{
|
||||||
|
if(!fieldMapping.containsKey(c))
|
||||||
|
{
|
||||||
|
List<QRecordEntityField> fieldList = new ArrayList<>();
|
||||||
|
for(Method possibleGetter : c.getMethods())
|
||||||
|
{
|
||||||
|
if(isGetter(possibleGetter))
|
||||||
|
{
|
||||||
|
String fieldName = getFieldNameFromGetter(possibleGetter);
|
||||||
|
Optional<QField> fieldAnnotation = getQFieldAnnotation(c, fieldName);
|
||||||
|
fieldList.add(new QRecordEntityField(fieldName, possibleGetter, null, possibleGetter.getReturnType(), fieldAnnotation.orElse(null)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fieldMapping.put(c, fieldList);
|
||||||
|
}
|
||||||
|
return (fieldMapping.get(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public static Optional<QField> getQFieldAnnotation(Class<? extends QRecordEnum> c, String fieldName)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Field field = c.getDeclaredField(fieldName);
|
||||||
|
return (Optional.ofNullable(field.getAnnotation(QField.class)));
|
||||||
|
}
|
||||||
|
catch(NoSuchFieldException e)
|
||||||
|
{
|
||||||
|
//////////////////////////////////////////
|
||||||
|
// ok, we just won't have an annotation //
|
||||||
|
//////////////////////////////////////////
|
||||||
|
}
|
||||||
|
return (Optional.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public static String getFieldNameFromGetter(Method getter)
|
||||||
|
{
|
||||||
|
String nameWithoutGet = getter.getName().replaceFirst("^get", "");
|
||||||
|
if(nameWithoutGet.length() == 1)
|
||||||
|
{
|
||||||
|
return (nameWithoutGet.toLowerCase(Locale.ROOT));
|
||||||
|
}
|
||||||
|
return (nameWithoutGet.substring(0, 1).toLowerCase(Locale.ROOT) + nameWithoutGet.substring(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private static boolean isGetter(Method method)
|
||||||
|
{
|
||||||
|
if(method.getParameterTypes().length == 0 && method.getName().matches("^get[A-Z].*"))
|
||||||
|
{
|
||||||
|
if(isSupportedFieldType(method.getReturnType()))
|
||||||
|
{
|
||||||
|
return (true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(!method.getName().equals("getClass"))
|
||||||
|
{
|
||||||
|
System.err.println("Method [" + method.getName() + "] looks like a getter, but its return type, [" + method.getReturnType() + "], isn't supported.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private static boolean isSupportedFieldType(Class<?> returnType)
|
||||||
|
{
|
||||||
|
// todo - more types!!
|
||||||
|
return (returnType.equals(String.class)
|
||||||
|
|| returnType.equals(Integer.class)
|
||||||
|
|| returnType.equals(int.class)
|
||||||
|
|| returnType.equals(Boolean.class)
|
||||||
|
|| returnType.equals(boolean.class)
|
||||||
|
|| returnType.equals(BigDecimal.class)
|
||||||
|
|| returnType.equals(Instant.class)
|
||||||
|
|| returnType.equals(LocalDate.class)
|
||||||
|
|| returnType.equals(LocalTime.class));
|
||||||
|
/////////////////////////////////////////////
|
||||||
|
// note - this list has implications upon: //
|
||||||
|
// - QFieldType.fromClass //
|
||||||
|
// - QRecordEntityField.convertValueType //
|
||||||
|
/////////////////////////////////////////////
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,139 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.backend.core.model.metadata.code;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public class AssociatedScriptCodeReference extends QCodeReference
|
||||||
|
{
|
||||||
|
private String recordTable;
|
||||||
|
private Serializable recordPrimaryKey;
|
||||||
|
private String fieldName;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for recordTable
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getRecordTable()
|
||||||
|
{
|
||||||
|
return recordTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for recordTable
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setRecordTable(String recordTable)
|
||||||
|
{
|
||||||
|
this.recordTable = recordTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for recordTable
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public AssociatedScriptCodeReference withRecordTable(String recordTable)
|
||||||
|
{
|
||||||
|
this.recordTable = recordTable;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for recordPrimaryKey
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Serializable getRecordPrimaryKey()
|
||||||
|
{
|
||||||
|
return recordPrimaryKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for recordPrimaryKey
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setRecordPrimaryKey(Serializable recordPrimaryKey)
|
||||||
|
{
|
||||||
|
this.recordPrimaryKey = recordPrimaryKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for recordPrimaryKey
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public AssociatedScriptCodeReference withRecordPrimaryKey(Serializable recordPrimaryKey)
|
||||||
|
{
|
||||||
|
this.recordPrimaryKey = recordPrimaryKey;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for fieldName
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getFieldName()
|
||||||
|
{
|
||||||
|
return fieldName;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for fieldName
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setFieldName(String fieldName)
|
||||||
|
{
|
||||||
|
this.fieldName = fieldName;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for fieldName
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public AssociatedScriptCodeReference withFieldName(String fieldName)
|
||||||
|
{
|
||||||
|
this.fieldName = fieldName;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -38,6 +38,8 @@ public class QCodeReference implements Serializable
|
|||||||
private QCodeType codeType;
|
private QCodeType codeType;
|
||||||
private QCodeUsage codeUsage;
|
private QCodeUsage codeUsage;
|
||||||
|
|
||||||
|
private String inlineCode;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
@ -212,4 +214,38 @@ public class QCodeReference implements Serializable
|
|||||||
return (this);
|
return (this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for inlineCode
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getInlineCode()
|
||||||
|
{
|
||||||
|
return inlineCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for inlineCode
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setInlineCode(String inlineCode)
|
||||||
|
{
|
||||||
|
this.inlineCode = inlineCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for inlineCode
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public QCodeReference withInlineCode(String inlineCode)
|
||||||
|
{
|
||||||
|
this.inlineCode = inlineCode;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -28,5 +28,6 @@ package com.kingsrook.qqq.backend.core.model.metadata.code;
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public enum QCodeType
|
public enum QCodeType
|
||||||
{
|
{
|
||||||
JAVA
|
JAVA,
|
||||||
|
JAVA_SCRIPT
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,104 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.backend.core.model.metadata.tables;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public class AssociatedScript implements Serializable
|
||||||
|
{
|
||||||
|
private String fieldName;
|
||||||
|
private Serializable scriptTypeId;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for fieldName
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getFieldName()
|
||||||
|
{
|
||||||
|
return fieldName;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for fieldName
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setFieldName(String fieldName)
|
||||||
|
{
|
||||||
|
this.fieldName = fieldName;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for fieldName
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public AssociatedScript withFieldName(String fieldName)
|
||||||
|
{
|
||||||
|
this.fieldName = fieldName;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for scriptTypeId
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Serializable getScriptTypeId()
|
||||||
|
{
|
||||||
|
return scriptTypeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for scriptTypeId
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setScriptTypeId(Serializable scriptTypeId)
|
||||||
|
{
|
||||||
|
this.scriptTypeId = scriptTypeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for scriptTypeId
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public AssociatedScript withScriptTypeId(Serializable scriptTypeId)
|
||||||
|
{
|
||||||
|
this.scriptTypeId = scriptTypeId;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -79,6 +79,7 @@ public class QTableMetaData implements QAppChildMetaData, Serializable
|
|||||||
private List<QFieldSection> sections;
|
private List<QFieldSection> sections;
|
||||||
|
|
||||||
private List<String> widgets;
|
private List<String> widgets;
|
||||||
|
private List<AssociatedScript> associatedScripts;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -754,6 +755,56 @@ public class QTableMetaData implements QAppChildMetaData, Serializable
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for associatedScripts
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public List<AssociatedScript> getAssociatedScripts()
|
||||||
|
{
|
||||||
|
return associatedScripts;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for associatedScripts
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setAssociatedScripts(List<AssociatedScript> associatedScripts)
|
||||||
|
{
|
||||||
|
this.associatedScripts = associatedScripts;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for associatedScripts
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public QTableMetaData withAssociatedScripts(List<AssociatedScript> associatedScripts)
|
||||||
|
{
|
||||||
|
this.associatedScripts = associatedScripts;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for associatedScripts
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public QTableMetaData withAssociatedScript(AssociatedScript associatedScript)
|
||||||
|
{
|
||||||
|
if(this.associatedScripts == null)
|
||||||
|
{
|
||||||
|
this.associatedScripts = new ArrayList();
|
||||||
|
}
|
||||||
|
this.associatedScripts.add(associatedScript);
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** Getter for uniqueKeys
|
** Getter for uniqueKeys
|
||||||
**
|
**
|
||||||
|
@ -0,0 +1,282 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.backend.core.model.scripts;
|
||||||
|
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.data.QField;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.data.QRecordEntity;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public class Script extends QRecordEntity
|
||||||
|
{
|
||||||
|
public static final String TABLE_NAME = "script";
|
||||||
|
|
||||||
|
@QField()
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
@QField()
|
||||||
|
private Instant createDate;
|
||||||
|
|
||||||
|
@QField()
|
||||||
|
private Instant modifyDate;
|
||||||
|
|
||||||
|
@QField()
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@QField()
|
||||||
|
private Integer scriptTypeId;
|
||||||
|
|
||||||
|
@QField()
|
||||||
|
private Integer currentScriptRevisionId;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Constructor
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Script()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Constructor
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Script(QRecord qRecord) throws QException
|
||||||
|
{
|
||||||
|
populateFromQRecord(qRecord);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for id
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Integer getId()
|
||||||
|
{
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for id
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setId(Integer id)
|
||||||
|
{
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for id
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Script withId(Integer id)
|
||||||
|
{
|
||||||
|
this.id = id;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for createDate
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Instant getCreateDate()
|
||||||
|
{
|
||||||
|
return createDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for createDate
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setCreateDate(Instant createDate)
|
||||||
|
{
|
||||||
|
this.createDate = createDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for createDate
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Script withCreateDate(Instant createDate)
|
||||||
|
{
|
||||||
|
this.createDate = createDate;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for modifyDate
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Instant getModifyDate()
|
||||||
|
{
|
||||||
|
return modifyDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for modifyDate
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setModifyDate(Instant modifyDate)
|
||||||
|
{
|
||||||
|
this.modifyDate = modifyDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for modifyDate
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Script withModifyDate(Instant modifyDate)
|
||||||
|
{
|
||||||
|
this.modifyDate = modifyDate;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for name
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getName()
|
||||||
|
{
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for name
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setName(String name)
|
||||||
|
{
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for name
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Script withName(String name)
|
||||||
|
{
|
||||||
|
this.name = name;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for scriptTypeId
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Integer getScriptTypeId()
|
||||||
|
{
|
||||||
|
return scriptTypeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for scriptTypeId
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setScriptTypeId(Integer scriptTypeId)
|
||||||
|
{
|
||||||
|
this.scriptTypeId = scriptTypeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for scriptTypeId
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Script withScriptTypeId(Integer scriptTypeId)
|
||||||
|
{
|
||||||
|
this.scriptTypeId = scriptTypeId;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for currentScriptRevisionId
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Integer getCurrentScriptRevisionId()
|
||||||
|
{
|
||||||
|
return currentScriptRevisionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for currentScriptRevisionId
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setCurrentScriptRevisionId(Integer currentScriptRevisionId)
|
||||||
|
{
|
||||||
|
this.currentScriptRevisionId = currentScriptRevisionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for currentScriptRevisionId
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Script withCurrentScriptRevisionId(Integer currentScriptRevisionId)
|
||||||
|
{
|
||||||
|
this.currentScriptRevisionId = currentScriptRevisionId;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,481 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.backend.core.model.scripts;
|
||||||
|
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.data.QField;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.data.QRecordEntity;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public class ScriptLog extends QRecordEntity
|
||||||
|
{
|
||||||
|
public static final String TABLE_NAME = "scriptLog";
|
||||||
|
|
||||||
|
@QField()
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
@QField()
|
||||||
|
private Instant createDate;
|
||||||
|
|
||||||
|
@QField()
|
||||||
|
private Instant modifyDate;
|
||||||
|
|
||||||
|
@QField()
|
||||||
|
private Integer scriptId;
|
||||||
|
|
||||||
|
@QField()
|
||||||
|
private Integer scriptRevisionId;
|
||||||
|
|
||||||
|
@QField()
|
||||||
|
private Instant startTimestamp;
|
||||||
|
|
||||||
|
@QField()
|
||||||
|
private Instant endTimestamp;
|
||||||
|
|
||||||
|
@QField()
|
||||||
|
private Integer runTimeMillis;
|
||||||
|
|
||||||
|
@QField()
|
||||||
|
private Boolean hadError;
|
||||||
|
|
||||||
|
@QField()
|
||||||
|
private String input;
|
||||||
|
|
||||||
|
@QField()
|
||||||
|
private String output;
|
||||||
|
|
||||||
|
@QField()
|
||||||
|
private String error;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for id
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Integer getId()
|
||||||
|
{
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for id
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setId(Integer id)
|
||||||
|
{
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for id
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public ScriptLog withId(Integer id)
|
||||||
|
{
|
||||||
|
this.id = id;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for createDate
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Instant getCreateDate()
|
||||||
|
{
|
||||||
|
return createDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for createDate
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setCreateDate(Instant createDate)
|
||||||
|
{
|
||||||
|
this.createDate = createDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for createDate
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public ScriptLog withCreateDate(Instant createDate)
|
||||||
|
{
|
||||||
|
this.createDate = createDate;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for modifyDate
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Instant getModifyDate()
|
||||||
|
{
|
||||||
|
return modifyDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for modifyDate
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setModifyDate(Instant modifyDate)
|
||||||
|
{
|
||||||
|
this.modifyDate = modifyDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for modifyDate
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public ScriptLog withModifyDate(Instant modifyDate)
|
||||||
|
{
|
||||||
|
this.modifyDate = modifyDate;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for scriptId
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Integer getScriptId()
|
||||||
|
{
|
||||||
|
return scriptId;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for scriptId
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setScriptId(Integer scriptId)
|
||||||
|
{
|
||||||
|
this.scriptId = scriptId;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for scriptId
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public ScriptLog withScriptId(Integer scriptId)
|
||||||
|
{
|
||||||
|
this.scriptId = scriptId;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for scriptRevisionId
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Integer getScriptRevisionId()
|
||||||
|
{
|
||||||
|
return scriptRevisionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for scriptRevisionId
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setScriptRevisionId(Integer scriptRevisionId)
|
||||||
|
{
|
||||||
|
this.scriptRevisionId = scriptRevisionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for scriptRevisionId
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public ScriptLog withScriptRevisionId(Integer scriptRevisionId)
|
||||||
|
{
|
||||||
|
this.scriptRevisionId = scriptRevisionId;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for startTimestamp
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Instant getStartTimestamp()
|
||||||
|
{
|
||||||
|
return startTimestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for startTimestamp
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setStartTimestamp(Instant startTimestamp)
|
||||||
|
{
|
||||||
|
this.startTimestamp = startTimestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for startTimestamp
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public ScriptLog withStartTimestamp(Instant startTimestamp)
|
||||||
|
{
|
||||||
|
this.startTimestamp = startTimestamp;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for endTimestamp
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Instant getEndTimestamp()
|
||||||
|
{
|
||||||
|
return endTimestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for endTimestamp
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setEndTimestamp(Instant endTimestamp)
|
||||||
|
{
|
||||||
|
this.endTimestamp = endTimestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for endTimestamp
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public ScriptLog withEndTimestamp(Instant endTimestamp)
|
||||||
|
{
|
||||||
|
this.endTimestamp = endTimestamp;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for runTimeMillis
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Integer getRunTimeMillis()
|
||||||
|
{
|
||||||
|
return runTimeMillis;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for runTimeMillis
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setRunTimeMillis(Integer runTimeMillis)
|
||||||
|
{
|
||||||
|
this.runTimeMillis = runTimeMillis;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for runTimeMillis
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public ScriptLog withRunTimeMillis(Integer runTimeMillis)
|
||||||
|
{
|
||||||
|
this.runTimeMillis = runTimeMillis;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for hadError
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Boolean getHadError()
|
||||||
|
{
|
||||||
|
return hadError;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for hadError
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setHadError(Boolean hadError)
|
||||||
|
{
|
||||||
|
this.hadError = hadError;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for hadError
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public ScriptLog withHadError(Boolean hadError)
|
||||||
|
{
|
||||||
|
this.hadError = hadError;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for input
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getInput()
|
||||||
|
{
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for input
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setInput(String input)
|
||||||
|
{
|
||||||
|
this.input = input;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for input
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public ScriptLog withInput(String input)
|
||||||
|
{
|
||||||
|
this.input = input;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for output
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getOutput()
|
||||||
|
{
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for output
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setOutput(String output)
|
||||||
|
{
|
||||||
|
this.output = output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for output
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public ScriptLog withOutput(String output)
|
||||||
|
{
|
||||||
|
this.output = output;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for error
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getError()
|
||||||
|
{
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for error
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setError(String error)
|
||||||
|
{
|
||||||
|
this.error = error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for error
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public ScriptLog withError(String error)
|
||||||
|
{
|
||||||
|
this.error = error;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,259 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.backend.core.model.scripts;
|
||||||
|
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.data.QField;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.data.QRecordEntity;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public class ScriptLogLine extends QRecordEntity
|
||||||
|
{
|
||||||
|
public static final String TABLE_NAME = "scriptLogLine";
|
||||||
|
|
||||||
|
@QField()
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
@QField()
|
||||||
|
private Instant createDate;
|
||||||
|
|
||||||
|
@QField()
|
||||||
|
private Instant modifyDate;
|
||||||
|
|
||||||
|
@QField()
|
||||||
|
private Integer scriptLogId;
|
||||||
|
|
||||||
|
@QField()
|
||||||
|
private Instant timestamp;
|
||||||
|
|
||||||
|
@QField()
|
||||||
|
private String text;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for id
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Integer getId()
|
||||||
|
{
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for id
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setId(Integer id)
|
||||||
|
{
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for id
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public ScriptLogLine withId(Integer id)
|
||||||
|
{
|
||||||
|
this.id = id;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for createDate
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Instant getCreateDate()
|
||||||
|
{
|
||||||
|
return createDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for createDate
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setCreateDate(Instant createDate)
|
||||||
|
{
|
||||||
|
this.createDate = createDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for createDate
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public ScriptLogLine withCreateDate(Instant createDate)
|
||||||
|
{
|
||||||
|
this.createDate = createDate;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for modifyDate
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Instant getModifyDate()
|
||||||
|
{
|
||||||
|
return modifyDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for modifyDate
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setModifyDate(Instant modifyDate)
|
||||||
|
{
|
||||||
|
this.modifyDate = modifyDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for modifyDate
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public ScriptLogLine withModifyDate(Instant modifyDate)
|
||||||
|
{
|
||||||
|
this.modifyDate = modifyDate;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for scriptLogId
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Integer getScriptLogId()
|
||||||
|
{
|
||||||
|
return scriptLogId;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for scriptLogId
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setScriptLogId(Integer scriptLogId)
|
||||||
|
{
|
||||||
|
this.scriptLogId = scriptLogId;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for scriptLogId
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public ScriptLogLine withScriptLogId(Integer scriptLogId)
|
||||||
|
{
|
||||||
|
this.scriptLogId = scriptLogId;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for timestamp
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Instant getTimestamp()
|
||||||
|
{
|
||||||
|
return timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for timestamp
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setTimestamp(Instant timestamp)
|
||||||
|
{
|
||||||
|
this.timestamp = timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for timestamp
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public ScriptLogLine withTimestamp(Instant timestamp)
|
||||||
|
{
|
||||||
|
this.timestamp = timestamp;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for text
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getText()
|
||||||
|
{
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for text
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setText(String text)
|
||||||
|
{
|
||||||
|
this.text = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for text
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public ScriptLogLine withText(String text)
|
||||||
|
{
|
||||||
|
this.text = text;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,356 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.backend.core.model.scripts;
|
||||||
|
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.data.QField;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.data.QRecordEntity;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public class ScriptRevision extends QRecordEntity
|
||||||
|
{
|
||||||
|
public static final String TABLE_NAME = "scriptRevision";
|
||||||
|
|
||||||
|
@QField()
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
@QField()
|
||||||
|
private Instant createDate;
|
||||||
|
|
||||||
|
@QField()
|
||||||
|
private Instant modifyDate;
|
||||||
|
|
||||||
|
@QField()
|
||||||
|
private Integer scriptId;
|
||||||
|
|
||||||
|
@QField()
|
||||||
|
private String contents;
|
||||||
|
|
||||||
|
@QField()
|
||||||
|
private Integer sequenceNo;
|
||||||
|
|
||||||
|
@QField()
|
||||||
|
private String commitMessage;
|
||||||
|
|
||||||
|
@QField()
|
||||||
|
private String author;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Constructor
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public ScriptRevision()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Constructor
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public ScriptRevision(QRecord qRecord) throws QException
|
||||||
|
{
|
||||||
|
populateFromQRecord(qRecord);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for id
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Integer getId()
|
||||||
|
{
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for id
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setId(Integer id)
|
||||||
|
{
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for id
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public ScriptRevision withId(Integer id)
|
||||||
|
{
|
||||||
|
this.id = id;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for createDate
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Instant getCreateDate()
|
||||||
|
{
|
||||||
|
return createDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for createDate
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setCreateDate(Instant createDate)
|
||||||
|
{
|
||||||
|
this.createDate = createDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for createDate
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public ScriptRevision withCreateDate(Instant createDate)
|
||||||
|
{
|
||||||
|
this.createDate = createDate;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for modifyDate
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Instant getModifyDate()
|
||||||
|
{
|
||||||
|
return modifyDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for modifyDate
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setModifyDate(Instant modifyDate)
|
||||||
|
{
|
||||||
|
this.modifyDate = modifyDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for modifyDate
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public ScriptRevision withModifyDate(Instant modifyDate)
|
||||||
|
{
|
||||||
|
this.modifyDate = modifyDate;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for scriptId
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Integer getScriptId()
|
||||||
|
{
|
||||||
|
return scriptId;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for scriptId
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setScriptId(Integer scriptId)
|
||||||
|
{
|
||||||
|
this.scriptId = scriptId;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for scriptId
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public ScriptRevision withScriptId(Integer scriptId)
|
||||||
|
{
|
||||||
|
this.scriptId = scriptId;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for contents
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getContents()
|
||||||
|
{
|
||||||
|
return contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for contents
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setContents(String contents)
|
||||||
|
{
|
||||||
|
this.contents = contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for contents
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public ScriptRevision withContents(String contents)
|
||||||
|
{
|
||||||
|
this.contents = contents;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for sequenceNo
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Integer getSequenceNo()
|
||||||
|
{
|
||||||
|
return sequenceNo;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for sequenceNo
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setSequenceNo(Integer sequenceNo)
|
||||||
|
{
|
||||||
|
this.sequenceNo = sequenceNo;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for sequenceNo
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public ScriptRevision withSequenceNo(Integer sequenceNo)
|
||||||
|
{
|
||||||
|
this.sequenceNo = sequenceNo;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for commitMessage
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getCommitMessage()
|
||||||
|
{
|
||||||
|
return commitMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for commitMessage
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setCommitMessage(String commitMessage)
|
||||||
|
{
|
||||||
|
this.commitMessage = commitMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for commitMessage
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public ScriptRevision withCommitMessage(String commitMessage)
|
||||||
|
{
|
||||||
|
this.commitMessage = commitMessage;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for author
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getAuthor()
|
||||||
|
{
|
||||||
|
return author;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for author
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setAuthor(String author)
|
||||||
|
{
|
||||||
|
this.author = author;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for author
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public ScriptRevision withAuthor(String author)
|
||||||
|
{
|
||||||
|
this.author = author;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,259 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.backend.core.model.scripts;
|
||||||
|
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.data.QField;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.data.QRecordEntity;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public class ScriptType extends QRecordEntity
|
||||||
|
{
|
||||||
|
public static final String TABLE_NAME = "scriptType";
|
||||||
|
|
||||||
|
@QField()
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
@QField()
|
||||||
|
private Instant createDate;
|
||||||
|
|
||||||
|
@QField()
|
||||||
|
private Instant modifyDate;
|
||||||
|
|
||||||
|
@QField()
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@QField()
|
||||||
|
private String helpText;
|
||||||
|
|
||||||
|
@QField()
|
||||||
|
private String sampleCode;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for id
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Integer getId()
|
||||||
|
{
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for id
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setId(Integer id)
|
||||||
|
{
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for id
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public ScriptType withId(Integer id)
|
||||||
|
{
|
||||||
|
this.id = id;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for createDate
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Instant getCreateDate()
|
||||||
|
{
|
||||||
|
return createDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for createDate
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setCreateDate(Instant createDate)
|
||||||
|
{
|
||||||
|
this.createDate = createDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for createDate
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public ScriptType withCreateDate(Instant createDate)
|
||||||
|
{
|
||||||
|
this.createDate = createDate;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for modifyDate
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Instant getModifyDate()
|
||||||
|
{
|
||||||
|
return modifyDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for modifyDate
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setModifyDate(Instant modifyDate)
|
||||||
|
{
|
||||||
|
this.modifyDate = modifyDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for modifyDate
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public ScriptType withModifyDate(Instant modifyDate)
|
||||||
|
{
|
||||||
|
this.modifyDate = modifyDate;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for name
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getName()
|
||||||
|
{
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for name
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setName(String name)
|
||||||
|
{
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for name
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public ScriptType withName(String name)
|
||||||
|
{
|
||||||
|
this.name = name;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for helpText
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getHelpText()
|
||||||
|
{
|
||||||
|
return helpText;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for helpText
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setHelpText(String helpText)
|
||||||
|
{
|
||||||
|
this.helpText = helpText;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for helpText
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public ScriptType withHelpText(String helpText)
|
||||||
|
{
|
||||||
|
this.helpText = helpText;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for sampleCode
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getSampleCode()
|
||||||
|
{
|
||||||
|
return sampleCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for sampleCode
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setSampleCode(String sampleCode)
|
||||||
|
{
|
||||||
|
this.sampleCode = sampleCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for sampleCode
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public ScriptType withSampleCode(String sampleCode)
|
||||||
|
{
|
||||||
|
this.sampleCode = sampleCode;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,150 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.backend.core.model.scripts;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.data.QRecordEntity;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public class ScriptsMetaDataProvider
|
||||||
|
{
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void defineStandardScriptsTables(QInstance instance, String backendName, Consumer<QTableMetaData> backendDetailEnricher) throws QException
|
||||||
|
{
|
||||||
|
for(QTableMetaData tableMetaData : defineStandardScriptsTables(backendName, backendDetailEnricher))
|
||||||
|
{
|
||||||
|
instance.addTable(tableMetaData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public List<QTableMetaData> defineStandardScriptsTables(String backendName, Consumer<QTableMetaData> backendDetailEnricher) throws QException
|
||||||
|
{
|
||||||
|
List<QTableMetaData> rs = new ArrayList<>();
|
||||||
|
rs.add(enrich(backendDetailEnricher, defineScriptTypeTable(backendName)));
|
||||||
|
rs.add(enrich(backendDetailEnricher, defineScriptTable(backendName)));
|
||||||
|
rs.add(enrich(backendDetailEnricher, defineScriptRevisionTable(backendName)));
|
||||||
|
rs.add(enrich(backendDetailEnricher, defineScriptLogTable(backendName)));
|
||||||
|
rs.add(enrich(backendDetailEnricher, defineScriptLogLineTable(backendName)));
|
||||||
|
return (rs);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private QTableMetaData enrich(Consumer<QTableMetaData> backendDetailEnricher, QTableMetaData table)
|
||||||
|
{
|
||||||
|
if(backendDetailEnricher != null)
|
||||||
|
{
|
||||||
|
backendDetailEnricher.accept(table);
|
||||||
|
}
|
||||||
|
return (table);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private QTableMetaData defineStandardTable(String backendName, String name, Class<? extends QRecordEntity> fieldsFromEntity) throws QException
|
||||||
|
{
|
||||||
|
return new QTableMetaData()
|
||||||
|
.withName(name)
|
||||||
|
.withBackendName(backendName)
|
||||||
|
.withRecordLabelFormat("%s")
|
||||||
|
.withRecordLabelFields("name")
|
||||||
|
.withPrimaryKeyField("id")
|
||||||
|
.withFieldsFromEntity(fieldsFromEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private QTableMetaData defineScriptTable(String backendName) throws QException
|
||||||
|
{
|
||||||
|
return (defineStandardTable(backendName, Script.TABLE_NAME, Script.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private QTableMetaData defineScriptTypeTable(String backendName) throws QException
|
||||||
|
{
|
||||||
|
return (defineStandardTable(backendName, ScriptType.TABLE_NAME, ScriptType.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private QTableMetaData defineScriptRevisionTable(String backendName) throws QException
|
||||||
|
{
|
||||||
|
return (defineStandardTable(backendName, ScriptRevision.TABLE_NAME, ScriptRevision.class)
|
||||||
|
.withRecordLabelFields(List.of("id")));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private QTableMetaData defineScriptLogTable(String backendName) throws QException
|
||||||
|
{
|
||||||
|
return (defineStandardTable(backendName, ScriptLog.TABLE_NAME, ScriptLog.class)
|
||||||
|
.withRecordLabelFields(List.of("id")));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private QTableMetaData defineScriptLogLineTable(String backendName) throws QException
|
||||||
|
{
|
||||||
|
return (defineStandardTable(backendName, ScriptLogLine.TABLE_NAME, ScriptLogLine.class)
|
||||||
|
.withRecordLabelFields(List.of("id")));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -73,6 +73,7 @@ public class QBackendModuleDispatcher
|
|||||||
// e.g., backend-core shouldn't need to "know" about the modules.
|
// e.g., backend-core shouldn't need to "know" about the modules.
|
||||||
"com.kingsrook.qqq.backend.core.modules.backend.implementations.mock.MockBackendModule",
|
"com.kingsrook.qqq.backend.core.modules.backend.implementations.mock.MockBackendModule",
|
||||||
"com.kingsrook.qqq.backend.core.modules.backend.implementations.memory.MemoryBackendModule",
|
"com.kingsrook.qqq.backend.core.modules.backend.implementations.memory.MemoryBackendModule",
|
||||||
|
"com.kingsrook.qqq.backend.core.modules.backend.implementations.enumeration.EnumerationBackendModule",
|
||||||
"com.kingsrook.qqq.backend.module.rdbms.RDBMSBackendModule",
|
"com.kingsrook.qqq.backend.module.rdbms.RDBMSBackendModule",
|
||||||
"com.kingsrook.qqq.backend.module.filesystem.local.FilesystemBackendModule",
|
"com.kingsrook.qqq.backend.module.filesystem.local.FilesystemBackendModule",
|
||||||
"com.kingsrook.qqq.backend.module.filesystem.s3.S3BackendModule",
|
"com.kingsrook.qqq.backend.module.filesystem.s3.S3BackendModule",
|
||||||
|
@ -49,7 +49,10 @@ public interface QBackendModuleInterface
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** Method to identify the class used for backend meta data for this module.
|
** Method to identify the class used for backend meta data for this module.
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
Class<? extends QBackendMetaData> getBackendMetaDataClass();
|
default Class<? extends QBackendMetaData> getBackendMetaDataClass()
|
||||||
|
{
|
||||||
|
return (QBackendMetaData.class);
|
||||||
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** Method to identify the class used for table-backend details for this module.
|
** Method to identify the class used for table-backend details for this module.
|
||||||
|
@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.backend.core.modules.backend.implementations.enumeration;
|
||||||
|
|
||||||
|
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.interfaces.QueryInterface;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableBackendDetails;
|
||||||
|
import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleInterface;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public class EnumerationBackendModule implements QBackendModuleInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Method where a backend module must be able to provide its type (name).
|
||||||
|
*******************************************************************************/
|
||||||
|
@Override
|
||||||
|
public String getBackendType()
|
||||||
|
{
|
||||||
|
return ("enum");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Override
|
||||||
|
public Class<? extends QTableBackendDetails> getTableBackendDetailsClass()
|
||||||
|
{
|
||||||
|
return (EnumerationTableBackendDetails.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Override
|
||||||
|
public QueryInterface getQueryInterface()
|
||||||
|
{
|
||||||
|
return new EnumerationQueryAction();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.backend.core.modules.backend.implementations.enumeration;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.interfaces.QueryInterface;
|
||||||
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.data.QRecordEnum;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.modules.backend.implementations.utils.BackendQueryFilterUtils;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public class EnumerationQueryAction implements QueryInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Override
|
||||||
|
public QueryOutput execute(QueryInput queryInput) throws QException
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
QTableMetaData table = queryInput.getTable();
|
||||||
|
EnumerationTableBackendDetails backendDetails = (EnumerationTableBackendDetails) table.getBackendDetails();
|
||||||
|
Class<? extends QRecordEnum> enumClass = backendDetails.getEnumClass();
|
||||||
|
QRecordEnum[] values = (QRecordEnum[]) enumClass.getMethod("values").invoke(null);
|
||||||
|
|
||||||
|
//////////////////////////////////////////////
|
||||||
|
// note - not good streaming behavior here. //
|
||||||
|
//////////////////////////////////////////////
|
||||||
|
|
||||||
|
List<QRecord> recordList = new ArrayList<>();
|
||||||
|
for(QRecordEnum value : values)
|
||||||
|
{
|
||||||
|
QRecord record = value.toQRecord();
|
||||||
|
boolean recordMatches = BackendQueryFilterUtils.doesRecordMatch(queryInput.getFilter(), record);
|
||||||
|
if(recordMatches)
|
||||||
|
{
|
||||||
|
recordList.add(record);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BackendQueryFilterUtils.sortRecordList(queryInput.getFilter(), recordList);
|
||||||
|
recordList = BackendQueryFilterUtils.applySkipAndLimit(queryInput, recordList);
|
||||||
|
|
||||||
|
QueryOutput queryOutput = new QueryOutput(queryInput);
|
||||||
|
queryOutput.addRecords(recordList);
|
||||||
|
return queryOutput;
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
throw (new QException("Error executing query", e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.backend.core.modules.backend.implementations.enumeration;
|
||||||
|
|
||||||
|
|
||||||
|
import com.kingsrook.qqq.backend.core.model.data.QRecordEnum;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableBackendDetails;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public class EnumerationTableBackendDetails extends QTableBackendDetails
|
||||||
|
{
|
||||||
|
private Class<? extends QRecordEnum> enumClass;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Constructor
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public EnumerationTableBackendDetails()
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
setBackendType(EnumerationBackendModule.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for enumClass
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Class<? extends QRecordEnum> getEnumClass()
|
||||||
|
{
|
||||||
|
return enumClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for enumClass
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setEnumClass(Class<? extends QRecordEnum> enumClass)
|
||||||
|
{
|
||||||
|
this.enumClass = enumClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for enumClass
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public EnumerationTableBackendDetails withEnumClass(Class<? extends QRecordEnum> enumClass)
|
||||||
|
{
|
||||||
|
this.enumClass = enumClass;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -27,7 +27,6 @@ import com.kingsrook.qqq.backend.core.actions.interfaces.DeleteInterface;
|
|||||||
import com.kingsrook.qqq.backend.core.actions.interfaces.InsertInterface;
|
import com.kingsrook.qqq.backend.core.actions.interfaces.InsertInterface;
|
||||||
import com.kingsrook.qqq.backend.core.actions.interfaces.QueryInterface;
|
import com.kingsrook.qqq.backend.core.actions.interfaces.QueryInterface;
|
||||||
import com.kingsrook.qqq.backend.core.actions.interfaces.UpdateInterface;
|
import com.kingsrook.qqq.backend.core.actions.interfaces.UpdateInterface;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData;
|
|
||||||
import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleInterface;
|
import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleInterface;
|
||||||
|
|
||||||
|
|
||||||
@ -53,17 +52,6 @@ public class MemoryBackendModule implements QBackendModuleInterface
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
|
||||||
** Method to identify the class used for backend meta data for this module.
|
|
||||||
*******************************************************************************/
|
|
||||||
@Override
|
|
||||||
public Class<? extends QBackendMetaData> getBackendMetaDataClass()
|
|
||||||
{
|
|
||||||
return (QBackendMetaData.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
@ -23,27 +23,21 @@ package com.kingsrook.qqq.backend.core.modules.backend.implementations.memory;
|
|||||||
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.time.LocalDate;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.count.CountInput;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.count.CountInput;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.delete.DeleteInput;
|
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.insert.InsertInput;
|
||||||
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.QueryInput;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.update.UpdateInput;
|
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.data.QRecord;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
|
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
import com.kingsrook.qqq.backend.core.modules.backend.implementations.utils.BackendQueryFilterUtils;
|
||||||
import com.kingsrook.qqq.backend.core.utils.ValueUtils;
|
|
||||||
import org.apache.commons.lang.NotImplementedException;
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
@ -126,7 +120,7 @@ public class MemoryRecordStore
|
|||||||
|
|
||||||
for(QRecord qRecord : tableData.values())
|
for(QRecord qRecord : tableData.values())
|
||||||
{
|
{
|
||||||
boolean recordMatches = doesRecordMatch(input.getFilter(), qRecord);
|
boolean recordMatches = BackendQueryFilterUtils.doesRecordMatch(input.getFilter(), qRecord);
|
||||||
|
|
||||||
if(recordMatches)
|
if(recordMatches)
|
||||||
{
|
{
|
||||||
@ -139,349 +133,6 @@ public class MemoryRecordStore
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
|
||||||
**
|
|
||||||
*******************************************************************************/
|
|
||||||
@SuppressWarnings("checkstyle:indentation")
|
|
||||||
private boolean doesRecordMatch(QQueryFilter filter, QRecord qRecord)
|
|
||||||
{
|
|
||||||
if(filter == null || !filter.hasAnyCriteria())
|
|
||||||
{
|
|
||||||
return (true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// for an AND query, default to a TRUE answer, and we'll &= each criteria's value. //
|
|
||||||
// for an OR query, default to FALSE, and |= each criteria's value. //
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
AtomicBoolean recordMatches = new AtomicBoolean(filter.getBooleanOperator().equals(QQueryFilter.BooleanOperator.AND) ? true : false);
|
|
||||||
|
|
||||||
///////////////////////////////////////
|
|
||||||
// if there are criteria, apply them //
|
|
||||||
///////////////////////////////////////
|
|
||||||
for(QFilterCriteria criterion : CollectionUtils.nonNullList(filter.getCriteria()))
|
|
||||||
{
|
|
||||||
String fieldName = criterion.getFieldName();
|
|
||||||
Serializable value = qRecord.getValue(fieldName);
|
|
||||||
|
|
||||||
boolean criterionMatches = switch(criterion.getOperator())
|
|
||||||
{
|
|
||||||
case EQUALS -> testEquals(criterion, value);
|
|
||||||
case NOT_EQUALS -> !testEquals(criterion, value);
|
|
||||||
case IN -> testIn(criterion, value);
|
|
||||||
case NOT_IN -> !testIn(criterion, value);
|
|
||||||
case IS_BLANK -> testBlank(criterion, value);
|
|
||||||
case IS_NOT_BLANK -> !testBlank(criterion, value);
|
|
||||||
case CONTAINS -> testContains(criterion, fieldName, value);
|
|
||||||
case NOT_CONTAINS -> !testContains(criterion, fieldName, value);
|
|
||||||
case STARTS_WITH -> testStartsWith(criterion, fieldName, value);
|
|
||||||
case NOT_STARTS_WITH -> !testStartsWith(criterion, fieldName, value);
|
|
||||||
case ENDS_WITH -> testEndsWith(criterion, fieldName, value);
|
|
||||||
case NOT_ENDS_WITH -> !testEndsWith(criterion, fieldName, value);
|
|
||||||
case GREATER_THAN -> testGreaterThan(criterion, value);
|
|
||||||
case GREATER_THAN_OR_EQUALS -> testGreaterThan(criterion, value) || testEquals(criterion, value);
|
|
||||||
case LESS_THAN -> !testGreaterThan(criterion, value) && !testEquals(criterion, value);
|
|
||||||
case LESS_THAN_OR_EQUALS -> !testGreaterThan(criterion, value);
|
|
||||||
case BETWEEN ->
|
|
||||||
{
|
|
||||||
QFilterCriteria criteria0 = new QFilterCriteria().withValues(criterion.getValues());
|
|
||||||
QFilterCriteria criteria1 = new QFilterCriteria().withValues(new ArrayList<>(criterion.getValues()));
|
|
||||||
criteria1.getValues().remove(0);
|
|
||||||
yield (testGreaterThan(criteria0, value) || testEquals(criteria0, value)) && (!testGreaterThan(criteria1, value) || testEquals(criteria1, value));
|
|
||||||
}
|
|
||||||
case NOT_BETWEEN ->
|
|
||||||
{
|
|
||||||
QFilterCriteria criteria0 = new QFilterCriteria().withValues(criterion.getValues());
|
|
||||||
QFilterCriteria criteria1 = new QFilterCriteria().withValues(criterion.getValues());
|
|
||||||
criteria1.getValues().remove(0);
|
|
||||||
yield !(testGreaterThan(criteria0, value) || testEquals(criteria0, value)) && (!testGreaterThan(criteria1, value) || testEquals(criteria1, value));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// add this new value to the existing recordMatches value - and if we can short circuit the remaining checks, do so. //
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
Boolean shortCircuitValue = applyBooleanOperator(recordMatches, criterionMatches, filter.getBooleanOperator());
|
|
||||||
if(shortCircuitValue != null)
|
|
||||||
{
|
|
||||||
return (shortCircuitValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////
|
|
||||||
// apply sub-filters if there are any //
|
|
||||||
////////////////////////////////////////
|
|
||||||
for(QQueryFilter subFilter : CollectionUtils.nonNullList(filter.getSubFilters()))
|
|
||||||
{
|
|
||||||
boolean subFilterMatches = doesRecordMatch(subFilter, qRecord);
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// add this new value to the existing recordMatches value - and if we can short circuit the remaining checks, do so. //
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
Boolean shortCircuitValue = applyBooleanOperator(recordMatches, subFilterMatches, filter.getBooleanOperator());
|
|
||||||
if(shortCircuitValue != null)
|
|
||||||
{
|
|
||||||
return (shortCircuitValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (recordMatches.getPlain());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
|
||||||
** Based on an incoming boolean value (accumulator), a new value, and a boolean
|
|
||||||
** operator, update the accumulator, and if we can then short-circuit remaining
|
|
||||||
** operations, return a true or false. Returning null means to keep going.
|
|
||||||
*******************************************************************************/
|
|
||||||
private Boolean applyBooleanOperator(AtomicBoolean accumulator, boolean newValue, QQueryFilter.BooleanOperator booleanOperator)
|
|
||||||
{
|
|
||||||
boolean accumulatorValue = accumulator.getPlain();
|
|
||||||
if(booleanOperator.equals(QQueryFilter.BooleanOperator.AND))
|
|
||||||
{
|
|
||||||
accumulatorValue &= newValue;
|
|
||||||
if(!accumulatorValue)
|
|
||||||
{
|
|
||||||
return (false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
accumulatorValue |= newValue;
|
|
||||||
if(accumulatorValue)
|
|
||||||
{
|
|
||||||
return (true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
accumulator.set(accumulatorValue);
|
|
||||||
return (null);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
|
||||||
**
|
|
||||||
*******************************************************************************/
|
|
||||||
private boolean testBlank(QFilterCriteria criterion, Serializable value)
|
|
||||||
{
|
|
||||||
if(value == null)
|
|
||||||
{
|
|
||||||
return (true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if("".equals(ValueUtils.getValueAsString(value)))
|
|
||||||
{
|
|
||||||
return (true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (false);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
|
||||||
**
|
|
||||||
*******************************************************************************/
|
|
||||||
private boolean testGreaterThan(QFilterCriteria criterion, Serializable value)
|
|
||||||
{
|
|
||||||
Serializable criterionValue = criterion.getValues().get(0);
|
|
||||||
if(criterionValue == null)
|
|
||||||
{
|
|
||||||
throw (new IllegalArgumentException("Missing criterion value in query"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if(value == null)
|
|
||||||
{
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// a database would say 'false' for if a null column is > a value, so do the same. //
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
return (false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(value instanceof LocalDate valueDate && criterionValue instanceof LocalDate criterionValueDate)
|
|
||||||
{
|
|
||||||
return (valueDate.isAfter(criterionValueDate));
|
|
||||||
}
|
|
||||||
|
|
||||||
if(value instanceof Number valueNumber && criterionValue instanceof Number criterionValueNumber)
|
|
||||||
{
|
|
||||||
return (valueNumber.doubleValue() > criterionValueNumber.doubleValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
if(value instanceof LocalDate || criterionValue instanceof LocalDate)
|
|
||||||
{
|
|
||||||
LocalDate valueDate;
|
|
||||||
if(value instanceof LocalDate ld)
|
|
||||||
{
|
|
||||||
valueDate = ld;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
valueDate = ValueUtils.getValueAsLocalDate(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
LocalDate criterionDate;
|
|
||||||
if(criterionValue instanceof LocalDate ld)
|
|
||||||
{
|
|
||||||
criterionDate = ld;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
criterionDate = ValueUtils.getValueAsLocalDate(criterionValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (valueDate.isAfter(criterionDate));
|
|
||||||
}
|
|
||||||
|
|
||||||
throw (new NotImplementedException("Greater/Less Than comparisons are not (yet?) implemented for the supplied types [" + value.getClass().getSimpleName() + "][" + criterionValue.getClass().getSimpleName() + "]"));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
|
||||||
**
|
|
||||||
*******************************************************************************/
|
|
||||||
private boolean testIn(QFilterCriteria criterion, Serializable value)
|
|
||||||
{
|
|
||||||
if(!criterion.getValues().contains(value))
|
|
||||||
{
|
|
||||||
return (false);
|
|
||||||
}
|
|
||||||
return (true);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
|
||||||
**
|
|
||||||
*******************************************************************************/
|
|
||||||
private boolean testEquals(QFilterCriteria criterion, Serializable value)
|
|
||||||
{
|
|
||||||
if(value == null)
|
|
||||||
{
|
|
||||||
return (false);
|
|
||||||
}
|
|
||||||
|
|
||||||
Serializable criteriaValue = criterion.getValues().get(0);
|
|
||||||
if(value instanceof String && criteriaValue instanceof Number)
|
|
||||||
{
|
|
||||||
criteriaValue = String.valueOf(criteriaValue);
|
|
||||||
}
|
|
||||||
else if(criteriaValue instanceof String && value instanceof Number)
|
|
||||||
{
|
|
||||||
value = String.valueOf(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!value.equals(criteriaValue))
|
|
||||||
{
|
|
||||||
return (false);
|
|
||||||
}
|
|
||||||
return (true);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
|
||||||
**
|
|
||||||
*******************************************************************************/
|
|
||||||
private boolean testContains(QFilterCriteria criterion, String fieldName, Serializable value)
|
|
||||||
{
|
|
||||||
String stringValue = getStringFieldValue(value, fieldName, criterion);
|
|
||||||
String criterionValue = getFirstStringCriterionValue(criterion);
|
|
||||||
|
|
||||||
if(!stringValue.contains(criterionValue))
|
|
||||||
{
|
|
||||||
return (false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (true);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
|
||||||
**
|
|
||||||
*******************************************************************************/
|
|
||||||
private boolean testStartsWith(QFilterCriteria criterion, String fieldName, Serializable value)
|
|
||||||
{
|
|
||||||
String stringValue = getStringFieldValue(value, fieldName, criterion);
|
|
||||||
String criterionValue = getFirstStringCriterionValue(criterion);
|
|
||||||
|
|
||||||
if(!stringValue.startsWith(criterionValue))
|
|
||||||
{
|
|
||||||
return (false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (true);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
|
||||||
**
|
|
||||||
*******************************************************************************/
|
|
||||||
private boolean testEndsWith(QFilterCriteria criterion, String fieldName, Serializable value)
|
|
||||||
{
|
|
||||||
String stringValue = getStringFieldValue(value, fieldName, criterion);
|
|
||||||
String criterionValue = getFirstStringCriterionValue(criterion);
|
|
||||||
|
|
||||||
if(!stringValue.endsWith(criterionValue))
|
|
||||||
{
|
|
||||||
return (false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (true);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
|
||||||
**
|
|
||||||
*******************************************************************************/
|
|
||||||
private String getFirstStringCriterionValue(QFilterCriteria criteria)
|
|
||||||
{
|
|
||||||
if(CollectionUtils.nullSafeIsEmpty(criteria.getValues()))
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException("Missing value for [" + criteria.getOperator() + "] criteria on field [" + criteria.getFieldName() + "]");
|
|
||||||
}
|
|
||||||
Serializable value = criteria.getValues().get(0);
|
|
||||||
if(value == null)
|
|
||||||
{
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!(value instanceof String stringValue))
|
|
||||||
{
|
|
||||||
throw new ClassCastException("Value [" + value + "] for criteria [" + criteria.getFieldName() + "] is not a String, which is required for the [" + criteria.getOperator() + "] operator.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return (stringValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
|
||||||
**
|
|
||||||
*******************************************************************************/
|
|
||||||
private String getStringFieldValue(Serializable value, String fieldName, QFilterCriteria criterion)
|
|
||||||
{
|
|
||||||
if(value == null)
|
|
||||||
{
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!(value instanceof String stringValue))
|
|
||||||
{
|
|
||||||
throw new ClassCastException("Value [" + value + "] in field [" + fieldName + "] is not a String, which is required for the [" + criterion.getOperator() + "] operator.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return (stringValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
@ -0,0 +1,471 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.backend.core.modules.backend.implementations.utils;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
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.CollectionUtils;
|
||||||
|
import com.kingsrook.qqq.backend.core.utils.ValueUtils;
|
||||||
|
import org.apache.commons.lang.NotImplementedException;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public class BackendQueryFilterUtils
|
||||||
|
{
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@SuppressWarnings("checkstyle:indentation")
|
||||||
|
public static boolean doesRecordMatch(QQueryFilter filter, QRecord qRecord)
|
||||||
|
{
|
||||||
|
if(filter == null || !filter.hasAnyCriteria())
|
||||||
|
{
|
||||||
|
return (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// for an AND query, default to a TRUE answer, and we'll &= each criteria's value. //
|
||||||
|
// for an OR query, default to FALSE, and |= each criteria's value. //
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
AtomicBoolean recordMatches = new AtomicBoolean(filter.getBooleanOperator().equals(QQueryFilter.BooleanOperator.AND) ? true : false);
|
||||||
|
|
||||||
|
///////////////////////////////////////
|
||||||
|
// if there are criteria, apply them //
|
||||||
|
///////////////////////////////////////
|
||||||
|
for(QFilterCriteria criterion : CollectionUtils.nonNullList(filter.getCriteria()))
|
||||||
|
{
|
||||||
|
String fieldName = criterion.getFieldName();
|
||||||
|
Serializable value = qRecord.getValue(fieldName);
|
||||||
|
|
||||||
|
boolean criterionMatches = switch(criterion.getOperator())
|
||||||
|
{
|
||||||
|
case EQUALS -> testEquals(criterion, value);
|
||||||
|
case NOT_EQUALS -> !testEquals(criterion, value);
|
||||||
|
case IN -> testIn(criterion, value);
|
||||||
|
case NOT_IN -> !testIn(criterion, value);
|
||||||
|
case IS_BLANK -> testBlank(criterion, value);
|
||||||
|
case IS_NOT_BLANK -> !testBlank(criterion, value);
|
||||||
|
case CONTAINS -> testContains(criterion, fieldName, value);
|
||||||
|
case NOT_CONTAINS -> !testContains(criterion, fieldName, value);
|
||||||
|
case STARTS_WITH -> testStartsWith(criterion, fieldName, value);
|
||||||
|
case NOT_STARTS_WITH -> !testStartsWith(criterion, fieldName, value);
|
||||||
|
case ENDS_WITH -> testEndsWith(criterion, fieldName, value);
|
||||||
|
case NOT_ENDS_WITH -> !testEndsWith(criterion, fieldName, value);
|
||||||
|
case GREATER_THAN -> testGreaterThan(criterion, value);
|
||||||
|
case GREATER_THAN_OR_EQUALS -> testGreaterThan(criterion, value) || testEquals(criterion, value);
|
||||||
|
case LESS_THAN -> !testGreaterThan(criterion, value) && !testEquals(criterion, value);
|
||||||
|
case LESS_THAN_OR_EQUALS -> !testGreaterThan(criterion, value);
|
||||||
|
case BETWEEN ->
|
||||||
|
{
|
||||||
|
QFilterCriteria criteria0 = new QFilterCriteria().withValues(criterion.getValues());
|
||||||
|
QFilterCriteria criteria1 = new QFilterCriteria().withValues(new ArrayList<>(criterion.getValues()));
|
||||||
|
criteria1.getValues().remove(0);
|
||||||
|
yield (testGreaterThan(criteria0, value) || testEquals(criteria0, value)) && (!testGreaterThan(criteria1, value) || testEquals(criteria1, value));
|
||||||
|
}
|
||||||
|
case NOT_BETWEEN ->
|
||||||
|
{
|
||||||
|
QFilterCriteria criteria0 = new QFilterCriteria().withValues(criterion.getValues());
|
||||||
|
QFilterCriteria criteria1 = new QFilterCriteria().withValues(criterion.getValues());
|
||||||
|
criteria1.getValues().remove(0);
|
||||||
|
yield !(testGreaterThan(criteria0, value) || testEquals(criteria0, value)) && (!testGreaterThan(criteria1, value) || testEquals(criteria1, value));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// add this new value to the existing recordMatches value - and if we can short circuit the remaining checks, do so. //
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
Boolean shortCircuitValue = applyBooleanOperator(recordMatches, criterionMatches, filter.getBooleanOperator());
|
||||||
|
if(shortCircuitValue != null)
|
||||||
|
{
|
||||||
|
return (shortCircuitValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////
|
||||||
|
// apply sub-filters if there are any //
|
||||||
|
////////////////////////////////////////
|
||||||
|
for(QQueryFilter subFilter : CollectionUtils.nonNullList(filter.getSubFilters()))
|
||||||
|
{
|
||||||
|
boolean subFilterMatches = doesRecordMatch(subFilter, qRecord);
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// add this new value to the existing recordMatches value - and if we can short circuit the remaining checks, do so. //
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
Boolean shortCircuitValue = applyBooleanOperator(recordMatches, subFilterMatches, filter.getBooleanOperator());
|
||||||
|
if(shortCircuitValue != null)
|
||||||
|
{
|
||||||
|
return (shortCircuitValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (recordMatches.getPlain());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Based on an incoming boolean value (accumulator), a new value, and a boolean
|
||||||
|
** operator, update the accumulator, and if we can then short-circuit remaining
|
||||||
|
** operations, return a true or false. Returning null means to keep going.
|
||||||
|
*******************************************************************************/
|
||||||
|
private static Boolean applyBooleanOperator(AtomicBoolean accumulator, boolean newValue, QQueryFilter.BooleanOperator booleanOperator)
|
||||||
|
{
|
||||||
|
boolean accumulatorValue = accumulator.getPlain();
|
||||||
|
if(booleanOperator.equals(QQueryFilter.BooleanOperator.AND))
|
||||||
|
{
|
||||||
|
accumulatorValue &= newValue;
|
||||||
|
if(!accumulatorValue)
|
||||||
|
{
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
accumulatorValue |= newValue;
|
||||||
|
if(accumulatorValue)
|
||||||
|
{
|
||||||
|
return (true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
accumulator.set(accumulatorValue);
|
||||||
|
return (null);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private static boolean testBlank(QFilterCriteria criterion, Serializable value)
|
||||||
|
{
|
||||||
|
if(value == null)
|
||||||
|
{
|
||||||
|
return (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if("".equals(ValueUtils.getValueAsString(value)))
|
||||||
|
{
|
||||||
|
return (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private static boolean testGreaterThan(QFilterCriteria criterion, Serializable value)
|
||||||
|
{
|
||||||
|
Serializable criterionValue = criterion.getValues().get(0);
|
||||||
|
if(criterionValue == null)
|
||||||
|
{
|
||||||
|
throw (new IllegalArgumentException("Missing criterion value in query"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(value == null)
|
||||||
|
{
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// a database would say 'false' for if a null column is > a value, so do the same. //
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return isGreaterThan(criterionValue, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private static boolean isGreaterThan(Serializable a, Serializable b)
|
||||||
|
{
|
||||||
|
if(Objects.equals(a, b))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(b instanceof LocalDate valueDate && a instanceof LocalDate criterionValueDate)
|
||||||
|
{
|
||||||
|
return (valueDate.isAfter(criterionValueDate));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(b instanceof Number valueNumber && a instanceof Number criterionValueNumber)
|
||||||
|
{
|
||||||
|
return (valueNumber.doubleValue() > criterionValueNumber.doubleValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(b instanceof String valueString && a instanceof String criterionValueString)
|
||||||
|
{
|
||||||
|
return (valueString.compareTo(criterionValueString) > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(b instanceof LocalDate || a instanceof LocalDate)
|
||||||
|
{
|
||||||
|
LocalDate valueDate;
|
||||||
|
if(b instanceof LocalDate ld)
|
||||||
|
{
|
||||||
|
valueDate = ld;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
valueDate = ValueUtils.getValueAsLocalDate(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalDate criterionDate;
|
||||||
|
if(a instanceof LocalDate ld)
|
||||||
|
{
|
||||||
|
criterionDate = ld;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
criterionDate = ValueUtils.getValueAsLocalDate(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (valueDate.isAfter(criterionDate));
|
||||||
|
}
|
||||||
|
|
||||||
|
throw (new NotImplementedException("Greater/Less Than comparisons are not (yet?) implemented for the supplied types [" + b.getClass().getSimpleName() + "][" + a.getClass().getSimpleName() + "]"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private static boolean testIn(QFilterCriteria criterion, Serializable value)
|
||||||
|
{
|
||||||
|
if(!criterion.getValues().contains(value))
|
||||||
|
{
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
return (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private static boolean testEquals(QFilterCriteria criterion, Serializable value)
|
||||||
|
{
|
||||||
|
if(value == null)
|
||||||
|
{
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
Serializable criteriaValue = criterion.getValues().get(0);
|
||||||
|
if(value instanceof String && criteriaValue instanceof Number)
|
||||||
|
{
|
||||||
|
criteriaValue = String.valueOf(criteriaValue);
|
||||||
|
}
|
||||||
|
else if(criteriaValue instanceof String && value instanceof Number)
|
||||||
|
{
|
||||||
|
value = String.valueOf(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!value.equals(criteriaValue))
|
||||||
|
{
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
return (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private static boolean testContains(QFilterCriteria criterion, String fieldName, Serializable value)
|
||||||
|
{
|
||||||
|
String stringValue = getStringFieldValue(value, fieldName, criterion);
|
||||||
|
String criterionValue = getFirstStringCriterionValue(criterion);
|
||||||
|
|
||||||
|
if(!stringValue.contains(criterionValue))
|
||||||
|
{
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private static boolean testStartsWith(QFilterCriteria criterion, String fieldName, Serializable value)
|
||||||
|
{
|
||||||
|
String stringValue = getStringFieldValue(value, fieldName, criterion);
|
||||||
|
String criterionValue = getFirstStringCriterionValue(criterion);
|
||||||
|
|
||||||
|
if(!stringValue.startsWith(criterionValue))
|
||||||
|
{
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private static boolean testEndsWith(QFilterCriteria criterion, String fieldName, Serializable value)
|
||||||
|
{
|
||||||
|
String stringValue = getStringFieldValue(value, fieldName, criterion);
|
||||||
|
String criterionValue = getFirstStringCriterionValue(criterion);
|
||||||
|
|
||||||
|
if(!stringValue.endsWith(criterionValue))
|
||||||
|
{
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private static String getFirstStringCriterionValue(QFilterCriteria criteria)
|
||||||
|
{
|
||||||
|
if(CollectionUtils.nullSafeIsEmpty(criteria.getValues()))
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException("Missing value for [" + criteria.getOperator() + "] criteria on field [" + criteria.getFieldName() + "]");
|
||||||
|
}
|
||||||
|
Serializable value = criteria.getValues().get(0);
|
||||||
|
if(value == null)
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!(value instanceof String stringValue))
|
||||||
|
{
|
||||||
|
throw new ClassCastException("Value [" + value + "] for criteria [" + criteria.getFieldName() + "] is not a String, which is required for the [" + criteria.getOperator() + "] operator.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return (stringValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private static String getStringFieldValue(Serializable value, String fieldName, QFilterCriteria criterion)
|
||||||
|
{
|
||||||
|
if(value == null)
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!(value instanceof String stringValue))
|
||||||
|
{
|
||||||
|
throw new ClassCastException("Value [" + value + "] in field [" + fieldName + "] is not a String, which is required for the [" + criterion.getOperator() + "] operator.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return (stringValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public static void sortRecordList(QQueryFilter filter, List<QRecord> recordList)
|
||||||
|
{
|
||||||
|
if(filter == null || CollectionUtils.nullSafeIsEmpty(filter.getOrderBys()))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
recordList.sort((a, b) ->
|
||||||
|
{
|
||||||
|
for(QFilterOrderBy orderBy : filter.getOrderBys())
|
||||||
|
{
|
||||||
|
Serializable valueA = a.getValue(orderBy.getFieldName());
|
||||||
|
Serializable valueB = b.getValue(orderBy.getFieldName());
|
||||||
|
if(Objects.equals(valueA, valueB))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if(isGreaterThan(valueA, valueB) && orderBy.getIsAscending())
|
||||||
|
{
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public static List<QRecord> applySkipAndLimit(QueryInput queryInput, List<QRecord> recordList)
|
||||||
|
{
|
||||||
|
Integer skip = queryInput.getSkip();
|
||||||
|
if(skip != null && skip > 0)
|
||||||
|
{
|
||||||
|
if(skip < recordList.size())
|
||||||
|
{
|
||||||
|
recordList = recordList.subList(skip, recordList.size());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
recordList.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Integer limit = queryInput.getLimit();
|
||||||
|
if(limit != null && limit >= 0 && limit < recordList.size())
|
||||||
|
{
|
||||||
|
recordList = recordList.subList(0, limit);
|
||||||
|
}
|
||||||
|
return recordList;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,226 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.backend.core.processes.utils;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.tables.QueryAction;
|
||||||
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.AbstractActionInput;
|
||||||
|
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.QueryOutput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||||
|
import com.kingsrook.qqq.backend.core.utils.ListingHash;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public class GeneralProcessUtils
|
||||||
|
{
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public static Map<Serializable, QRecord> getForeignRecordMap(AbstractActionInput parentActionInput, List<QRecord> sourceRecords, String sourceTableForeignKeyFieldName, String foreignTableName, String foreignTablePrimaryKeyName) throws QException
|
||||||
|
{
|
||||||
|
Map<Serializable, QRecord> foreignRecordMap = new HashMap<>();
|
||||||
|
QueryInput queryInput = new QueryInput(parentActionInput.getInstance());
|
||||||
|
queryInput.setSession(parentActionInput.getSession());
|
||||||
|
queryInput.setTableName(foreignTableName);
|
||||||
|
List<Serializable> foreignIds = new ArrayList<>(sourceRecords.stream().map(r -> r.getValue(sourceTableForeignKeyFieldName)).toList());
|
||||||
|
|
||||||
|
queryInput.setFilter(new QQueryFilter().withCriteria(new QFilterCriteria(foreignTablePrimaryKeyName, QCriteriaOperator.IN, foreignIds)));
|
||||||
|
QueryOutput queryOutput = new QueryAction().execute(queryInput);
|
||||||
|
for(QRecord foreignRecord : queryOutput.getRecords())
|
||||||
|
{
|
||||||
|
foreignRecordMap.put(foreignRecord.getValue(foreignTablePrimaryKeyName), foreignRecord);
|
||||||
|
}
|
||||||
|
return foreignRecordMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public static ListingHash<Serializable, QRecord> getForeignRecordListingHashMap(AbstractActionInput parentActionInput, List<QRecord> sourceRecords, String sourceTableForeignKeyFieldName, String foreignTableName, String foreignTablePrimaryKeyName) throws QException
|
||||||
|
{
|
||||||
|
ListingHash<Serializable, QRecord> foreignRecordMap = new ListingHash<>();
|
||||||
|
QueryInput queryInput = new QueryInput(parentActionInput.getInstance());
|
||||||
|
queryInput.setSession(parentActionInput.getSession());
|
||||||
|
queryInput.setTableName(foreignTableName);
|
||||||
|
List<Serializable> foreignIds = new ArrayList<>(sourceRecords.stream().map(r -> r.getValue(sourceTableForeignKeyFieldName)).toList());
|
||||||
|
|
||||||
|
queryInput.setFilter(new QQueryFilter().withCriteria(new QFilterCriteria(foreignTablePrimaryKeyName, QCriteriaOperator.IN, foreignIds)));
|
||||||
|
QueryOutput queryOutput = new QueryAction().execute(queryInput);
|
||||||
|
for(QRecord foreignRecord : queryOutput.getRecords())
|
||||||
|
{
|
||||||
|
foreignRecordMap.add(foreignRecord.getValue(foreignTablePrimaryKeyName), foreignRecord);
|
||||||
|
}
|
||||||
|
return foreignRecordMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public static void addForeignRecordsToRecordList(AbstractActionInput parentActionInput, List<QRecord> sourceRecords, String sourceTableForeignKeyFieldName, String foreignTableName, String foreignTablePrimaryKeyName) throws QException
|
||||||
|
{
|
||||||
|
Map<Serializable, QRecord> foreignRecordMap = getForeignRecordMap(parentActionInput, sourceRecords, sourceTableForeignKeyFieldName, foreignTableName, foreignTablePrimaryKeyName);
|
||||||
|
for(QRecord sourceRecord : sourceRecords)
|
||||||
|
{
|
||||||
|
QRecord foreignRecord = foreignRecordMap.get(sourceRecord.getValue(sourceTableForeignKeyFieldName));
|
||||||
|
sourceRecord.setValue(foreignTableName, foreignRecord);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public static void addForeignRecordsListToRecordList(AbstractActionInput parentActionInput, List<QRecord> sourceRecords, String sourceTableForeignKeyFieldName, String foreignTableName, String foreignTablePrimaryKeyName) throws QException
|
||||||
|
{
|
||||||
|
ListingHash<Serializable, QRecord> foreignRecordMap = getForeignRecordListingHashMap(parentActionInput, sourceRecords, sourceTableForeignKeyFieldName, foreignTableName, foreignTablePrimaryKeyName);
|
||||||
|
for(QRecord sourceRecord : sourceRecords)
|
||||||
|
{
|
||||||
|
List<QRecord> foreignRecordList = foreignRecordMap.get(sourceRecord.getValue(sourceTableForeignKeyFieldName));
|
||||||
|
if(foreignRecordList != null)
|
||||||
|
{
|
||||||
|
if(foreignRecordList instanceof Serializable s)
|
||||||
|
{
|
||||||
|
sourceRecord.setValue(foreignTableName, s);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sourceRecord.setValue(foreignTableName, new ArrayList<>(foreignRecordList));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public static List<QRecord> getRecordListByField(AbstractActionInput parentActionInput, String tableName, String fieldName, Serializable fieldValue) throws QException
|
||||||
|
{
|
||||||
|
QueryInput queryInput = new QueryInput(parentActionInput.getInstance());
|
||||||
|
queryInput.setSession(parentActionInput.getSession());
|
||||||
|
queryInput.setTableName(tableName);
|
||||||
|
queryInput.setFilter(new QQueryFilter().withCriteria(new QFilterCriteria(fieldName, QCriteriaOperator.EQUALS, List.of(fieldValue))));
|
||||||
|
QueryOutput queryOutput = new QueryAction().execute(queryInput);
|
||||||
|
return (queryOutput.getRecords());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public static Optional<QRecord> getRecordById(AbstractActionInput parentActionInput, String tableName, String fieldName, Serializable fieldValue) throws QException
|
||||||
|
{
|
||||||
|
QueryInput queryInput = new QueryInput(parentActionInput.getInstance());
|
||||||
|
queryInput.setSession(parentActionInput.getSession());
|
||||||
|
queryInput.setTableName(tableName);
|
||||||
|
queryInput.setFilter(new QQueryFilter().withCriteria(new QFilterCriteria(fieldName, QCriteriaOperator.EQUALS, List.of(fieldValue))));
|
||||||
|
queryInput.setLimit(1);
|
||||||
|
QueryOutput queryOutput = new QueryAction().execute(queryInput);
|
||||||
|
return (queryOutput.getRecords().stream().findFirst());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public static List<QRecord> loadTable(AbstractActionInput parentActionInput, String tableName) throws QException
|
||||||
|
{
|
||||||
|
QueryInput queryInput = new QueryInput(parentActionInput.getInstance());
|
||||||
|
queryInput.setSession(parentActionInput.getSession());
|
||||||
|
queryInput.setTableName(tableName);
|
||||||
|
QueryOutput queryOutput = new QueryAction().execute(queryInput);
|
||||||
|
return (queryOutput.getRecords());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Note - null values from the key field are NOT put in the map.
|
||||||
|
*******************************************************************************/
|
||||||
|
public static Map<Serializable, QRecord> loadTableToMap(AbstractActionInput parentActionInput, String tableName, String keyFieldName) throws QException
|
||||||
|
{
|
||||||
|
QueryInput queryInput = new QueryInput(parentActionInput.getInstance());
|
||||||
|
queryInput.setSession(parentActionInput.getSession());
|
||||||
|
queryInput.setTableName(tableName);
|
||||||
|
QueryOutput queryOutput = new QueryAction().execute(queryInput);
|
||||||
|
List<QRecord> records = queryOutput.getRecords();
|
||||||
|
|
||||||
|
Map<Serializable, QRecord> map = new HashMap<>();
|
||||||
|
for(QRecord record : records)
|
||||||
|
{
|
||||||
|
Serializable value = record.getValue(keyFieldName);
|
||||||
|
if(value != null)
|
||||||
|
{
|
||||||
|
map.put(value, record);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (map);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Note - null values from the key field are NOT put in the map.
|
||||||
|
*******************************************************************************/
|
||||||
|
public static ListingHash<Serializable, QRecord> loadTableToListingHash(AbstractActionInput parentActionInput, String tableName, String keyFieldName) throws QException
|
||||||
|
{
|
||||||
|
QueryInput queryInput = new QueryInput(parentActionInput.getInstance());
|
||||||
|
queryInput.setSession(parentActionInput.getSession());
|
||||||
|
queryInput.setTableName(tableName);
|
||||||
|
QueryOutput queryOutput = new QueryAction().execute(queryInput);
|
||||||
|
List<QRecord> records = queryOutput.getRecords();
|
||||||
|
|
||||||
|
ListingHash<Serializable, QRecord> map = new ListingHash<>();
|
||||||
|
for(QRecord record : records)
|
||||||
|
{
|
||||||
|
Serializable value = record.getValue(keyFieldName);
|
||||||
|
if(value != null)
|
||||||
|
{
|
||||||
|
map.add(value, record);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (map);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,177 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.backend.core.actions.scripts;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.scripts.logging.HeaderAndDetailTableCodeExecutionLogger;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.scripts.logging.Log4jCodeExecutionLogger;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.scripts.logging.NoopCodeExecutionLogger;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.scripts.logging.QCodeExecutionLoggerInterface;
|
||||||
|
import com.kingsrook.qqq.backend.core.exceptions.QCodeException;
|
||||||
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
|
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.data.QRecord;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeUsage;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.scripts.ScriptsMetaDataProvider;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.session.QSession;
|
||||||
|
import com.kingsrook.qqq.backend.core.modules.backend.implementations.memory.MemoryRecordStore;
|
||||||
|
import com.kingsrook.qqq.backend.core.utils.TestUtils;
|
||||||
|
import com.kingsrook.qqq.backend.core.utils.ValueUtils;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Unit test for ExecuteCodeAction
|
||||||
|
*******************************************************************************/
|
||||||
|
class ExecuteCodeActionTest
|
||||||
|
{
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@BeforeEach
|
||||||
|
@AfterEach
|
||||||
|
void beforeAndAfterEach()
|
||||||
|
{
|
||||||
|
MemoryRecordStore.getInstance().reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void test() throws QException
|
||||||
|
{
|
||||||
|
QInstance qInstance = TestUtils.defineInstance();
|
||||||
|
ExecuteCodeInput executeCodeInput = setupInput(qInstance, Map.of("x", 4), new NoopCodeExecutionLogger());
|
||||||
|
ExecuteCodeOutput executeCodeOutput = new ExecuteCodeOutput();
|
||||||
|
new ExecuteCodeAction().run(executeCodeInput, executeCodeOutput);
|
||||||
|
assertEquals(16, executeCodeOutput.getOutput());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private ExecuteCodeInput setupInput(QInstance qInstance, Map<String, Serializable> context, QCodeExecutionLoggerInterface executionLogger)
|
||||||
|
{
|
||||||
|
ExecuteCodeInput executeCodeInput = new ExecuteCodeInput(qInstance);
|
||||||
|
executeCodeInput.setSession(new QSession());
|
||||||
|
executeCodeInput.setCodeReference(new QCodeReference(ScriptInJava.class, QCodeUsage.CUSTOMIZER));
|
||||||
|
executeCodeInput.setContext(context);
|
||||||
|
executeCodeInput.setExecutionLogger(executionLogger);
|
||||||
|
return executeCodeInput;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testLog4jLogger() throws QException
|
||||||
|
{
|
||||||
|
QInstance qInstance = TestUtils.defineInstance();
|
||||||
|
ExecuteCodeInput executeCodeInput = setupInput(qInstance, Map.of("x", 4), new Log4jCodeExecutionLogger());
|
||||||
|
ExecuteCodeOutput executeCodeOutput = new ExecuteCodeOutput();
|
||||||
|
new ExecuteCodeAction().run(executeCodeInput, executeCodeOutput);
|
||||||
|
assertEquals(16, executeCodeOutput.getOutput());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testTableLogger() throws QException
|
||||||
|
{
|
||||||
|
QInstance qInstance = TestUtils.defineInstance();
|
||||||
|
new ScriptsMetaDataProvider().defineStandardScriptsTables(qInstance, TestUtils.MEMORY_BACKEND_NAME, null);
|
||||||
|
|
||||||
|
ExecuteCodeInput executeCodeInput = setupInput(qInstance, Map.of("x", 4), new HeaderAndDetailTableCodeExecutionLogger(1701, 1702));
|
||||||
|
ExecuteCodeOutput executeCodeOutput = new ExecuteCodeOutput();
|
||||||
|
new ExecuteCodeAction().run(executeCodeInput, executeCodeOutput);
|
||||||
|
assertEquals(16, executeCodeOutput.getOutput());
|
||||||
|
|
||||||
|
List<QRecord> scriptLogRecords = TestUtils.queryTable(qInstance, "scriptLog");
|
||||||
|
List<QRecord> scriptLogLineRecords = TestUtils.queryTable(qInstance, "scriptLogLine");
|
||||||
|
assertEquals(1, scriptLogRecords.size());
|
||||||
|
assertEquals(1701, scriptLogRecords.get(0).getValueInteger("scriptId"));
|
||||||
|
assertEquals(1702, scriptLogRecords.get(0).getValueInteger("scriptRevisionId"));
|
||||||
|
assertEquals(1, scriptLogLineRecords.size());
|
||||||
|
assertEquals(1, scriptLogLineRecords.get(0).getValueInteger("scriptLogId"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testException()
|
||||||
|
{
|
||||||
|
QInstance qInstance = TestUtils.defineInstance();
|
||||||
|
ExecuteCodeInput executeCodeInput = setupInput(qInstance, Map.of(), new NoopCodeExecutionLogger());
|
||||||
|
ExecuteCodeOutput executeCodeOutput = new ExecuteCodeOutput();
|
||||||
|
assertThrows(QCodeException.class, () ->
|
||||||
|
{
|
||||||
|
new ExecuteCodeAction().run(executeCodeInput, executeCodeOutput);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public static class ScriptInJava implements Function<Map<String, Object>, Serializable>
|
||||||
|
{
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Override
|
||||||
|
public Serializable apply(Map<String, Object> context)
|
||||||
|
{
|
||||||
|
((QCodeExecutionLoggerInterface) context.get("logger")).log("Test a log");
|
||||||
|
|
||||||
|
int x = ValueUtils.getValueAsInteger(context.get("x"));
|
||||||
|
return (x * x);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,116 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.backend.core.actions.scripts;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.scripts.RunAssociatedScriptInput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.scripts.RunAssociatedScriptOutput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.scripts.StoreAssociatedScriptInput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.scripts.StoreAssociatedScriptOutput;
|
||||||
|
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.metadata.code.AssociatedScriptCodeReference;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.AssociatedScript;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.scripts.ScriptsMetaDataProvider;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.session.QSession;
|
||||||
|
import com.kingsrook.qqq.backend.core.utils.TestUtils;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Unit test for RunAssociatedScriptAction
|
||||||
|
*******************************************************************************/
|
||||||
|
class RunAssociatedScriptActionTest
|
||||||
|
{
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void test() throws QException
|
||||||
|
{
|
||||||
|
QInstance instance = TestUtils.defineInstance();
|
||||||
|
QTableMetaData table = instance.getTable(TestUtils.TABLE_NAME_PERSON_MEMORY)
|
||||||
|
.withField(new QFieldMetaData("testScriptId", QFieldType.INTEGER))
|
||||||
|
.withAssociatedScript(new AssociatedScript()
|
||||||
|
.withScriptTypeId(1)
|
||||||
|
.withFieldName("testScriptId")
|
||||||
|
);
|
||||||
|
|
||||||
|
new ScriptsMetaDataProvider().defineStandardScriptsTables(instance, TestUtils.MEMORY_BACKEND_NAME, null);
|
||||||
|
|
||||||
|
TestUtils.insertRecords(instance, table, List.of(
|
||||||
|
new QRecord().withValue("id", 1),
|
||||||
|
new QRecord().withValue("id", 2)
|
||||||
|
));
|
||||||
|
|
||||||
|
TestUtils.insertRecords(instance, instance.getTable("scriptType"), List.of(
|
||||||
|
new QRecord().withValue("id", 1).withValue("name", "Test Script Type")
|
||||||
|
));
|
||||||
|
|
||||||
|
insertScript(instance, 1, """
|
||||||
|
return "Hello";
|
||||||
|
""");
|
||||||
|
|
||||||
|
RunAssociatedScriptInput runAssociatedScriptInput = new RunAssociatedScriptInput(instance);
|
||||||
|
runAssociatedScriptInput.setSession(new QSession());
|
||||||
|
runAssociatedScriptInput.setInputValues(Map.of());
|
||||||
|
runAssociatedScriptInput.setTableName(TestUtils.TABLE_NAME_PERSON_MEMORY);
|
||||||
|
runAssociatedScriptInput.setCodeReference(new AssociatedScriptCodeReference()
|
||||||
|
.withRecordTable(TestUtils.TABLE_NAME_PERSON_MEMORY)
|
||||||
|
.withRecordPrimaryKey(1)
|
||||||
|
.withFieldName("testScriptId")
|
||||||
|
);
|
||||||
|
RunAssociatedScriptOutput runAssociatedScriptOutput = new RunAssociatedScriptOutput();
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> new RunAssociatedScriptAction().run(runAssociatedScriptInput, runAssociatedScriptOutput))
|
||||||
|
.isInstanceOf(QException.class)
|
||||||
|
.hasRootCauseInstanceOf(ClassNotFoundException.class)
|
||||||
|
.hasRootCauseMessage("com.kingsrook.qqq.languages.javascript.QJavaScriptExecutor");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private void insertScript(QInstance instance, Serializable recordId, String code) throws QException
|
||||||
|
{
|
||||||
|
StoreAssociatedScriptInput storeAssociatedScriptInput = new StoreAssociatedScriptInput(instance);
|
||||||
|
storeAssociatedScriptInput.setSession(new QSession());
|
||||||
|
storeAssociatedScriptInput.setTableName(TestUtils.TABLE_NAME_PERSON_MEMORY);
|
||||||
|
storeAssociatedScriptInput.setRecordPrimaryKey(recordId);
|
||||||
|
storeAssociatedScriptInput.setCode(code);
|
||||||
|
storeAssociatedScriptInput.setFieldName("testScriptId");
|
||||||
|
StoreAssociatedScriptOutput storeAssociatedScriptOutput = new StoreAssociatedScriptOutput();
|
||||||
|
new StoreAssociatedScriptAction().run(storeAssociatedScriptInput, storeAssociatedScriptOutput);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,172 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.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.exceptions.QException;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.scripts.StoreAssociatedScriptInput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.scripts.StoreAssociatedScriptOutput;
|
||||||
|
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.QueryOutput;
|
||||||
|
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.metadata.fields.QFieldMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.AssociatedScript;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.scripts.ScriptsMetaDataProvider;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.session.QSession;
|
||||||
|
import com.kingsrook.qqq.backend.core.modules.backend.implementations.memory.MemoryRecordStore;
|
||||||
|
import com.kingsrook.qqq.backend.core.utils.TestUtils;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Unit test for StoreAssociatedScriptAction
|
||||||
|
*******************************************************************************/
|
||||||
|
class StoreAssociatedScriptActionTest
|
||||||
|
{
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@BeforeEach
|
||||||
|
@AfterEach
|
||||||
|
void beforeAndAfterEach()
|
||||||
|
{
|
||||||
|
MemoryRecordStore.getInstance().reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void test() throws QException
|
||||||
|
{
|
||||||
|
QInstance instance = TestUtils.defineInstance();
|
||||||
|
QTableMetaData table = instance.getTable(TestUtils.TABLE_NAME_PERSON_MEMORY)
|
||||||
|
.withField(new QFieldMetaData("testScriptId", QFieldType.INTEGER))
|
||||||
|
.withAssociatedScript(new AssociatedScript()
|
||||||
|
.withScriptTypeId(1)
|
||||||
|
.withFieldName("testScriptId")
|
||||||
|
)
|
||||||
|
.withField(new QFieldMetaData("otherScriptId", QFieldType.INTEGER))
|
||||||
|
.withAssociatedScript(new AssociatedScript()
|
||||||
|
.withScriptTypeId(2)
|
||||||
|
.withFieldName("otherScriptId")
|
||||||
|
);
|
||||||
|
|
||||||
|
new ScriptsMetaDataProvider().defineStandardScriptsTables(instance, TestUtils.MEMORY_BACKEND_NAME, null);
|
||||||
|
|
||||||
|
TestUtils.insertRecords(instance, table, List.of(
|
||||||
|
new QRecord().withValue("id", 1),
|
||||||
|
new QRecord().withValue("id", 2),
|
||||||
|
new QRecord().withValue("id", 3)
|
||||||
|
));
|
||||||
|
|
||||||
|
TestUtils.insertRecords(instance, instance.getTable("scriptType"), List.of(
|
||||||
|
new QRecord().withValue("id", 1).withValue("name", "Test Script"),
|
||||||
|
new QRecord().withValue("id", 2).withValue("name", "Other Script")
|
||||||
|
));
|
||||||
|
|
||||||
|
StoreAssociatedScriptInput storeAssociatedScriptInput = new StoreAssociatedScriptInput(instance);
|
||||||
|
storeAssociatedScriptInput.setSession(new QSession());
|
||||||
|
storeAssociatedScriptInput.setTableName(TestUtils.TABLE_NAME_PERSON_MEMORY);
|
||||||
|
storeAssociatedScriptInput.setRecordPrimaryKey(1);
|
||||||
|
storeAssociatedScriptInput.setCode("var i = 0;");
|
||||||
|
storeAssociatedScriptInput.setCommitMessage("Test commit");
|
||||||
|
storeAssociatedScriptInput.setFieldName("testScriptId");
|
||||||
|
StoreAssociatedScriptOutput storeAssociatedScriptOutput = new StoreAssociatedScriptOutput();
|
||||||
|
|
||||||
|
///////////////////////////////////////////////
|
||||||
|
// insert 1st version of script for record 1 //
|
||||||
|
///////////////////////////////////////////////
|
||||||
|
new StoreAssociatedScriptAction().run(storeAssociatedScriptInput, storeAssociatedScriptOutput);
|
||||||
|
assertValueInField(instance, TestUtils.TABLE_NAME_PERSON_MEMORY, 1, "testScriptId", 1);
|
||||||
|
assertValueInField(instance, "script", 1, "currentScriptRevisionId", 1);
|
||||||
|
|
||||||
|
////////////////////////////////////////////
|
||||||
|
// add 2nd version of script for record 1 //
|
||||||
|
////////////////////////////////////////////
|
||||||
|
storeAssociatedScriptInput.setCode("var i = 1;");
|
||||||
|
storeAssociatedScriptInput.setCommitMessage("2nd commit");
|
||||||
|
new StoreAssociatedScriptAction().run(storeAssociatedScriptInput, storeAssociatedScriptOutput);
|
||||||
|
assertValueInField(instance, TestUtils.TABLE_NAME_PERSON_MEMORY, 1, "testScriptId", 1);
|
||||||
|
assertValueInField(instance, "script", 1, "currentScriptRevisionId", 2);
|
||||||
|
|
||||||
|
///////////////////////////////////////////////
|
||||||
|
// insert 1st version of script for record 3 //
|
||||||
|
///////////////////////////////////////////////
|
||||||
|
storeAssociatedScriptInput.setRecordPrimaryKey(3);
|
||||||
|
storeAssociatedScriptInput.setCode("var i = 2;");
|
||||||
|
storeAssociatedScriptInput.setCommitMessage("First Commit here");
|
||||||
|
new StoreAssociatedScriptAction().run(storeAssociatedScriptInput, storeAssociatedScriptOutput);
|
||||||
|
assertValueInField(instance, TestUtils.TABLE_NAME_PERSON_MEMORY, 3, "testScriptId", 2);
|
||||||
|
assertValueInField(instance, "script", 2, "currentScriptRevisionId", 3);
|
||||||
|
|
||||||
|
/////////////////////////////////////
|
||||||
|
// make sure no script on record 2 //
|
||||||
|
/////////////////////////////////////
|
||||||
|
assertValueInField(instance, TestUtils.TABLE_NAME_PERSON_MEMORY, 2, "testScriptId", null);
|
||||||
|
|
||||||
|
////////////////////////////////////
|
||||||
|
// add another script to record 1 //
|
||||||
|
////////////////////////////////////
|
||||||
|
storeAssociatedScriptInput.setRecordPrimaryKey(1);
|
||||||
|
storeAssociatedScriptInput.setCode("var i = 3;");
|
||||||
|
storeAssociatedScriptInput.setCommitMessage("Other field");
|
||||||
|
storeAssociatedScriptInput.setFieldName("otherScriptId");
|
||||||
|
new StoreAssociatedScriptAction().run(storeAssociatedScriptInput, storeAssociatedScriptOutput);
|
||||||
|
assertValueInField(instance, TestUtils.TABLE_NAME_PERSON_MEMORY, 1, "testScriptId", 1);
|
||||||
|
assertValueInField(instance, TestUtils.TABLE_NAME_PERSON_MEMORY, 1, "otherScriptId", 3);
|
||||||
|
assertValueInField(instance, "script", 3, "currentScriptRevisionId", 4);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private Serializable assertValueInField(QInstance instance, String tableName, Serializable recordId, String fieldName, Serializable value) throws QException
|
||||||
|
{
|
||||||
|
QueryInput queryInput = new QueryInput(instance);
|
||||||
|
queryInput.setSession(new QSession());
|
||||||
|
queryInput.setTableName(tableName);
|
||||||
|
queryInput.setFilter(new QQueryFilter().withCriteria(new QFilterCriteria("id", QCriteriaOperator.EQUALS, List.of(recordId))));
|
||||||
|
QueryOutput queryOutput = new QueryAction().execute(queryInput);
|
||||||
|
Serializable actual = queryOutput.getRecords().get(0).getValue(fieldName);
|
||||||
|
assertEquals(value, actual);
|
||||||
|
return (actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.backend.core.actions.scripts;
|
||||||
|
|
||||||
|
|
||||||
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.scripts.TestScriptInput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.scripts.TestScriptOutput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||||
|
import com.kingsrook.qqq.backend.core.utils.TestUtils;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Unit test for TestScriptAction
|
||||||
|
*******************************************************************************/
|
||||||
|
class TestScriptActionTest
|
||||||
|
{
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void test() throws QException
|
||||||
|
{
|
||||||
|
QInstance instance = TestUtils.defineInstance();
|
||||||
|
TestScriptInput input = new TestScriptInput(instance);
|
||||||
|
TestScriptOutput output = new TestScriptOutput();
|
||||||
|
new TestScriptAction().run(input, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,271 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.backend.core.modules.backend.implementations.enumeration;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.tables.QueryAction;
|
||||||
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
|
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.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.query.QueryOutput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.data.QRecordEnum;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.session.QSession;
|
||||||
|
import com.kingsrook.qqq.backend.core.utils.TestUtils;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Unit test for EnumerationQueryAction
|
||||||
|
*******************************************************************************/
|
||||||
|
class EnumerationQueryActionTest
|
||||||
|
{
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testUnfilteredQuery() throws QException
|
||||||
|
{
|
||||||
|
QInstance instance = defineQInstance();
|
||||||
|
|
||||||
|
QueryInput queryInput = new QueryInput(instance);
|
||||||
|
queryInput.setSession(new QSession());
|
||||||
|
queryInput.setTableName("statesEnum");
|
||||||
|
QueryOutput queryOutput = new QueryAction().execute(queryInput);
|
||||||
|
assertEquals(2, queryOutput.getRecords().size());
|
||||||
|
|
||||||
|
assertEquals(1, queryOutput.getRecords().get(0).getValueInteger("id"));
|
||||||
|
assertEquals("Missouri", queryOutput.getRecords().get(0).getValueString("name"));
|
||||||
|
assertEquals("MO", queryOutput.getRecords().get(0).getValueString("postalCode"));
|
||||||
|
assertEquals(15_000_000, queryOutput.getRecords().get(0).getValueInteger("population"));
|
||||||
|
|
||||||
|
assertEquals(2, queryOutput.getRecords().get(1).getValueInteger("id"));
|
||||||
|
assertEquals("Illinois", queryOutput.getRecords().get(1).getValueString("name"));
|
||||||
|
assertEquals("IL", queryOutput.getRecords().get(1).getValueString("postalCode"));
|
||||||
|
assertEquals(25_000_000, queryOutput.getRecords().get(1).getValueInteger("population"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testFilteredQuery() throws QException
|
||||||
|
{
|
||||||
|
QInstance instance = defineQInstance();
|
||||||
|
|
||||||
|
QueryInput queryInput = new QueryInput(instance);
|
||||||
|
queryInput.setSession(new QSession());
|
||||||
|
queryInput.setTableName("statesEnum");
|
||||||
|
queryInput.setFilter(new QQueryFilter().withCriteria(new QFilterCriteria("population", QCriteriaOperator.GREATER_THAN, List.of(20_000_000))));
|
||||||
|
QueryOutput queryOutput = new QueryAction().execute(queryInput);
|
||||||
|
assertEquals(1, queryOutput.getRecords().size());
|
||||||
|
|
||||||
|
assertEquals(2, queryOutput.getRecords().get(0).getValueInteger("id"));
|
||||||
|
assertEquals("IL", queryOutput.getRecords().get(0).getValueString("postalCode"));
|
||||||
|
assertEquals(25_000_000, queryOutput.getRecords().get(0).getValueInteger("population"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testQueryOrderBy() throws QException
|
||||||
|
{
|
||||||
|
QInstance instance = defineQInstance();
|
||||||
|
|
||||||
|
QueryInput queryInput = new QueryInput(instance);
|
||||||
|
queryInput.setSession(new QSession());
|
||||||
|
queryInput.setTableName("statesEnum");
|
||||||
|
|
||||||
|
queryInput.setFilter(new QQueryFilter().withOrderBy(new QFilterOrderBy("name")));
|
||||||
|
QueryOutput queryOutput = new QueryAction().execute(queryInput);
|
||||||
|
assertEquals(List.of("Illinois", "Missouri"), queryOutput.getRecords().stream().map(r -> r.getValueString("name")).toList());
|
||||||
|
|
||||||
|
queryInput.setFilter(new QQueryFilter().withOrderBy(new QFilterOrderBy("name", false)));
|
||||||
|
queryOutput = new QueryAction().execute(queryInput);
|
||||||
|
assertEquals(List.of("Missouri", "Illinois"), queryOutput.getRecords().stream().map(r -> r.getValueString("name")).toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testQuerySkipLimit() throws QException
|
||||||
|
{
|
||||||
|
QInstance instance = defineQInstance();
|
||||||
|
|
||||||
|
QueryInput queryInput = new QueryInput(instance);
|
||||||
|
queryInput.setSession(new QSession());
|
||||||
|
queryInput.setTableName("statesEnum");
|
||||||
|
queryInput.setSkip(0);
|
||||||
|
queryInput.setLimit(null);
|
||||||
|
QueryOutput queryOutput = new QueryAction().execute(queryInput);
|
||||||
|
assertEquals(List.of("Missouri", "Illinois"), queryOutput.getRecords().stream().map(r -> r.getValueString("name")).toList());
|
||||||
|
|
||||||
|
queryInput.setSkip(1);
|
||||||
|
queryInput.setLimit(null);
|
||||||
|
queryOutput = new QueryAction().execute(queryInput);
|
||||||
|
assertEquals(List.of("Illinois"), queryOutput.getRecords().stream().map(r -> r.getValueString("name")).toList());
|
||||||
|
|
||||||
|
queryInput.setSkip(2);
|
||||||
|
queryInput.setLimit(null);
|
||||||
|
queryOutput = new QueryAction().execute(queryInput);
|
||||||
|
assertEquals(List.of(), queryOutput.getRecords().stream().map(r -> r.getValueString("name")).toList());
|
||||||
|
|
||||||
|
queryInput.setSkip(null);
|
||||||
|
queryInput.setLimit(1);
|
||||||
|
queryOutput = new QueryAction().execute(queryInput);
|
||||||
|
assertEquals(List.of("Missouri"), queryOutput.getRecords().stream().map(r -> r.getValueString("name")).toList());
|
||||||
|
|
||||||
|
queryInput.setSkip(null);
|
||||||
|
queryInput.setLimit(2);
|
||||||
|
queryOutput = new QueryAction().execute(queryInput);
|
||||||
|
assertEquals(List.of("Missouri", "Illinois"), queryOutput.getRecords().stream().map(r -> r.getValueString("name")).toList());
|
||||||
|
|
||||||
|
queryInput.setSkip(null);
|
||||||
|
queryInput.setLimit(3);
|
||||||
|
queryOutput = new QueryAction().execute(queryInput);
|
||||||
|
assertEquals(List.of("Missouri", "Illinois"), queryOutput.getRecords().stream().map(r -> r.getValueString("name")).toList());
|
||||||
|
|
||||||
|
queryInput.setSkip(null);
|
||||||
|
queryInput.setLimit(0);
|
||||||
|
queryOutput = new QueryAction().execute(queryInput);
|
||||||
|
assertEquals(List.of(), queryOutput.getRecords().stream().map(r -> r.getValueString("name")).toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private QInstance defineQInstance()
|
||||||
|
{
|
||||||
|
QInstance instance = TestUtils.defineInstance();
|
||||||
|
instance.addBackend(new QBackendMetaData()
|
||||||
|
.withName("enum")
|
||||||
|
.withBackendType("enum")
|
||||||
|
);
|
||||||
|
|
||||||
|
instance.addTable(new QTableMetaData()
|
||||||
|
.withName("statesEnum")
|
||||||
|
.withBackendName("enum")
|
||||||
|
.withPrimaryKeyField("id")
|
||||||
|
.withField(new QFieldMetaData("id", QFieldType.INTEGER))
|
||||||
|
.withField(new QFieldMetaData("name", QFieldType.STRING))
|
||||||
|
.withField(new QFieldMetaData("postalCode", QFieldType.STRING))
|
||||||
|
.withField(new QFieldMetaData("population", QFieldType.INTEGER))
|
||||||
|
.withBackendDetails(new EnumerationTableBackendDetails().withEnumClass(States.class))
|
||||||
|
);
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public static enum States implements QRecordEnum
|
||||||
|
{
|
||||||
|
MO(1, "Missouri", "MO", 15_000_000),
|
||||||
|
IL(2, "Illinois", "IL", 25_000_000);
|
||||||
|
|
||||||
|
|
||||||
|
private final Integer id;
|
||||||
|
private final String name;
|
||||||
|
private final String postalCode;
|
||||||
|
private final Integer population;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
States(int id, String name, String postalCode, int population)
|
||||||
|
{
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
this.postalCode = postalCode;
|
||||||
|
this.population = population;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for id
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Integer getId()
|
||||||
|
{
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for name
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getName()
|
||||||
|
{
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for postalCode
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getPostalCode()
|
||||||
|
{
|
||||||
|
return postalCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for population
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Integer getPopulation()
|
||||||
|
{
|
||||||
|
return population;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -271,12 +271,12 @@ class MemoryBackendModuleTest
|
|||||||
assertEquals(2, queryShapes(qInstance, table, session, new QFilterCriteria("id", QCriteriaOperator.LESS_THAN_OR_EQUALS, List.of(2))).size());
|
assertEquals(2, queryShapes(qInstance, table, session, new QFilterCriteria("id", QCriteriaOperator.LESS_THAN_OR_EQUALS, List.of(2))).size());
|
||||||
assertEquals(1, queryShapes(qInstance, table, session, new QFilterCriteria("id", QCriteriaOperator.LESS_THAN_OR_EQUALS, List.of(1))).size());
|
assertEquals(1, queryShapes(qInstance, table, session, new QFilterCriteria("id", QCriteriaOperator.LESS_THAN_OR_EQUALS, List.of(1))).size());
|
||||||
assertEquals(0, queryShapes(qInstance, table, session, new QFilterCriteria("id", QCriteriaOperator.LESS_THAN_OR_EQUALS, List.of(0))).size());
|
assertEquals(0, queryShapes(qInstance, table, session, new QFilterCriteria("id", QCriteriaOperator.LESS_THAN_OR_EQUALS, List.of(0))).size());
|
||||||
|
assertEquals(1, queryShapes(qInstance, table, session, new QFilterCriteria("name", QCriteriaOperator.LESS_THAN_OR_EQUALS, List.of("Darin"))).size());
|
||||||
|
|
||||||
assertThrows(QException.class, () -> queryShapes(qInstance, table, session, new QFilterCriteria("id", QCriteriaOperator.GREATER_THAN, List.of())));
|
assertThrows(QException.class, () -> queryShapes(qInstance, table, session, new QFilterCriteria("id", QCriteriaOperator.GREATER_THAN, List.of())));
|
||||||
assertThrows(QException.class, () -> queryShapes(qInstance, table, session, new QFilterCriteria("id", QCriteriaOperator.GREATER_THAN_OR_EQUALS, List.of())));
|
assertThrows(QException.class, () -> queryShapes(qInstance, table, session, new QFilterCriteria("id", QCriteriaOperator.GREATER_THAN_OR_EQUALS, List.of())));
|
||||||
assertThrows(QException.class, () -> queryShapes(qInstance, table, session, new QFilterCriteria("id", QCriteriaOperator.LESS_THAN, List.of())));
|
assertThrows(QException.class, () -> queryShapes(qInstance, table, session, new QFilterCriteria("id", QCriteriaOperator.LESS_THAN, List.of())));
|
||||||
assertThrows(QException.class, () -> queryShapes(qInstance, table, session, new QFilterCriteria("id", QCriteriaOperator.LESS_THAN_OR_EQUALS, List.of())));
|
assertThrows(QException.class, () -> queryShapes(qInstance, table, session, new QFilterCriteria("id", QCriteriaOperator.LESS_THAN_OR_EQUALS, List.of())));
|
||||||
assertThrows(QException.class, () -> queryShapes(qInstance, table, session, new QFilterCriteria("name", QCriteriaOperator.LESS_THAN_OR_EQUALS, List.of("Bob"))));
|
|
||||||
|
|
||||||
{
|
{
|
||||||
////////////////////////////
|
////////////////////////////
|
||||||
|
@ -0,0 +1,326 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.backend.core.processes.utils;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.tables.QueryAction;
|
||||||
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput;
|
||||||
|
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.session.QSession;
|
||||||
|
import com.kingsrook.qqq.backend.core.modules.backend.implementations.memory.MemoryRecordStore;
|
||||||
|
import com.kingsrook.qqq.backend.core.utils.ListingHash;
|
||||||
|
import com.kingsrook.qqq.backend.core.utils.TestUtils;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Unit test for GeneralProcessUtils
|
||||||
|
*******************************************************************************/
|
||||||
|
class GeneralProcessUtilsTest
|
||||||
|
{
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@AfterEach
|
||||||
|
@BeforeEach
|
||||||
|
void beforeAndAfterEach()
|
||||||
|
{
|
||||||
|
MemoryRecordStore.getInstance().reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testGetForeignRecordMap() throws QException
|
||||||
|
{
|
||||||
|
QInstance instance = TestUtils.defineInstance();
|
||||||
|
|
||||||
|
TestUtils.insertRecords(instance, instance.getTable(TestUtils.TABLE_NAME_PERSON_MEMORY), List.of(
|
||||||
|
new QRecord().withValue("favoriteShapeId", 3),
|
||||||
|
new QRecord().withValue("favoriteShapeId", 1)
|
||||||
|
));
|
||||||
|
TestUtils.insertDefaultShapes(instance);
|
||||||
|
|
||||||
|
QueryInput queryInput = new QueryInput(instance);
|
||||||
|
queryInput.setSession(new QSession());
|
||||||
|
queryInput.setTableName(TestUtils.TABLE_NAME_PERSON_MEMORY);
|
||||||
|
QueryOutput queryOutput = new QueryAction().execute(queryInput);
|
||||||
|
|
||||||
|
Map<Serializable, QRecord> foreignRecordMap = GeneralProcessUtils.getForeignRecordMap(queryInput, queryOutput.getRecords(), "favoriteShapeId", TestUtils.TABLE_NAME_SHAPE, "id");
|
||||||
|
|
||||||
|
assertEquals(2, foreignRecordMap.size());
|
||||||
|
assertEquals(1, foreignRecordMap.get(1).getValueInteger("id"));
|
||||||
|
assertEquals(3, foreignRecordMap.get(3).getValueInteger("id"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testGetForeignRecordListingHashMap() throws QException
|
||||||
|
{
|
||||||
|
QInstance instance = TestUtils.defineInstance();
|
||||||
|
|
||||||
|
TestUtils.insertRecords(instance, instance.getTable(TestUtils.TABLE_NAME_PERSON_MEMORY), List.of(
|
||||||
|
new QRecord().withValue("id", 1).withValue("favoriteShapeId", 3),
|
||||||
|
new QRecord().withValue("id", 2).withValue("favoriteShapeId", 3),
|
||||||
|
new QRecord().withValue("id", 3).withValue("favoriteShapeId", 1)
|
||||||
|
));
|
||||||
|
TestUtils.insertDefaultShapes(instance);
|
||||||
|
|
||||||
|
QueryInput queryInput = new QueryInput(instance);
|
||||||
|
queryInput.setSession(new QSession());
|
||||||
|
queryInput.setTableName(TestUtils.TABLE_NAME_SHAPE);
|
||||||
|
QueryOutput queryOutput = new QueryAction().execute(queryInput);
|
||||||
|
|
||||||
|
ListingHash<Serializable, QRecord> foreignRecordListingHashMap = GeneralProcessUtils.getForeignRecordListingHashMap(queryInput, queryOutput.getRecords(), "id", TestUtils.TABLE_NAME_PERSON_MEMORY, "favoriteShapeId");
|
||||||
|
|
||||||
|
assertEquals(2, foreignRecordListingHashMap.size());
|
||||||
|
|
||||||
|
assertEquals(1, foreignRecordListingHashMap.get(1).size());
|
||||||
|
assertEquals(Set.of(3), foreignRecordListingHashMap.get(1).stream().map(r -> r.getValueInteger("id")).collect(Collectors.toSet()));
|
||||||
|
|
||||||
|
assertEquals(2, foreignRecordListingHashMap.get(3).size());
|
||||||
|
assertEquals(Set.of(1, 2), foreignRecordListingHashMap.get(3).stream().map(r -> r.getValueInteger("id")).collect(Collectors.toSet()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testAddForeignRecordsToRecordList() throws QException
|
||||||
|
{
|
||||||
|
QInstance instance = TestUtils.defineInstance();
|
||||||
|
|
||||||
|
TestUtils.insertRecords(instance, instance.getTable(TestUtils.TABLE_NAME_PERSON_MEMORY), List.of(
|
||||||
|
new QRecord().withValue("favoriteShapeId", 3),
|
||||||
|
new QRecord().withValue("favoriteShapeId", 1)
|
||||||
|
));
|
||||||
|
TestUtils.insertDefaultShapes(instance);
|
||||||
|
|
||||||
|
QueryInput queryInput = new QueryInput(instance);
|
||||||
|
queryInput.setSession(new QSession());
|
||||||
|
queryInput.setTableName(TestUtils.TABLE_NAME_PERSON_MEMORY);
|
||||||
|
QueryOutput queryOutput = new QueryAction().execute(queryInput);
|
||||||
|
|
||||||
|
GeneralProcessUtils.addForeignRecordsToRecordList(queryInput, queryOutput.getRecords(), "favoriteShapeId", TestUtils.TABLE_NAME_SHAPE, "id");
|
||||||
|
|
||||||
|
for(QRecord record : queryOutput.getRecords())
|
||||||
|
{
|
||||||
|
assertEquals(record.getValue("favoriteShapeId"), ((QRecord) record.getValue(TestUtils.TABLE_NAME_SHAPE)).getValue("id"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testAddForeignRecordsListToRecordList() throws QException
|
||||||
|
{
|
||||||
|
QInstance instance = TestUtils.defineInstance();
|
||||||
|
|
||||||
|
TestUtils.insertRecords(instance, instance.getTable(TestUtils.TABLE_NAME_PERSON_MEMORY), List.of(
|
||||||
|
new QRecord().withValue("id", 1).withValue("favoriteShapeId", 3),
|
||||||
|
new QRecord().withValue("id", 2).withValue("favoriteShapeId", 3),
|
||||||
|
new QRecord().withValue("id", 3).withValue("favoriteShapeId", 1)
|
||||||
|
));
|
||||||
|
TestUtils.insertDefaultShapes(instance);
|
||||||
|
|
||||||
|
QueryInput queryInput = new QueryInput(instance);
|
||||||
|
queryInput.setSession(new QSession());
|
||||||
|
queryInput.setTableName(TestUtils.TABLE_NAME_SHAPE);
|
||||||
|
QueryOutput queryOutput = new QueryAction().execute(queryInput);
|
||||||
|
|
||||||
|
GeneralProcessUtils.addForeignRecordsListToRecordList(queryInput, queryOutput.getRecords(), "id", TestUtils.TABLE_NAME_PERSON_MEMORY, "favoriteShapeId");
|
||||||
|
|
||||||
|
for(QRecord record : queryOutput.getRecords())
|
||||||
|
{
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
List<QRecord> foreignRecordList = (List<QRecord>) record.getValue(TestUtils.TABLE_NAME_PERSON_MEMORY);
|
||||||
|
|
||||||
|
if(record.getValueInteger("id").equals(3))
|
||||||
|
{
|
||||||
|
assertEquals(2, foreignRecordList.size());
|
||||||
|
}
|
||||||
|
else if(record.getValueInteger("id").equals(2))
|
||||||
|
{
|
||||||
|
assertNull(foreignRecordList);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(QRecord foreignRecord : foreignRecordList)
|
||||||
|
{
|
||||||
|
assertEquals(record.getValue("id"), foreignRecord.getValue("favoriteShapeId"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testGetRecordListByField() throws QException
|
||||||
|
{
|
||||||
|
QInstance instance = TestUtils.defineInstance();
|
||||||
|
|
||||||
|
TestUtils.insertRecords(instance, instance.getTable(TestUtils.TABLE_NAME_PERSON_MEMORY), List.of(
|
||||||
|
new QRecord().withValue("id", 1).withValue("favoriteShapeId", 3),
|
||||||
|
new QRecord().withValue("id", 2).withValue("favoriteShapeId", 3),
|
||||||
|
new QRecord().withValue("id", 3).withValue("favoriteShapeId", 1)
|
||||||
|
));
|
||||||
|
|
||||||
|
QueryInput queryInput = new QueryInput(instance);
|
||||||
|
queryInput.setSession(new QSession());
|
||||||
|
List<QRecord> records = GeneralProcessUtils.getRecordListByField(queryInput, TestUtils.TABLE_NAME_PERSON_MEMORY, "favoriteShapeId", 3);
|
||||||
|
assertEquals(2, records.size());
|
||||||
|
assertTrue(records.stream().anyMatch(r -> r.getValue("id").equals(1)));
|
||||||
|
assertTrue(records.stream().anyMatch(r -> r.getValue("id").equals(2)));
|
||||||
|
assertTrue(records.stream().noneMatch(r -> r.getValue("id").equals(3)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testGetRecordById() throws QException
|
||||||
|
{
|
||||||
|
QInstance instance = TestUtils.defineInstance();
|
||||||
|
|
||||||
|
TestUtils.insertRecords(instance, instance.getTable(TestUtils.TABLE_NAME_PERSON_MEMORY), List.of(
|
||||||
|
new QRecord().withValue("id", 1).withValue("firstName", "Darin"),
|
||||||
|
new QRecord().withValue("id", 2).withValue("firstName", "James"),
|
||||||
|
new QRecord().withValue("id", 3).withValue("firstName", "Tim")
|
||||||
|
));
|
||||||
|
|
||||||
|
QueryInput queryInput = new QueryInput(instance);
|
||||||
|
queryInput.setSession(new QSession());
|
||||||
|
Optional<QRecord> record = GeneralProcessUtils.getRecordById(queryInput, TestUtils.TABLE_NAME_PERSON_MEMORY, "firstName", "James");
|
||||||
|
assertTrue(record.isPresent());
|
||||||
|
assertEquals(2, record.get().getValueInteger("id"));
|
||||||
|
|
||||||
|
record = GeneralProcessUtils.getRecordById(queryInput, TestUtils.TABLE_NAME_PERSON_MEMORY, "firstName", "Bobby");
|
||||||
|
assertFalse(record.isPresent());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testLoadTable() throws QException
|
||||||
|
{
|
||||||
|
QInstance instance = TestUtils.defineInstance();
|
||||||
|
|
||||||
|
TestUtils.insertRecords(instance, instance.getTable(TestUtils.TABLE_NAME_PERSON_MEMORY), List.of(
|
||||||
|
new QRecord().withValue("id", 1).withValue("firstName", "Darin"),
|
||||||
|
new QRecord().withValue("id", 2).withValue("firstName", "James"),
|
||||||
|
new QRecord().withValue("id", 3).withValue("firstName", "Tim")
|
||||||
|
));
|
||||||
|
|
||||||
|
QueryInput queryInput = new QueryInput(instance);
|
||||||
|
queryInput.setSession(new QSession());
|
||||||
|
List<QRecord> records = GeneralProcessUtils.loadTable(queryInput, TestUtils.TABLE_NAME_PERSON_MEMORY);
|
||||||
|
assertEquals(3, records.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testLoadTableToMap() throws QException
|
||||||
|
{
|
||||||
|
QInstance instance = TestUtils.defineInstance();
|
||||||
|
|
||||||
|
TestUtils.insertRecords(instance, instance.getTable(TestUtils.TABLE_NAME_PERSON_MEMORY), List.of(
|
||||||
|
new QRecord().withValue("id", 1).withValue("firstName", "Darin"),
|
||||||
|
new QRecord().withValue("id", 2).withValue("firstName", "James"),
|
||||||
|
new QRecord().withValue("id", 3).withValue("firstName", "Tim")
|
||||||
|
));
|
||||||
|
|
||||||
|
QueryInput queryInput = new QueryInput(instance);
|
||||||
|
queryInput.setSession(new QSession());
|
||||||
|
Map<Serializable, QRecord> recordMapById = GeneralProcessUtils.loadTableToMap(queryInput, TestUtils.TABLE_NAME_PERSON_MEMORY, "id");
|
||||||
|
assertEquals(3, recordMapById.size());
|
||||||
|
assertEquals("Darin", recordMapById.get(1).getValueString("firstName"));
|
||||||
|
assertEquals("James", recordMapById.get(2).getValueString("firstName"));
|
||||||
|
|
||||||
|
Map<Serializable, QRecord> recordMapByFirstName = GeneralProcessUtils.loadTableToMap(queryInput, TestUtils.TABLE_NAME_PERSON_MEMORY, "firstName");
|
||||||
|
assertEquals(3, recordMapByFirstName.size());
|
||||||
|
assertEquals(1, recordMapByFirstName.get("Darin").getValueInteger("id"));
|
||||||
|
assertEquals(3, recordMapByFirstName.get("Tim").getValueInteger("id"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testLoadTableToListingHash() throws QException
|
||||||
|
{
|
||||||
|
QInstance instance = TestUtils.defineInstance();
|
||||||
|
|
||||||
|
TestUtils.insertRecords(instance, instance.getTable(TestUtils.TABLE_NAME_PERSON_MEMORY), List.of(
|
||||||
|
new QRecord().withValue("id", 1).withValue("firstName", "Darin").withValue("lastName", "Kelkhoff"),
|
||||||
|
new QRecord().withValue("id", 2).withValue("firstName", "James").withValue("lastName", "Maes"),
|
||||||
|
new QRecord().withValue("id", 3).withValue("firstName", "James").withValue("lastName", "Brown")
|
||||||
|
));
|
||||||
|
|
||||||
|
QueryInput queryInput = new QueryInput(instance);
|
||||||
|
queryInput.setSession(new QSession());
|
||||||
|
ListingHash<Serializable, QRecord> map = GeneralProcessUtils.loadTableToListingHash(queryInput, TestUtils.TABLE_NAME_PERSON_MEMORY, "firstName");
|
||||||
|
assertEquals(2, map.size());
|
||||||
|
assertEquals(1, map.get("Darin").size());
|
||||||
|
assertEquals(2, map.get("James").size());
|
||||||
|
}
|
||||||
|
}
|
90
qqq-language-support-javascript/pom.xml
Normal file
90
qqq-language-support-javascript/pom.xml
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
~ QQQ - Low-code Application Framework for Engineers.
|
||||||
|
~ Copyright (C) 2021-2022. Kingsrook, LLC
|
||||||
|
~ 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
~ contact@kingsrook.com
|
||||||
|
~ https://github.com/Kingsrook/
|
||||||
|
~
|
||||||
|
~ This program is free software: you can redistribute it and/or modify
|
||||||
|
~ it under the terms of the GNU Affero General Public License as
|
||||||
|
~ published by the Free Software Foundation, either version 3 of the
|
||||||
|
~ License, or (at your option) any later version.
|
||||||
|
~
|
||||||
|
~ This program is distributed in the hope that it will be useful,
|
||||||
|
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
~ GNU Affero General Public License for more details.
|
||||||
|
~
|
||||||
|
~ You should have received a copy of the GNU Affero General Public License
|
||||||
|
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<artifactId>qqq-language-support-javascript</artifactId>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>com.kingsrook.qqq</groupId>
|
||||||
|
<artifactId>qqq-parent-project</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<!-- props specifically to this module -->
|
||||||
|
|
||||||
|
<!-- todo - remove these!! -->
|
||||||
|
<coverage.instructionCoveredRatioMinimum>0.10</coverage.instructionCoveredRatioMinimum>
|
||||||
|
<coverage.classCoveredRatioMinimum>0.10</coverage.classCoveredRatioMinimum>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<!-- other qqq modules deps -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.kingsrook.qqq</groupId>
|
||||||
|
<artifactId>qqq-backend-core</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 3rd party deps specifically for this module -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.openjdk.nashorn</groupId>
|
||||||
|
<artifactId>nashorn-core</artifactId>
|
||||||
|
<version>15.4</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Common deps for all qqq modules -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.logging.log4j</groupId>
|
||||||
|
<artifactId>log4j-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.logging.log4j</groupId>
|
||||||
|
<artifactId>log4j-core</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-engine</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.assertj</groupId>
|
||||||
|
<artifactId>assertj-core</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<!-- plugins specifically for this module -->
|
||||||
|
<!-- none at this time -->
|
||||||
|
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
@ -0,0 +1,168 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.languages.javascript;
|
||||||
|
|
||||||
|
|
||||||
|
import javax.script.Bindings;
|
||||||
|
import javax.script.ScriptEngine;
|
||||||
|
import javax.script.ScriptEngineManager;
|
||||||
|
import javax.script.ScriptException;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Map;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.scripts.QCodeExecutor;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.scripts.logging.QCodeExecutionLoggerInterface;
|
||||||
|
import com.kingsrook.qqq.backend.core.exceptions.QCodeException;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
|
||||||
|
import com.kingsrook.qqq.backend.core.utils.ExceptionUtils;
|
||||||
|
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||||
|
import org.apache.commons.lang.NotImplementedException;
|
||||||
|
import org.openjdk.nashorn.api.scripting.NashornScriptEngineFactory;
|
||||||
|
import org.openjdk.nashorn.internal.runtime.ECMAException;
|
||||||
|
import org.openjdk.nashorn.internal.runtime.ParserException;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public class QJavaScriptExecutor implements QCodeExecutor
|
||||||
|
{
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Override
|
||||||
|
public Serializable execute(QCodeReference codeReference, Map<String, Serializable> context, QCodeExecutionLoggerInterface executionLogger) throws QCodeException
|
||||||
|
{
|
||||||
|
String code = getCode(codeReference);
|
||||||
|
Serializable output = runInline(code, context, executionLogger);
|
||||||
|
return (output);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private Serializable runInline(String code, Map<String, Serializable> context, QCodeExecutionLoggerInterface executionLogger) throws QCodeException
|
||||||
|
{
|
||||||
|
new NashornScriptEngineFactory();
|
||||||
|
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
|
||||||
|
|
||||||
|
Bindings bindings = engine.createBindings();
|
||||||
|
bindings.putAll(context);
|
||||||
|
if(!bindings.containsKey("logger"))
|
||||||
|
{
|
||||||
|
bindings.put("logger", executionLogger);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////
|
||||||
|
// wrap the user's code in an immediately-invoked function expression //
|
||||||
|
////////////////////////////////////////////////////////////////////////
|
||||||
|
String codeToRun = """
|
||||||
|
(function userDefinedFunction()
|
||||||
|
{
|
||||||
|
%s
|
||||||
|
})();
|
||||||
|
""".formatted(code);
|
||||||
|
|
||||||
|
Serializable output;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
output = (Serializable) engine.eval(codeToRun, bindings);
|
||||||
|
}
|
||||||
|
catch(ScriptException se)
|
||||||
|
{
|
||||||
|
QCodeException qCodeException = getQCodeExceptionFromScriptException(se);
|
||||||
|
throw (qCodeException);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (output);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private QCodeException getQCodeExceptionFromScriptException(ScriptException se)
|
||||||
|
{
|
||||||
|
boolean isParserException = ExceptionUtils.findClassInRootChain(se, ParserException.class) != null;
|
||||||
|
boolean isUserThrownException = ExceptionUtils.findClassInRootChain(se, ECMAException.class) != null;
|
||||||
|
|
||||||
|
String message = se.getMessage();
|
||||||
|
String errorContext = null;
|
||||||
|
if(message != null)
|
||||||
|
{
|
||||||
|
message = message.replaceFirst(" in <eval>.*", "");
|
||||||
|
message = message.replaceFirst("<eval>:\\d+:\\d+", "");
|
||||||
|
|
||||||
|
if(message.contains("\n"))
|
||||||
|
{
|
||||||
|
String[] parts = message.split("\n", 2);
|
||||||
|
message = parts[0];
|
||||||
|
errorContext = parts[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int actualScriptLineNumber = se.getLineNumber() - 2;
|
||||||
|
|
||||||
|
String prefix = "Script Exception";
|
||||||
|
boolean includeColumn = true;
|
||||||
|
boolean includeContext = false;
|
||||||
|
if(isParserException)
|
||||||
|
{
|
||||||
|
prefix = "Script parser exception";
|
||||||
|
includeContext = true;
|
||||||
|
}
|
||||||
|
else if(isUserThrownException)
|
||||||
|
{
|
||||||
|
prefix = "Script threw an exception";
|
||||||
|
includeColumn = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QCodeException qCodeException = new QCodeException(prefix + " at line " + actualScriptLineNumber + (includeColumn ? (" column " + se.getColumnNumber()) : "") + ": " + message);
|
||||||
|
if(includeContext)
|
||||||
|
{
|
||||||
|
qCodeException.setContext(errorContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (qCodeException);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private String getCode(QCodeReference codeReference)
|
||||||
|
{
|
||||||
|
if(StringUtils.hasContent(codeReference.getInlineCode()))
|
||||||
|
{
|
||||||
|
return (codeReference.getInlineCode());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw (new NotImplementedException("Only inline code is implemented at this time."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,322 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.languages.javascript;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.scripts.ExecuteCodeAction;
|
||||||
|
import com.kingsrook.qqq.backend.core.exceptions.QCodeException;
|
||||||
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
|
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.metadata.QInstance;
|
||||||
|
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.code.QCodeUsage;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.session.QSession;
|
||||||
|
import org.assertj.core.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Unit test for ExecuteCodeAction
|
||||||
|
*******************************************************************************/
|
||||||
|
class ExecuteCodeActionTest
|
||||||
|
{
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testHelloWorld() throws QException
|
||||||
|
{
|
||||||
|
ExecuteCodeInput input = new ExecuteCodeInput(TestUtils.defineInstance())
|
||||||
|
.withCodeReference(new QCodeReference("helloWorld.js", QCodeType.JAVA_SCRIPT, QCodeUsage.CUSTOMIZER)
|
||||||
|
.withInlineCode("""
|
||||||
|
return "Hello, " + input"""))
|
||||||
|
.withContext("input", "World");
|
||||||
|
ExecuteCodeOutput output = new ExecuteCodeOutput();
|
||||||
|
new ExecuteCodeAction().run(input, output);
|
||||||
|
assertEquals("Hello, World", output.getOutput());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testSetInContextObject() throws QException
|
||||||
|
{
|
||||||
|
OneTestOutput oneTestOutput = testOne(3, """
|
||||||
|
var a = 1;
|
||||||
|
var b = 2;
|
||||||
|
output.setD(a + b + input.getC());
|
||||||
|
""");
|
||||||
|
assertEquals(6, oneTestOutput.testOutput().getD());
|
||||||
|
assertNull(oneTestOutput.executeCodeOutput().getOutput());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testReturnsContextObject() throws QException
|
||||||
|
{
|
||||||
|
OneTestOutput oneTestOutput = testOne(4, """
|
||||||
|
var a = 1;
|
||||||
|
var b = 2;
|
||||||
|
output.setD(a + b + input.getC());
|
||||||
|
return (output);
|
||||||
|
""");
|
||||||
|
assertEquals(7, oneTestOutput.testOutput().getD());
|
||||||
|
assertTrue(oneTestOutput.executeCodeOutput().getOutput() instanceof TestOutput);
|
||||||
|
assertEquals(7, ((TestOutput) oneTestOutput.executeCodeOutput().getOutput()).getD());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testReturnsPrimitive() throws QException
|
||||||
|
{
|
||||||
|
OneTestOutput oneTestOutput = testOne(5, """
|
||||||
|
var a = 1;
|
||||||
|
var b = 2;
|
||||||
|
output.setD(a + b + input.getC());
|
||||||
|
return output.getD()
|
||||||
|
""");
|
||||||
|
assertEquals(8, oneTestOutput.testOutput().getD());
|
||||||
|
assertEquals(8, oneTestOutput.executeCodeOutput().getOutput());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testThrows() throws QException
|
||||||
|
{
|
||||||
|
String code = """
|
||||||
|
var a = 1;
|
||||||
|
var b = 2;
|
||||||
|
if (input.getC() === 6)
|
||||||
|
{
|
||||||
|
throw ("oh no, six!");
|
||||||
|
}
|
||||||
|
output.setD(a + b + input.getC());
|
||||||
|
return output.getD()
|
||||||
|
""";
|
||||||
|
|
||||||
|
Assertions.assertThatThrownBy(() -> testOne(6, code))
|
||||||
|
.isInstanceOf(QCodeException.class)
|
||||||
|
.hasMessageContaining("threw")
|
||||||
|
.hasMessageContaining("oh no, six!")
|
||||||
|
.hasMessageContaining("line 5:");
|
||||||
|
|
||||||
|
OneTestOutput oneTestOutput = testOne(7, code);
|
||||||
|
assertEquals(10, oneTestOutput.testOutput().getD());
|
||||||
|
assertEquals(10, oneTestOutput.executeCodeOutput().getOutput());
|
||||||
|
|
||||||
|
Assertions.assertThatThrownBy(() -> testOne(6, """
|
||||||
|
var a = null;
|
||||||
|
return a.toString();
|
||||||
|
"""))
|
||||||
|
.isInstanceOf(QCodeException.class)
|
||||||
|
.hasMessageContaining("threw")
|
||||||
|
.hasMessageContaining("TypeError: null has no such function \"toString\"");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testSyntaxError() throws QException
|
||||||
|
{
|
||||||
|
Assertions.assertThatThrownBy(() -> testOne(6, """
|
||||||
|
var a = 1;
|
||||||
|
if (input.getC() === 6
|
||||||
|
{
|
||||||
|
"""))
|
||||||
|
.isInstanceOf(QCodeException.class)
|
||||||
|
.hasMessageContaining("parser")
|
||||||
|
.hasMessageContaining("line 3 column 0");
|
||||||
|
|
||||||
|
Assertions.assertThatThrownBy(() -> testOne(6, """
|
||||||
|
var a = 1;
|
||||||
|
vr b = 2;
|
||||||
|
"""))
|
||||||
|
.isInstanceOf(QCodeException.class)
|
||||||
|
.hasMessageContaining("parser")
|
||||||
|
.hasMessageContaining("line 2 column 3");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testLogs() throws QException
|
||||||
|
{
|
||||||
|
OneTestOutput oneTestOutput = testOne(5, """
|
||||||
|
logger.log("This is a log.");
|
||||||
|
""");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private OneTestOutput testOne(Integer inputValueC, String code) throws QException
|
||||||
|
{
|
||||||
|
System.out.println();
|
||||||
|
QInstance instance = TestUtils.defineInstance();
|
||||||
|
|
||||||
|
TestInput testInput = new TestInput();
|
||||||
|
testInput.setC(inputValueC);
|
||||||
|
|
||||||
|
TestOutput testOutput = new TestOutput();
|
||||||
|
|
||||||
|
ExecuteCodeInput input = new ExecuteCodeInput(instance);
|
||||||
|
input.setSession(new QSession());
|
||||||
|
input.setCodeReference(new QCodeReference("test.js", QCodeType.JAVA_SCRIPT, QCodeUsage.CUSTOMIZER).withInlineCode(code));
|
||||||
|
input.withContext("input", testInput);
|
||||||
|
input.withContext("output", testOutput);
|
||||||
|
|
||||||
|
ExecuteCodeOutput output = new ExecuteCodeOutput();
|
||||||
|
|
||||||
|
ExecuteCodeAction executeCodeAction = new ExecuteCodeAction();
|
||||||
|
executeCodeAction.run(input, output);
|
||||||
|
|
||||||
|
return (new OneTestOutput(output, testOutput));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private record OneTestOutput(ExecuteCodeOutput executeCodeOutput, TestOutput testOutput)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public static class TestInput implements Serializable
|
||||||
|
{
|
||||||
|
private Integer c;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for c
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Integer getC()
|
||||||
|
{
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for c
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setC(Integer c)
|
||||||
|
{
|
||||||
|
this.c = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return "TestInput{c=" + c + '}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public static class TestOutput implements Serializable
|
||||||
|
{
|
||||||
|
private Integer d;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for d
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Integer getD()
|
||||||
|
{
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for d
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setD(Integer d)
|
||||||
|
{
|
||||||
|
this.d = d;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return "TestOutput{d=" + d + '}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.languages.javascript;
|
||||||
|
|
||||||
|
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.QAuthenticationType;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.modules.authentication.metadata.QAuthenticationMetaData;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public class TestUtils
|
||||||
|
{
|
||||||
|
public static final String DEFAULT_BACKEND_NAME = "memoryBackend";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public static QInstance defineInstance()
|
||||||
|
{
|
||||||
|
QInstance qInstance = new QInstance();
|
||||||
|
qInstance.addBackend(defineBackend());
|
||||||
|
qInstance.addTable(defineTablePerson());
|
||||||
|
qInstance.setAuthentication(defineAuthentication());
|
||||||
|
return (qInstance);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Define the authentication used in standard tests - using 'mock' type.
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public static QAuthenticationMetaData defineAuthentication()
|
||||||
|
{
|
||||||
|
return new QAuthenticationMetaData()
|
||||||
|
.withName("mock")
|
||||||
|
.withType(QAuthenticationType.MOCK);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public static QBackendMetaData defineBackend()
|
||||||
|
{
|
||||||
|
return (new QBackendMetaData()
|
||||||
|
.withName(DEFAULT_BACKEND_NAME)
|
||||||
|
.withBackendType("memory"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private static QTableMetaData defineTablePerson()
|
||||||
|
{
|
||||||
|
return new QTableMetaData()
|
||||||
|
.withName("person")
|
||||||
|
.withLabel("Person")
|
||||||
|
.withBackendName(DEFAULT_BACKEND_NAME)
|
||||||
|
.withPrimaryKeyField("id")
|
||||||
|
.withField(new QFieldMetaData("id", QFieldType.INTEGER).withIsEditable(false))
|
||||||
|
.withField(new QFieldMetaData("createDate", QFieldType.DATE_TIME).withIsEditable(false))
|
||||||
|
.withField(new QFieldMetaData("modifyDate", QFieldType.DATE_TIME).withIsEditable(false))
|
||||||
|
.withField(new QFieldMetaData("firstName", QFieldType.STRING))
|
||||||
|
.withField(new QFieldMetaData("lastName", QFieldType.STRING))
|
||||||
|
.withField(new QFieldMetaData("birthDate", QFieldType.DATE))
|
||||||
|
.withField(new QFieldMetaData("email", QFieldType.STRING));
|
||||||
|
}
|
||||||
|
}
|
@ -42,6 +42,8 @@ import com.kingsrook.qqq.backend.core.actions.metadata.MetaDataAction;
|
|||||||
import com.kingsrook.qqq.backend.core.actions.metadata.ProcessMetaDataAction;
|
import com.kingsrook.qqq.backend.core.actions.metadata.ProcessMetaDataAction;
|
||||||
import com.kingsrook.qqq.backend.core.actions.metadata.TableMetaDataAction;
|
import com.kingsrook.qqq.backend.core.actions.metadata.TableMetaDataAction;
|
||||||
import com.kingsrook.qqq.backend.core.actions.reporting.ExportAction;
|
import com.kingsrook.qqq.backend.core.actions.reporting.ExportAction;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.scripts.StoreAssociatedScriptAction;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.scripts.TestScriptAction;
|
||||||
import com.kingsrook.qqq.backend.core.actions.tables.CountAction;
|
import com.kingsrook.qqq.backend.core.actions.tables.CountAction;
|
||||||
import com.kingsrook.qqq.backend.core.actions.tables.DeleteAction;
|
import com.kingsrook.qqq.backend.core.actions.tables.DeleteAction;
|
||||||
import com.kingsrook.qqq.backend.core.actions.tables.GetAction;
|
import com.kingsrook.qqq.backend.core.actions.tables.GetAction;
|
||||||
@ -66,6 +68,10 @@ import com.kingsrook.qqq.backend.core.model.actions.metadata.TableMetaDataInput;
|
|||||||
import com.kingsrook.qqq.backend.core.model.actions.metadata.TableMetaDataOutput;
|
import com.kingsrook.qqq.backend.core.model.actions.metadata.TableMetaDataOutput;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.reporting.ExportInput;
|
import com.kingsrook.qqq.backend.core.model.actions.reporting.ExportInput;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.reporting.ReportFormat;
|
import com.kingsrook.qqq.backend.core.model.actions.reporting.ReportFormat;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.scripts.StoreAssociatedScriptInput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.scripts.StoreAssociatedScriptOutput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.scripts.TestScriptInput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.scripts.TestScriptOutput;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.count.CountInput;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.count.CountInput;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.count.CountOutput;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.count.CountOutput;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.delete.DeleteInput;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.delete.DeleteInput;
|
||||||
@ -74,6 +80,9 @@ 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.actions.tables.get.GetOutput;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertOutput;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertOutput;
|
||||||
|
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.QFilterOrderBy;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
|
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.QueryInput;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput;
|
||||||
@ -86,11 +95,13 @@ import com.kingsrook.qqq.backend.core.model.actions.widgets.RenderWidgetOutput;
|
|||||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
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.metadata.QInstance;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.AssociatedScript;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.session.QSession;
|
import com.kingsrook.qqq.backend.core.model.session.QSession;
|
||||||
import com.kingsrook.qqq.backend.core.modules.authentication.Auth0AuthenticationModule;
|
import com.kingsrook.qqq.backend.core.modules.authentication.Auth0AuthenticationModule;
|
||||||
import com.kingsrook.qqq.backend.core.modules.authentication.QAuthenticationModuleDispatcher;
|
import com.kingsrook.qqq.backend.core.modules.authentication.QAuthenticationModuleDispatcher;
|
||||||
import com.kingsrook.qqq.backend.core.modules.authentication.QAuthenticationModuleInterface;
|
import com.kingsrook.qqq.backend.core.modules.authentication.QAuthenticationModuleInterface;
|
||||||
|
import com.kingsrook.qqq.backend.core.processes.utils.GeneralProcessUtils;
|
||||||
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||||
import com.kingsrook.qqq.backend.core.utils.ExceptionUtils;
|
import com.kingsrook.qqq.backend.core.utils.ExceptionUtils;
|
||||||
import com.kingsrook.qqq.backend.core.utils.JsonUtils;
|
import com.kingsrook.qqq.backend.core.utils.JsonUtils;
|
||||||
@ -271,6 +282,7 @@ public class QJavalinImplementation
|
|||||||
{
|
{
|
||||||
get("", QJavalinImplementation::processMetaData);
|
get("", QJavalinImplementation::processMetaData);
|
||||||
});
|
});
|
||||||
|
get("/authentication", QJavalinImplementation::authenticationMetaData);
|
||||||
});
|
});
|
||||||
|
|
||||||
/////////////////////////
|
/////////////////////////
|
||||||
@ -294,6 +306,11 @@ public class QJavalinImplementation
|
|||||||
patch("", QJavalinImplementation::dataUpdate);
|
patch("", QJavalinImplementation::dataUpdate);
|
||||||
put("", QJavalinImplementation::dataUpdate); // todo - want different semantics??
|
put("", QJavalinImplementation::dataUpdate); // todo - want different semantics??
|
||||||
delete("", QJavalinImplementation::dataDelete);
|
delete("", QJavalinImplementation::dataDelete);
|
||||||
|
|
||||||
|
get("/developer", QJavalinImplementation::getRecordDeveloperMode);
|
||||||
|
post("/developer/associatedScript/{fieldName}", QJavalinImplementation::storeRecordAssociatedScript);
|
||||||
|
get("/developer/associatedScript/{fieldName}/{scriptRevisionId}/logs", QJavalinImplementation::getAssociatedScriptLogs);
|
||||||
|
post("/developer/associatedScript/{fieldName}/test", QJavalinImplementation::testAssociatedScript);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -308,6 +325,16 @@ public class QJavalinImplementation
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private static void authenticationMetaData(Context context)
|
||||||
|
{
|
||||||
|
context.result(JsonUtils.toJson(qInstance.getAuthentication()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
@ -932,6 +959,211 @@ public class QJavalinImplementation
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private static void getRecordDeveloperMode(Context context)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
String tableName = context.pathParam("table");
|
||||||
|
QTableMetaData table = qInstance.getTable(tableName);
|
||||||
|
String primaryKey = context.pathParam("primaryKey");
|
||||||
|
GetInput getInput = new GetInput(qInstance);
|
||||||
|
|
||||||
|
setupSession(context, getInput);
|
||||||
|
getInput.setTableName(tableName);
|
||||||
|
getInput.setShouldGenerateDisplayValues(true);
|
||||||
|
getInput.setShouldTranslatePossibleValues(true);
|
||||||
|
|
||||||
|
// todo - validate that the primary key is of the proper type (e.g,. not a string for an id field)
|
||||||
|
// and throw a 400-series error (tell the user bad-request), rather than, we're doing a 500 (server error)
|
||||||
|
|
||||||
|
getInput.setPrimaryKey(primaryKey);
|
||||||
|
|
||||||
|
GetAction getAction = new GetAction();
|
||||||
|
GetOutput getOutput = getAction.execute(getInput);
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////
|
||||||
|
// throw a not found error if the record isn't found //
|
||||||
|
///////////////////////////////////////////////////////
|
||||||
|
QRecord record = getOutput.getRecord();
|
||||||
|
if(record == null)
|
||||||
|
{
|
||||||
|
throw (new QNotFoundException("Could not find " + table.getLabel() + " with "
|
||||||
|
+ table.getFields().get(table.getPrimaryKeyField()).getLabel() + " of " + primaryKey));
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, Serializable> rs = new HashMap<>();
|
||||||
|
rs.put("record", record);
|
||||||
|
|
||||||
|
ArrayList<HashMap<String, Serializable>> associatedScripts = new ArrayList<>();
|
||||||
|
rs.put("associatedScripts", associatedScripts);
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////
|
||||||
|
// process each associated script type for the table //
|
||||||
|
///////////////////////////////////////////////////////
|
||||||
|
for(AssociatedScript associatedScript : CollectionUtils.nonNullList(table.getAssociatedScripts()))
|
||||||
|
{
|
||||||
|
HashMap<String, Serializable> thisScriptData = new HashMap<>();
|
||||||
|
associatedScripts.add(thisScriptData);
|
||||||
|
thisScriptData.put("associatedScript", associatedScript);
|
||||||
|
|
||||||
|
String fieldName = associatedScript.getFieldName();
|
||||||
|
Serializable scriptId = record.getValue(fieldName);
|
||||||
|
if(scriptId != null)
|
||||||
|
{
|
||||||
|
GetInput getScriptInput = new GetInput(qInstance);
|
||||||
|
setupSession(context, getScriptInput);
|
||||||
|
getScriptInput.setTableName("script");
|
||||||
|
getScriptInput.setPrimaryKey(scriptId);
|
||||||
|
GetOutput getScriptOutput = new GetAction().execute(getScriptInput);
|
||||||
|
if(getScriptOutput.getRecord() != null)
|
||||||
|
{
|
||||||
|
thisScriptData.put("script", getScriptOutput.getRecord());
|
||||||
|
|
||||||
|
QueryInput queryInput = new QueryInput(qInstance);
|
||||||
|
setupSession(context, queryInput);
|
||||||
|
queryInput.setTableName("scriptRevision");
|
||||||
|
queryInput.setFilter(new QQueryFilter()
|
||||||
|
.withCriteria(new QFilterCriteria("scriptId", QCriteriaOperator.EQUALS, List.of(getScriptOutput.getRecord().getValue("id"))))
|
||||||
|
.withOrderBy(new QFilterOrderBy("id", false))
|
||||||
|
);
|
||||||
|
QueryOutput queryOutput = new QueryAction().execute(queryInput);
|
||||||
|
thisScriptData.put("scriptRevisions", new ArrayList<>(queryOutput.getRecords()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
context.result(JsonUtils.toJson(rs));
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
handleException(context, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public static void getAssociatedScriptLogs(Context context)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
String scriptRevisionId = context.pathParam("scriptRevisionId");
|
||||||
|
|
||||||
|
QueryInput queryInput = new QueryInput(qInstance);
|
||||||
|
setupSession(context, queryInput);
|
||||||
|
queryInput.setTableName("scriptLog");
|
||||||
|
queryInput.setFilter(new QQueryFilter()
|
||||||
|
.withCriteria(new QFilterCriteria("scriptRevisionId", QCriteriaOperator.EQUALS, List.of(scriptRevisionId)))
|
||||||
|
.withOrderBy(new QFilterOrderBy("id", false))
|
||||||
|
);
|
||||||
|
queryInput.setLimit(100);
|
||||||
|
QueryOutput queryOutput = new QueryAction().execute(queryInput);
|
||||||
|
|
||||||
|
if(CollectionUtils.nullSafeHasContents(queryOutput.getRecords()))
|
||||||
|
{
|
||||||
|
GeneralProcessUtils.addForeignRecordsListToRecordList(queryInput, queryOutput.getRecords(), "id", "scriptLogLine", "scriptLogId");
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, Serializable> rs = new HashMap<>();
|
||||||
|
rs.put("scriptLogRecords", new ArrayList<>(queryOutput.getRecords()));
|
||||||
|
|
||||||
|
context.result(JsonUtils.toJson(rs));
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
handleException(context, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private static void storeRecordAssociatedScript(Context context)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
StoreAssociatedScriptInput input = new StoreAssociatedScriptInput(qInstance);
|
||||||
|
setupSession(context, input);
|
||||||
|
input.setCode(context.formParam("contents"));
|
||||||
|
input.setCommitMessage(context.formParam("commitMessage"));
|
||||||
|
input.setFieldName(context.pathParam("fieldName"));
|
||||||
|
input.setTableName(context.pathParam("table"));
|
||||||
|
input.setRecordPrimaryKey(context.pathParam("primaryKey"));
|
||||||
|
|
||||||
|
StoreAssociatedScriptOutput output = new StoreAssociatedScriptOutput();
|
||||||
|
|
||||||
|
StoreAssociatedScriptAction storeAssociatedScriptAction = new StoreAssociatedScriptAction();
|
||||||
|
storeAssociatedScriptAction.run(input, output);
|
||||||
|
|
||||||
|
context.result(JsonUtils.toJson("OK"));
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
handleException(context, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private static void testAssociatedScript(Context context)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
TestScriptInput input = new TestScriptInput(qInstance);
|
||||||
|
setupSession(context, input);
|
||||||
|
input.setTableName(context.pathParam("table"));
|
||||||
|
input.setRecordPrimaryKey(context.pathParam("primaryKey"));
|
||||||
|
// context.pathParam("fieldName");
|
||||||
|
Map<String, String> inputValues = new HashMap<>();
|
||||||
|
input.setInputValues(inputValues);
|
||||||
|
|
||||||
|
for(Map.Entry<String, List<String>> entry : context.formParamMap().entrySet())
|
||||||
|
{
|
||||||
|
String key = entry.getKey();
|
||||||
|
String value = entry.getValue().get(0);
|
||||||
|
|
||||||
|
if(key.equals("code"))
|
||||||
|
{
|
||||||
|
input.setCode(value);
|
||||||
|
}
|
||||||
|
else if(key.equals("scriptTypeId"))
|
||||||
|
{
|
||||||
|
input.setScriptTypeId(ValueUtils.getValueAsInteger(value));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
inputValues.put(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TestScriptOutput output = new TestScriptOutput();
|
||||||
|
|
||||||
|
new TestScriptAction().run(input, output);
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////
|
||||||
|
// todo - output to frontend - then add assertions in test. //
|
||||||
|
//////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
context.result(JsonUtils.toJson("OK"));
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
handleException(context, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
@ -26,9 +26,23 @@ import java.io.Serializable;
|
|||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
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.exceptions.QException;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.reporting.ReportFormat;
|
import com.kingsrook.qqq.backend.core.model.actions.reporting.ReportFormat;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput;
|
||||||
|
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.QueryOutput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.tables.update.UpdateInput;
|
||||||
import com.kingsrook.qqq.backend.core.model.dashboard.widgets.WidgetType;
|
import com.kingsrook.qqq.backend.core.model.dashboard.widgets.WidgetType;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.session.QSession;
|
||||||
import com.kingsrook.qqq.backend.core.utils.JsonUtils;
|
import com.kingsrook.qqq.backend.core.utils.JsonUtils;
|
||||||
import kong.unirest.HttpResponse;
|
import kong.unirest.HttpResponse;
|
||||||
import kong.unirest.Unirest;
|
import kong.unirest.Unirest;
|
||||||
@ -68,7 +82,7 @@ class QJavalinImplementationTest extends QJavalinTestBase
|
|||||||
JSONObject jsonObject = JsonUtils.toJSONObject(response.getBody());
|
JSONObject jsonObject = JsonUtils.toJSONObject(response.getBody());
|
||||||
assertTrue(jsonObject.has("tables"));
|
assertTrue(jsonObject.has("tables"));
|
||||||
JSONObject tables = jsonObject.getJSONObject("tables");
|
JSONObject tables = jsonObject.getJSONObject("tables");
|
||||||
assertEquals(1, tables.length());
|
assertEquals(6, tables.length()); // person + 5 script tables
|
||||||
JSONObject personTable = tables.getJSONObject("person");
|
JSONObject personTable = tables.getJSONObject("person");
|
||||||
assertTrue(personTable.has("name"));
|
assertTrue(personTable.has("name"));
|
||||||
assertEquals("person", personTable.getString("name"));
|
assertEquals("person", personTable.getString("name"));
|
||||||
@ -616,4 +630,135 @@ class QJavalinImplementationTest extends QJavalinTestBase
|
|||||||
assertEquals(5, jsonObject.getJSONArray("options").getJSONObject(1).getInt("id"));
|
assertEquals(5, jsonObject.getJSONArray("options").getJSONObject(1).getInt("id"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testGetRecordDeveloperMode() throws QException
|
||||||
|
{
|
||||||
|
UpdateInput updateInput = new UpdateInput(TestUtils.defineInstance());
|
||||||
|
updateInput.setSession(new QSession());
|
||||||
|
updateInput.setTableName("person");
|
||||||
|
updateInput.setRecords(List.of(new QRecord().withValue("id", 1).withValue("testScriptId", 47)));
|
||||||
|
new UpdateAction().execute(updateInput);
|
||||||
|
|
||||||
|
InsertInput insertInput = new InsertInput(TestUtils.defineInstance());
|
||||||
|
insertInput.setSession(new QSession());
|
||||||
|
insertInput.setTableName("script");
|
||||||
|
insertInput.setRecords(List.of(new QRecord().withValue("id", 47).withValue("currentScriptRevisionId", 100)));
|
||||||
|
new InsertAction().execute(insertInput);
|
||||||
|
|
||||||
|
insertInput.setTableName("scriptRevision");
|
||||||
|
insertInput.setRecords(List.of(new QRecord().withValue("id", 1000).withValue("scriptId", 47).withValue("content", "var i;")));
|
||||||
|
new InsertAction().execute(insertInput);
|
||||||
|
|
||||||
|
HttpResponse<String> response = Unirest.get(BASE_URL + "/data/person/1/developer").asString();
|
||||||
|
assertEquals(200, response.getStatus());
|
||||||
|
JSONObject jsonObject = JsonUtils.toJSONObject(response.getBody());
|
||||||
|
System.out.println(jsonObject.toString(3));
|
||||||
|
assertNotNull(jsonObject);
|
||||||
|
assertNotNull(jsonObject.getJSONObject("record"));
|
||||||
|
assertEquals("Darin", jsonObject.getJSONObject("record").getJSONObject("values").getString("firstName"));
|
||||||
|
assertEquals("Darin", jsonObject.getJSONObject("record").getJSONObject("displayValues").getString("firstName"));
|
||||||
|
assertNotNull(jsonObject.getJSONArray("associatedScripts"));
|
||||||
|
assertNotNull(jsonObject.getJSONArray("associatedScripts").getJSONObject(0));
|
||||||
|
assertNotNull(jsonObject.getJSONArray("associatedScripts").getJSONObject(0).getJSONArray("scriptRevisions"));
|
||||||
|
assertEquals("var i;", jsonObject.getJSONArray("associatedScripts").getJSONObject(0).getJSONArray("scriptRevisions").getJSONObject(0).getJSONObject("values").getString("content"));
|
||||||
|
assertNotNull(jsonObject.getJSONArray("associatedScripts").getJSONObject(0).getJSONObject("script"));
|
||||||
|
assertEquals(100, jsonObject.getJSONArray("associatedScripts").getJSONObject(0).getJSONObject("script").getJSONObject("values").getInt("currentScriptRevisionId"));
|
||||||
|
assertNotNull(jsonObject.getJSONArray("associatedScripts").getJSONObject(0).getJSONObject("associatedScript"));
|
||||||
|
assertEquals("testScriptId", jsonObject.getJSONArray("associatedScripts").getJSONObject(0).getJSONObject("associatedScript").getString("fieldName"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testStoreRecordAssociatedScript() throws QException
|
||||||
|
{
|
||||||
|
InsertInput insertInput = new InsertInput(TestUtils.defineInstance());
|
||||||
|
insertInput.setSession(new QSession());
|
||||||
|
insertInput.setTableName("scriptType");
|
||||||
|
insertInput.setRecords(List.of(new QRecord().withValue("id", 1).withValue("name", "Test")));
|
||||||
|
new InsertAction().execute(insertInput);
|
||||||
|
|
||||||
|
HttpResponse<String> response = Unirest.post(BASE_URL + "/data/person/1/developer/associatedScript/testScriptId")
|
||||||
|
.field("contents", "var j = 0;")
|
||||||
|
.field("commitMessage", "Javalin Commit")
|
||||||
|
.asString();
|
||||||
|
|
||||||
|
QueryInput queryInput = new QueryInput(TestUtils.defineInstance());
|
||||||
|
queryInput.setSession(new QSession());
|
||||||
|
queryInput.setTableName("scriptRevision");
|
||||||
|
queryInput.setFilter(new QQueryFilter()
|
||||||
|
.withCriteria(new QFilterCriteria("contents", QCriteriaOperator.EQUALS, List.of("var j = 0;")))
|
||||||
|
.withCriteria(new QFilterCriteria("commitMessage", QCriteriaOperator.EQUALS, List.of("Javalin Commit")))
|
||||||
|
);
|
||||||
|
QueryOutput queryOutput = new QueryAction().execute(queryInput);
|
||||||
|
assertEquals(1, queryOutput.getRecords().size());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testTestAssociatedScript() throws QException
|
||||||
|
{
|
||||||
|
InsertInput insertInput = new InsertInput(TestUtils.defineInstance());
|
||||||
|
insertInput.setSession(new QSession());
|
||||||
|
insertInput.setTableName("scriptType");
|
||||||
|
insertInput.setRecords(List.of(new QRecord().withValue("id", 1).withValue("name", "Test")));
|
||||||
|
new InsertAction().execute(insertInput);
|
||||||
|
|
||||||
|
HttpResponse<String> response = Unirest.post(BASE_URL + "/data/person/1/developer/associatedScript/testScriptId/test")
|
||||||
|
.field("code", "var j = 0;")
|
||||||
|
.field("scriptTypeId", "1")
|
||||||
|
.field("x", "47")
|
||||||
|
.asString();
|
||||||
|
|
||||||
|
/////////////////////////////////////////
|
||||||
|
// todo - assertions after implemented //
|
||||||
|
/////////////////////////////////////////
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testGetAssociatedScriptLogs() throws QException
|
||||||
|
{
|
||||||
|
InsertInput insertInput = new InsertInput(TestUtils.defineInstance());
|
||||||
|
insertInput.setSession(new QSession());
|
||||||
|
insertInput.setTableName("scriptLog");
|
||||||
|
insertInput.setRecords(List.of(new QRecord().withValue("id", 1).withValue("output", "testOutput").withValue("scriptRevisionId", 100)));
|
||||||
|
new InsertAction().execute(insertInput);
|
||||||
|
|
||||||
|
insertInput.setTableName("scriptLogLine");
|
||||||
|
insertInput.setRecords(List.of(
|
||||||
|
new QRecord().withValue("scriptLogId", 1).withValue("text", "line one"),
|
||||||
|
new QRecord().withValue("scriptLogId", 1).withValue("text", "line two")
|
||||||
|
));
|
||||||
|
new InsertAction().execute(insertInput);
|
||||||
|
|
||||||
|
HttpResponse<String> response = Unirest.get(BASE_URL + "/data/person/1/developer/associatedScript/testScriptId/100/logs").asString();
|
||||||
|
assertEquals(200, response.getStatus());
|
||||||
|
JSONObject jsonObject = JsonUtils.toJSONObject(response.getBody());
|
||||||
|
assertNotNull(jsonObject.getJSONArray("scriptLogRecords"));
|
||||||
|
assertEquals(1, jsonObject.getJSONArray("scriptLogRecords").length());
|
||||||
|
assertNotNull(jsonObject.getJSONArray("scriptLogRecords").getJSONObject(0).getJSONObject("values"));
|
||||||
|
assertEquals("testOutput", jsonObject.getJSONArray("scriptLogRecords").getJSONObject(0).getJSONObject("values").getString("output"));
|
||||||
|
assertNotNull(jsonObject.getJSONArray("scriptLogRecords").getJSONObject(0).getJSONObject("values").getJSONArray("scriptLogLine"));
|
||||||
|
assertEquals(2, jsonObject.getJSONArray("scriptLogRecords").getJSONObject(0).getJSONObject("values").getJSONArray("scriptLogLine").length());
|
||||||
|
assertEquals("line one", jsonObject.getJSONArray("scriptLogRecords").getJSONObject(0).getJSONObject("values").getJSONArray("scriptLogLine").getJSONObject(0).getJSONObject("values").getString("text"));
|
||||||
|
assertEquals("line two", jsonObject.getJSONArray("scriptLogRecords").getJSONObject(0).getJSONObject("values").getJSONArray("scriptLogLine").getJSONObject(1).getJSONObject("values").getString("text"));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,7 @@ import com.kingsrook.qqq.backend.core.exceptions.QValueException;
|
|||||||
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInput;
|
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.actions.processes.RunBackendStepOutput;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.QAuthenticationType;
|
import com.kingsrook.qqq.backend.core.model.metadata.QAuthenticationType;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
|
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.code.QCodeType;
|
||||||
@ -47,7 +48,9 @@ import com.kingsrook.qqq.backend.core.model.metadata.processes.QFunctionInputMet
|
|||||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFunctionOutputMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFunctionOutputMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QRecordListMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.processes.QRecordListMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.AssociatedScript;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.scripts.ScriptsMetaDataProvider;
|
||||||
import com.kingsrook.qqq.backend.core.modules.authentication.metadata.QAuthenticationMetaData;
|
import com.kingsrook.qqq.backend.core.modules.authentication.metadata.QAuthenticationMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.processes.implementations.mock.MockBackendStep;
|
import com.kingsrook.qqq.backend.core.processes.implementations.mock.MockBackendStep;
|
||||||
import com.kingsrook.qqq.backend.module.rdbms.jdbc.ConnectionManager;
|
import com.kingsrook.qqq.backend.module.rdbms.jdbc.ConnectionManager;
|
||||||
@ -84,7 +87,7 @@ public class TestUtils
|
|||||||
public static void primeTestDatabase() throws Exception
|
public static void primeTestDatabase() throws Exception
|
||||||
{
|
{
|
||||||
ConnectionManager connectionManager = new ConnectionManager();
|
ConnectionManager connectionManager = new ConnectionManager();
|
||||||
Connection connection = connectionManager.getConnection(TestUtils.defineBackend());
|
Connection connection = connectionManager.getConnection(TestUtils.defineDefaultH2Backend());
|
||||||
InputStream primeTestDatabaseSqlStream = TestUtils.class.getResourceAsStream("/prime-test-database.sql");
|
InputStream primeTestDatabaseSqlStream = TestUtils.class.getResourceAsStream("/prime-test-database.sql");
|
||||||
assertNotNull(primeTestDatabaseSqlStream);
|
assertNotNull(primeTestDatabaseSqlStream);
|
||||||
List<String> lines = (List<String>) IOUtils.readLines(primeTestDatabaseSqlStream);
|
List<String> lines = (List<String>) IOUtils.readLines(primeTestDatabaseSqlStream);
|
||||||
@ -105,7 +108,7 @@ public class TestUtils
|
|||||||
public static void runTestSql(String sql, QueryManager.ResultSetProcessor resultSetProcessor) throws Exception
|
public static void runTestSql(String sql, QueryManager.ResultSetProcessor resultSetProcessor) throws Exception
|
||||||
{
|
{
|
||||||
ConnectionManager connectionManager = new ConnectionManager();
|
ConnectionManager connectionManager = new ConnectionManager();
|
||||||
Connection connection = connectionManager.getConnection(defineBackend());
|
Connection connection = connectionManager.getConnection(defineDefaultH2Backend());
|
||||||
QueryManager.executeStatement(connection, sql, resultSetProcessor);
|
QueryManager.executeStatement(connection, sql, resultSetProcessor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,7 +122,7 @@ public class TestUtils
|
|||||||
{
|
{
|
||||||
QInstance qInstance = new QInstance();
|
QInstance qInstance = new QInstance();
|
||||||
qInstance.setAuthentication(defineAuthentication());
|
qInstance.setAuthentication(defineAuthentication());
|
||||||
qInstance.addBackend(defineBackend());
|
qInstance.addBackend(defineDefaultH2Backend());
|
||||||
qInstance.addTable(defineTablePerson());
|
qInstance.addTable(defineTablePerson());
|
||||||
qInstance.addProcess(defineProcessGreetPeople());
|
qInstance.addProcess(defineProcessGreetPeople());
|
||||||
qInstance.addProcess(defineProcessGreetPeopleInteractive());
|
qInstance.addProcess(defineProcessGreetPeopleInteractive());
|
||||||
@ -128,6 +131,17 @@ public class TestUtils
|
|||||||
qInstance.addProcess(defineProcessSimpleThrow());
|
qInstance.addProcess(defineProcessSimpleThrow());
|
||||||
qInstance.addPossibleValueSource(definePossibleValueSourcePerson());
|
qInstance.addPossibleValueSource(definePossibleValueSourcePerson());
|
||||||
defineWidgets(qInstance);
|
defineWidgets(qInstance);
|
||||||
|
|
||||||
|
qInstance.addBackend(defineMemoryBackend());
|
||||||
|
try
|
||||||
|
{
|
||||||
|
new ScriptsMetaDataProvider().defineStandardScriptsTables(qInstance, defineMemoryBackend().getName(), null);
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
throw new IllegalStateException("Error adding script tables to instance");
|
||||||
|
}
|
||||||
|
|
||||||
return (qInstance);
|
return (qInstance);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,7 +176,7 @@ public class TestUtils
|
|||||||
** Define the h2 rdbms backend
|
** Define the h2 rdbms backend
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public static RDBMSBackendMetaData defineBackend()
|
public static RDBMSBackendMetaData defineDefaultH2Backend()
|
||||||
{
|
{
|
||||||
RDBMSBackendMetaData rdbmsBackendMetaData = new RDBMSBackendMetaData()
|
RDBMSBackendMetaData rdbmsBackendMetaData = new RDBMSBackendMetaData()
|
||||||
.withVendor("h2")
|
.withVendor("h2")
|
||||||
@ -176,6 +190,19 @@ public class TestUtils
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Define the memory-only backend
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public static QBackendMetaData defineMemoryBackend()
|
||||||
|
{
|
||||||
|
return new QBackendMetaData()
|
||||||
|
.withBackendType("memory")
|
||||||
|
.withName("memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** Define the person table
|
** Define the person table
|
||||||
**
|
**
|
||||||
@ -187,7 +214,7 @@ public class TestUtils
|
|||||||
.withLabel("Person")
|
.withLabel("Person")
|
||||||
.withRecordLabelFormat("%s %s")
|
.withRecordLabelFormat("%s %s")
|
||||||
.withRecordLabelFields("firstName", "lastName")
|
.withRecordLabelFields("firstName", "lastName")
|
||||||
.withBackendName(defineBackend().getName())
|
.withBackendName(defineDefaultH2Backend().getName())
|
||||||
.withPrimaryKeyField("id")
|
.withPrimaryKeyField("id")
|
||||||
.withField(new QFieldMetaData("id", QFieldType.INTEGER))
|
.withField(new QFieldMetaData("id", QFieldType.INTEGER))
|
||||||
.withField(new QFieldMetaData("createDate", QFieldType.DATE_TIME).withBackendName("create_date"))
|
.withField(new QFieldMetaData("createDate", QFieldType.DATE_TIME).withBackendName("create_date"))
|
||||||
@ -196,7 +223,11 @@ public class TestUtils
|
|||||||
.withField(new QFieldMetaData("lastName", QFieldType.STRING).withBackendName("last_name"))
|
.withField(new QFieldMetaData("lastName", QFieldType.STRING).withBackendName("last_name"))
|
||||||
.withField(new QFieldMetaData("birthDate", QFieldType.DATE).withBackendName("birth_date"))
|
.withField(new QFieldMetaData("birthDate", QFieldType.DATE).withBackendName("birth_date"))
|
||||||
.withField(new QFieldMetaData("partnerPersonId", QFieldType.INTEGER).withBackendName("partner_person_id").withPossibleValueSourceName("person"))
|
.withField(new QFieldMetaData("partnerPersonId", QFieldType.INTEGER).withBackendName("partner_person_id").withPossibleValueSourceName("person"))
|
||||||
.withField(new QFieldMetaData("email", QFieldType.STRING));
|
.withField(new QFieldMetaData("email", QFieldType.STRING))
|
||||||
|
.withField(new QFieldMetaData("testScriptId", QFieldType.INTEGER).withBackendName("test_script_id"))
|
||||||
|
.withAssociatedScript(new AssociatedScript()
|
||||||
|
.withFieldName("testScriptId")
|
||||||
|
.withScriptTypeId(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -30,7 +30,8 @@ CREATE TABLE person
|
|||||||
last_name VARCHAR(80) NOT NULL,
|
last_name VARCHAR(80) NOT NULL,
|
||||||
birth_date DATE,
|
birth_date DATE,
|
||||||
email VARCHAR(250) NOT NULL,
|
email VARCHAR(250) NOT NULL,
|
||||||
partner_person_id INT
|
partner_person_id INT,
|
||||||
|
test_script_id INT
|
||||||
);
|
);
|
||||||
|
|
||||||
INSERT INTO person (id, first_name, last_name, birth_date, email) VALUES (1, 'Darin', 'Kelkhoff', '1980-05-31', 'darin.kelkhoff@gmail.com');
|
INSERT INTO person (id, first_name, last_name, birth_date, email) VALUES (1, 'Darin', 'Kelkhoff', '1980-05-31', 'darin.kelkhoff@gmail.com');
|
||||||
|
Reference in New Issue
Block a user