Merge branch 'release/0.0.0'

This commit is contained in:
2022-07-01 11:50:41 -05:00
12 changed files with 448 additions and 142 deletions

77
.circleci/config.yml Normal file
View File

@ -0,0 +1,77 @@
version: 2.1
executors:
java17:
docker:
- image: 'cimg/openjdk:17.0'
resource_class: small
orbs:
slack: circleci/slack@4.10.1
commands:
run_maven:
parameters:
maven_subcommand:
default: test
type: string
steps:
- checkout
- restore_cache:
keys:
- v1-dependencies-{{ checksum "pom.xml" }}
- run:
name: Run Maven
command: |
mvn -s .circleci/mvn-settings.xml << parameters.maven_subcommand >>
- run:
name: Save test results
command: |
mkdir -p ~/test-results/junit/
find . -type f -regex ".*/target/surefire-reports/.*xml" -exec cp {} ~/test-results/junit/ \;
when: always
- store_test_results:
path: ~/test-results
- save_cache:
paths:
- ~/.m2
key: v1-dependencies-{{ checksum "pom.xml" }}
jobs:
mvn_test:
executor: java17
steps:
- run_maven:
maven_subcommand: test
- slack/notify:
event: fail
mvn_deploy:
executor: java17
steps:
- run_maven:
maven_subcommand: deploy
- slack/notify:
event: always
workflows:
test_only:
jobs:
- mvn_test:
context: [ qqq-maven-registry-credentials, kingsrook-slack ]
filters:
branches:
ignore: /dev/
tags:
ignore: /(version|snapshot)-.*/
deploy:
jobs:
- mvn_deploy:
context: [ qqq-maven-registry-credentials, kingsrook-slack ]
filters:
branches:
only: /dev/
tags:
only: /(version|snapshot)-.*/

View File

@ -0,0 +1,9 @@
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
<servers>
<server>
<id>github-qqq-maven-registry</id>
<username>${env.QQQ_MAVEN_REGISTRY_USERNAME}</username>
<password>${env.QQQ_MAVEN_REGISTRY_PASSWORD}</password>
</server>
</servers>
</settings>

View File

@ -1,35 +0,0 @@
# This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
name: Java CI with Maven
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK 17
uses: actions/setup-java@v2
with:
java-version: '17'
distribution: 'adopt'
cache: maven
- name: maven-settings-xml-action
uses: whelk-io/maven-settings-xml-action@v20
with:
servers: '[{ "id": "github-qqq-maven-registry", "username": "${{ secrets.QQQ_MAVEN_REGISTRY_USERNAME }}", "password": "${{ secrets.QQQ_MAVEN_REGISTRY_PASSWORD }}" }]'
repositories: '[{ "id": "github-qqq-maven-registry", "url": "https://maven.pkg.github.com/Kingsrook/qqq-maven-registry", "snapshots": { "enabled": "true" }}]'
- name: Build with Maven
run: mvn -B package --file pom.xml
- name: Publish to GitHub Packages Apache Maven
run: mvn deploy
env:
GITHUB_TOKEN: ${{ github.token }}

View File

@ -6,8 +6,7 @@ This is a qqq middleware module, providing [picocli](https://picocli.info) acces
QQQ - Low-code Application Framework for Engineers. \ QQQ - Low-code Application Framework for Engineers. \
Copyright (C) 2022. Kingsrook, LLC \ Copyright (C) 2022. Kingsrook, LLC \
651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States \ 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States \
contact@kingsrook.com contact@kingsrook.com | https://github.com/Kingsrook/
https://github.com/Kingsrook/intellij-commentator-plugin
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as it under the terms of the GNU Affero General Public License as

View File

@ -46,6 +46,7 @@
--> -->
<module name="TreeWalker"> <module name="TreeWalker">
<module name="SuppressWarningsHolder"/>
<module name="OuterTypeFilename"/> <module name="OuterTypeFilename"/>
<module name="IllegalTokenText"> <module name="IllegalTokenText">
<property name="tokens" value="STRING_LITERAL, CHAR_LITERAL"/> <property name="tokens" value="STRING_LITERAL, CHAR_LITERAL"/>
@ -171,7 +172,7 @@
<property name="caseIndent" value="3"/> <property name="caseIndent" value="3"/>
<property name="throwsIndent" value="6"/> <property name="throwsIndent" value="6"/>
<property name="lineWrappingIndentation" value="3"/> <property name="lineWrappingIndentation" value="3"/>
<property name="arrayInitIndent" value="2"/> <property name="arrayInitIndent" value="6"/>
</module> </module>
<!-- <!--
<module name="AbbreviationAsWordInName"> <module name="AbbreviationAsWordInName">
@ -260,4 +261,5 @@
<module name="MissingOverride"/> <module name="MissingOverride"/>
</module> </module>
<module name="SuppressWarningsFilter"/>
</module> </module>

40
pom.xml
View File

@ -20,14 +20,18 @@
~ along with this program. If not, see <https://www.gnu.org/licenses/>. ~ along with this program. If not, see <https://www.gnu.org/licenses/>.
--> -->
<project xmlns="http://maven.apache.org/POM/4.0.0" <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">
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> <modelVersion>4.0.0</modelVersion>
<groupId>com.kingsrook.qqq</groupId> <groupId>com.kingsrook.qqq</groupId>
<artifactId>qqq-middleware-picocli</artifactId> <artifactId>qqq-middleware-picocli</artifactId>
<version>0.0-SNAPSHOT</version> <version>0.0.0</version>
<scm>
<connection>scm:git:git@github.com:Kingsrook/qqq-middleware-picocli.git</connection>
<developerConnection>scm:git:git@github.com:Kingsrook/qqq-middleware-picocli.git</developerConnection>
<tag>HEAD</tag>
</scm>
<properties> <properties>
<!-- props specifically to this module --> <!-- props specifically to this module -->
@ -47,12 +51,12 @@
<dependency> <dependency>
<groupId>com.kingsrook.qqq</groupId> <groupId>com.kingsrook.qqq</groupId>
<artifactId>qqq-backend-core</artifactId> <artifactId>qqq-backend-core</artifactId>
<version>0.0-SNAPSHOT</version> <version>0.0.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.kingsrook.qqq</groupId> <groupId>com.kingsrook.qqq</groupId>
<artifactId>qqq-backend-module-rdbms</artifactId> <artifactId>qqq-backend-module-rdbms</artifactId>
<version>0.0-SNAPSHOT</version> <version>0.0.0</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
@ -65,7 +69,7 @@
<dependency> <dependency>
<groupId>com.h2database</groupId> <groupId>com.h2database</groupId>
<artifactId>h2</artifactId> <artifactId>h2</artifactId>
<version>1.4.197</version> <version>2.1.210</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
@ -78,12 +82,12 @@
<dependency> <dependency>
<groupId>org.apache.logging.log4j</groupId> <groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId> <artifactId>log4j-api</artifactId>
<version>2.15.0</version> <version>2.17.1</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.logging.log4j</groupId> <groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId> <artifactId>log4j-core</artifactId>
<version>2.15.0</version> <version>2.17.1</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.junit.jupiter</groupId> <groupId>org.junit.jupiter</groupId>
@ -156,12 +160,28 @@
</execution> </execution>
</executions> </executions>
</plugin> </plugin>
<plugin>
<groupId>com.amashchenko.maven.plugin</groupId>
<artifactId>gitflow-maven-plugin</artifactId>
<version>1.18.0</version>
<configuration>
<gitFlowConfig>
<productionBranch>main</productionBranch>
<developmentBranch>dev</developmentBranch>
<versionTagPrefix>version-</versionTagPrefix>
</gitFlowConfig>
<skipFeatureVersion>true</skipFeatureVersion> <!-- Keep feature names out of versions -->
<postReleaseGoals>install</postReleaseGoals> <!-- Let CI run deploys -->
<commitDevelopmentVersionAtStart>true</commitDevelopmentVersionAtStart>
<versionDigitToIncrement>1</versionDigitToIncrement> <!-- In general, we update the minor -->
</configuration>
</plugin>
</plugins> </plugins>
</build> </build>
<repositories> <repositories>
<repository> <repository>
<id>github</id> <id>github-qqq-maven-registry</id>
<name>GitHub QQQ Maven Registry</name> <name>GitHub QQQ Maven Registry</name>
<url>https://maven.pkg.github.com/Kingsrook/qqq-maven-registry</url> <url>https://maven.pkg.github.com/Kingsrook/qqq-maven-registry</url>
</repository> </repository>

View File

@ -0,0 +1,87 @@
/*
* 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.frontend.picocli;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import com.kingsrook.qqq.backend.core.callbacks.QProcessCallback;
import com.kingsrook.qqq.backend.core.model.actions.query.QQueryFilter;
import com.kingsrook.qqq.backend.core.model.metadata.QFieldMetaData;
import picocli.CommandLine;
/*******************************************************************************
** Define how a PicoCLI process gets data back to a QProcess.
*******************************************************************************/
public class PicoCliProcessCallback implements QProcessCallback
{
private final CommandLine commandLine;
/*******************************************************************************
** Constructor that takes the picocli CommandLine object
*******************************************************************************/
public PicoCliProcessCallback(CommandLine commandLine)
{
this.commandLine = commandLine;
}
/*******************************************************************************
** Get the filter query for this callback.
*******************************************************************************/
@Override
public QQueryFilter getQueryFilter()
{
return null;
}
/*******************************************************************************
** Get the field values for this callback.
*******************************************************************************/
@Override
public Map<String, Serializable> getFieldValues(List<QFieldMetaData> fields)
{
Map<String, Serializable> rs = new HashMap<>();
final Scanner scanner = new Scanner(System.in);
///////////////////////////////////
// todo - only if "interactive?" //
///////////////////////////////////
for(QFieldMetaData field : fields)
{
commandLine.getOut().println("Please supply a value for the field: [" + field.getLabel() + "]:");
rs.put(field.getName(), scanner.nextLine());
}
return (rs);
}
}

View File

@ -25,12 +25,16 @@ package com.kingsrook.qqq.frontend.picocli;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import com.kingsrook.qqq.backend.core.model.metadata.QFieldMetaData; import com.kingsrook.qqq.backend.core.model.metadata.QFieldMetaData;
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.QTableMetaData; import com.kingsrook.qqq.backend.core.model.metadata.QTableMetaData;
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.utils.CollectionUtils; import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
import com.kingsrook.qqq.backend.core.utils.StringUtils;
import picocli.CommandLine; import picocli.CommandLine;
@ -94,9 +98,27 @@ public class QCommandBuilder
List<QProcessMetaData> processes = qInstance.getProcessesForTable(tableName); List<QProcessMetaData> processes = qInstance.getProcessesForTable(tableName);
if(CollectionUtils.nullSafeHasContents(processes)) if(CollectionUtils.nullSafeHasContents(processes))
{ {
tableCommand.addSubcommand("process", defineTableProcessesCommand(table, processes)); tableCommand.addSubcommand("process", defineProcessesCommand(processes));
} }
}); });
///////////////////////////////////////////////////////////////////////////
// add all orphan processes (e.g., ones without tables) to the top-level //
///////////////////////////////////////////////////////////////////////////
List<QProcessMetaData> orphanProcesses = new ArrayList<>();
for(QProcessMetaData process : qInstance.getProcesses().values())
{
if(!StringUtils.hasContent(process.getTableName()))
{
orphanProcesses.add(process);
}
}
if(!orphanProcesses.isEmpty())
{
topCommandSpec.addSubcommand("processes", defineProcessesCommand(orphanProcesses));
}
return topCommandSpec; return topCommandSpec;
} }
@ -233,14 +255,34 @@ public class QCommandBuilder
/******************************************************************************* /*******************************************************************************
** **
*******************************************************************************/ *******************************************************************************/
private CommandLine.Model.CommandSpec defineTableProcessesCommand(QTableMetaData table, List<QProcessMetaData> processes) private CommandLine.Model.CommandSpec defineProcessesCommand(List<QProcessMetaData> processes)
{ {
CommandLine.Model.CommandSpec processesCommand = CommandLine.Model.CommandSpec.create(); CommandLine.Model.CommandSpec processesCommand = CommandLine.Model.CommandSpec.create();
for(QProcessMetaData process : processes) for(QProcessMetaData process : processes)
{ {
///////////////////////////////////////////
// add the sub-command to run the proces //
///////////////////////////////////////////
CommandLine.Model.CommandSpec processCommand = CommandLine.Model.CommandSpec.create(); CommandLine.Model.CommandSpec processCommand = CommandLine.Model.CommandSpec.create();
processesCommand.addSubcommand(process.getName(), processCommand); processesCommand.addSubcommand(process.getName(), processCommand);
//////////////////////////////////////////////////////////////////////////////////
// add all (distinct, by name) input fields to the command as --field-* options //
//////////////////////////////////////////////////////////////////////////////////
Map<String, QFieldMetaData> inputFieldMap = new LinkedHashMap<>();
for(QFieldMetaData inputField : process.getInputFields())
{
inputFieldMap.put(inputField.getName(), inputField);
}
for(QFieldMetaData field : inputFieldMap.values())
{
processCommand.addOption(CommandLine.Model.OptionSpec.builder("--field-" + field.getName())
.type(getClassForField(field))
.build());
}
} }
return (processesCommand); return (processesCommand);

View File

@ -36,7 +36,7 @@ import com.kingsrook.qqq.backend.core.actions.DeleteAction;
import com.kingsrook.qqq.backend.core.actions.InsertAction; import com.kingsrook.qqq.backend.core.actions.InsertAction;
import com.kingsrook.qqq.backend.core.actions.MetaDataAction; import com.kingsrook.qqq.backend.core.actions.MetaDataAction;
import com.kingsrook.qqq.backend.core.actions.QueryAction; import com.kingsrook.qqq.backend.core.actions.QueryAction;
import com.kingsrook.qqq.backend.core.actions.RunFunctionAction; import com.kingsrook.qqq.backend.core.actions.RunProcessAction;
import com.kingsrook.qqq.backend.core.actions.TableMetaDataAction; import com.kingsrook.qqq.backend.core.actions.TableMetaDataAction;
import com.kingsrook.qqq.backend.core.actions.UpdateAction; import com.kingsrook.qqq.backend.core.actions.UpdateAction;
import com.kingsrook.qqq.backend.core.adapters.CsvToQRecordAdapter; import com.kingsrook.qqq.backend.core.adapters.CsvToQRecordAdapter;
@ -53,6 +53,8 @@ import com.kingsrook.qqq.backend.core.model.actions.metadata.MetaDataRequest;
import com.kingsrook.qqq.backend.core.model.actions.metadata.MetaDataResult; import com.kingsrook.qqq.backend.core.model.actions.metadata.MetaDataResult;
import com.kingsrook.qqq.backend.core.model.actions.metadata.table.TableMetaDataRequest; import com.kingsrook.qqq.backend.core.model.actions.metadata.table.TableMetaDataRequest;
import com.kingsrook.qqq.backend.core.model.actions.metadata.table.TableMetaDataResult; import com.kingsrook.qqq.backend.core.model.actions.metadata.table.TableMetaDataResult;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunProcessRequest;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunProcessResult;
import com.kingsrook.qqq.backend.core.model.actions.query.QCriteriaOperator; import com.kingsrook.qqq.backend.core.model.actions.query.QCriteriaOperator;
import com.kingsrook.qqq.backend.core.model.actions.query.QFilterCriteria; import com.kingsrook.qqq.backend.core.model.actions.query.QFilterCriteria;
import com.kingsrook.qqq.backend.core.model.actions.query.QQueryFilter; import com.kingsrook.qqq.backend.core.model.actions.query.QQueryFilter;
@ -62,6 +64,7 @@ import com.kingsrook.qqq.backend.core.model.actions.shared.mapping.AbstractQFiel
import com.kingsrook.qqq.backend.core.model.actions.update.UpdateRequest; import com.kingsrook.qqq.backend.core.model.actions.update.UpdateRequest;
import com.kingsrook.qqq.backend.core.model.actions.update.UpdateResult; import com.kingsrook.qqq.backend.core.model.actions.update.UpdateResult;
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.QFieldMetaData;
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.QTableMetaData; import com.kingsrook.qqq.backend.core.model.metadata.QTableMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData; import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
@ -91,7 +94,7 @@ public class QPicoCliImplementation
public static final int DEFAULT_LIMIT = 20; public static final int DEFAULT_LIMIT = 20;
private static QInstance qInstance; private static QInstance qInstance;
private static QSession session; private static QSession session;
@ -106,14 +109,14 @@ public class QPicoCliImplementation
// parse args to look up metaData and prime instance // parse args to look up metaData and prime instance
if(args.length > 0 && args[0].startsWith("--qInstanceJsonFile=")) if(args.length > 0 && args[0].startsWith("--qInstanceJsonFile="))
{ {
String filePath = args[0].replaceFirst("--.*=", ""); String filePath = args[0].replaceFirst("--.*=", "");
String qInstanceJson = FileUtils.readFileToString(new File(filePath)); String qInstanceJson = FileUtils.readFileToString(new File(filePath));
qInstance = new QInstanceAdapter().jsonToQInstanceIncludingBackends(qInstanceJson); qInstance = new QInstanceAdapter().jsonToQInstanceIncludingBackends(qInstanceJson);
String[] subArgs = Arrays.copyOfRange(args, 1, args.length); String[] subArgs = Arrays.copyOfRange(args, 1, args.length);
QPicoCliImplementation qPicoCliImplementation = new QPicoCliImplementation(qInstance); QPicoCliImplementation qPicoCliImplementation = new QPicoCliImplementation(qInstance);
int exitCode = qPicoCliImplementation.runCli("qapi", subArgs); int exitCode = qPicoCliImplementation.runCli("qapi", subArgs);
System.exit(exitCode); System.exit(exitCode);
} }
else else
@ -226,7 +229,7 @@ public class QPicoCliImplementation
private static void setupSession(String[] args) throws QModuleDispatchException private static void setupSession(String[] args) throws QModuleDispatchException
{ {
QAuthenticationModuleDispatcher qAuthenticationModuleDispatcher = new QAuthenticationModuleDispatcher(); QAuthenticationModuleDispatcher qAuthenticationModuleDispatcher = new QAuthenticationModuleDispatcher();
QAuthenticationModuleInterface authenticationModule = qAuthenticationModuleDispatcher.getQModule(qInstance.getAuthentication()); QAuthenticationModuleInterface authenticationModule = qAuthenticationModuleDispatcher.getQModule(qInstance.getAuthentication());
// todo - does this need some per-provider logic actually? mmm... // todo - does this need some per-provider logic actually? mmm...
Map<String, String> authenticationContext = new HashMap<>(); Map<String, String> authenticationContext = new HashMap<>();
@ -247,9 +250,23 @@ public class QPicoCliImplementation
} }
else else
{ {
String subCommandName = parseResult.subcommand().commandSpec().name(); ParseResult subParseResult = parseResult.subcommand();
String subCommandName = subParseResult.commandSpec().name();
CommandLine subCommandLine = commandLine.getSubcommands().get(subCommandName); CommandLine subCommandLine = commandLine.getSubcommands().get(subCommandName);
return runTableLevelCommand(subCommandLine, parseResult.subcommand()); switch(subCommandName)
{
case "processes":
{
return runProcessCommand(subCommandLine, subParseResult);
}
default:
{
/////////////////////////////////////////////////////////
// by default, assume the command here is a table name //
/////////////////////////////////////////////////////////
return runTableLevelCommand(subCommandLine, subParseResult);
}
}
} }
} }
@ -265,7 +282,7 @@ public class QPicoCliImplementation
if(tableParseResult.hasSubcommand()) if(tableParseResult.hasSubcommand())
{ {
ParseResult subParseResult = tableParseResult.subcommand(); ParseResult subParseResult = tableParseResult.subcommand();
String subCommandName = subParseResult.commandSpec().name(); String subCommandName = subParseResult.commandSpec().name();
switch(subCommandName) switch(subCommandName)
{ {
case "meta-data": case "meta-data":
@ -291,7 +308,7 @@ public class QPicoCliImplementation
case "process": case "process":
{ {
CommandLine subCommandLine = commandLine.getSubcommands().get(subCommandName); CommandLine subCommandLine = commandLine.getSubcommands().get(subCommandName);
return runTableProcess(subCommandLine, tableName, subParseResult); return runProcessCommand(subCommandLine, subParseResult);
} }
default: default:
{ {
@ -311,35 +328,74 @@ public class QPicoCliImplementation
/******************************************************************************* /*******************************************************************************
** ** Handle a command up to the point where 'process' was given
*******************************************************************************/ *******************************************************************************/
private int runTableProcess(CommandLine commandLine, String tableName, ParseResult subParseResult) private int runProcessCommand(CommandLine commandLine, ParseResult subParseResult)
{ {
if(!subParseResult.hasSubcommand()) if(!subParseResult.hasSubcommand())
{ {
////////////////////////////////////////////////////////////////
// process name must be a sub-command, so, error if not given //
////////////////////////////////////////////////////////////////
commandLine.usage(commandLine.getOut()); commandLine.usage(commandLine.getOut());
return commandLine.getCommandSpec().exitCodeOnUsageHelp(); return commandLine.getCommandSpec().exitCodeOnUsageHelp();
} }
else else
{ {
String subCommandName = subParseResult.subcommand().commandSpec().name(); ///////////////////////////////////////////
// move on to running the actual process //
///////////////////////////////////////////
String subCommandName = subParseResult.subcommand().commandSpec().name();
CommandLine subCommandLine = commandLine.getSubcommands().get(subCommandName); CommandLine subCommandLine = commandLine.getSubcommands().get(subCommandName);
return runTableProcessLevelCommand(subCommandLine, tableName, subParseResult.subcommand()); return runActualProcess(subCommandLine, subParseResult.subcommand());
} }
} }
/******************************************************************************* /*******************************************************************************
** ** actually run a process (the process name should be at the start of the sub-command line)
*******************************************************************************/ *******************************************************************************/
private int runTableProcessLevelCommand(CommandLine subCommandLine, String tableName, ParseResult processParseResult) private int runActualProcess(CommandLine subCommandLine, ParseResult processParseResult)
{ {
String processName = processParseResult.commandSpec().name(); String processName = processParseResult.commandSpec().name();
QTableMetaData table = qInstance.getTable(tableName); QProcessMetaData process = qInstance.getProcess(processName);
QProcessMetaData process = qInstance.getProcess(processName); RunProcessRequest request = new RunProcessRequest(qInstance);
RunFunctionAction runFunctionAction = new RunFunctionAction();
// todo! request.setSession(session);
request.setProcessName(processName);
request.setCallback(new PicoCliProcessCallback(subCommandLine));
for(OptionSpec matchedOption : processParseResult.matchedOptions())
{
if(matchedOption.longestName().startsWith("--field-"))
{
String fieldName = matchedOption.longestName().substring(8);
request.addValue(fieldName, matchedOption.getValue());
}
}
try
{
RunProcessResult result = new RunProcessAction().execute(request);
subCommandLine.getOut().println("Process Results: "); // todo better!!
for(QFieldMetaData outputField : process.getOutputFields())
{
subCommandLine.getOut().format(" %s: %s\n", outputField.getLabel(), result.getValues().get(outputField.getName()));
}
if(result.getError() != null)
{
subCommandLine.getOut().println("Process Error message: " + result.getError());
}
}
catch(Exception e)
{
e.printStackTrace();
subCommandLine.getOut().println("Caught Exception running process. See stack trace above for details.");
return 1;
}
return 0; return 0;
} }
@ -379,7 +435,7 @@ public class QPicoCliImplementation
for(String criterion : criteria) for(String criterion : criteria)
{ {
// todo - parse! // todo - parse!
String[] parts = criterion.split(" "); String[] parts = criterion.split(" ");
QFilterCriteria qQueryCriteria = new QFilterCriteria(); QFilterCriteria qQueryCriteria = new QFilterCriteria();
qQueryCriteria.setFieldName(parts[0]); qQueryCriteria.setFieldName(parts[0]);
qQueryCriteria.setOperator(QCriteriaOperator.valueOf(parts[1])); qQueryCriteria.setOperator(QCriteriaOperator.valueOf(parts[1]));
@ -440,7 +496,7 @@ public class QPicoCliImplementation
try try
{ {
String path = subParseResult.matchedOptionValue("--csvFile", ""); String path = subParseResult.matchedOptionValue("--csvFile", "");
String csv = FileUtils.readFileToString(new File(path)); String csv = FileUtils.readFileToString(new File(path));
recordList = new CsvToQRecordAdapter().buildRecordsFromCsv(csv, table, mapping); recordList = new CsvToQRecordAdapter().buildRecordsFromCsv(csv, table, mapping);
} }
catch(IOException e) catch(IOException e)
@ -497,7 +553,7 @@ public class QPicoCliImplementation
boolean anyFields = false; boolean anyFields = false;
String primaryKeyOption = subParseResult.matchedOptionValue("--primaryKey", ""); String primaryKeyOption = subParseResult.matchedOptionValue("--primaryKey", "");
Serializable[] primaryKeyValues = primaryKeyOption.split(","); Serializable[] primaryKeyValues = primaryKeyOption.split(",");
for(Serializable primaryKeyValue : primaryKeyValues) for(Serializable primaryKeyValue : primaryKeyValues)
{ {
@ -546,7 +602,7 @@ public class QPicoCliImplementation
///////////////////////////////////////////// /////////////////////////////////////////////
// get the pKeys that the user specified // // get the pKeys that the user specified //
///////////////////////////////////////////// /////////////////////////////////////////////
String primaryKeyOption = subParseResult.matchedOptionValue("--primaryKey", ""); String primaryKeyOption = subParseResult.matchedOptionValue("--primaryKey", "");
Serializable[] primaryKeyValues = primaryKeyOption.split(","); Serializable[] primaryKeyValues = primaryKeyOption.split(",");
deleteRequest.setPrimaryKeys(Arrays.asList(primaryKeyValues)); deleteRequest.setPrimaryKeys(Arrays.asList(primaryKeyValues));

View File

@ -22,10 +22,12 @@
package com.kingsrook.qqq.frontend.picocli; package com.kingsrook.qqq.frontend.picocli;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream; import java.io.PrintStream;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
@ -37,7 +39,6 @@ import org.apache.commons.io.FileUtils;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONObject; import org.json.JSONObject;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
@ -51,8 +52,8 @@ import static org.junit.jupiter.api.Assertions.fail;
*******************************************************************************/ *******************************************************************************/
class QPicoCliImplementationTest class QPicoCliImplementationTest
{ {
private static final boolean VERBOSE = true; private static final boolean VERBOSE = true;
private static final String CLI_NAME = "cli-unit-test"; private static final String CLI_NAME = "cli-unit-test";
@ -115,7 +116,7 @@ class QPicoCliImplementationTest
@Test @Test
public void test_badOption() public void test_badOption()
{ {
String badOption = "--asdf"; String badOption = "--asdf";
TestOutput testOutput = testCli(badOption); TestOutput testOutput = testCli(badOption);
assertTestErrorContains(testOutput, "Unknown option: '" + badOption + "'"); assertTestErrorContains(testOutput, "Unknown option: '" + badOption + "'");
assertTestErrorContains(testOutput, "Usage: " + CLI_NAME); assertTestErrorContains(testOutput, "Usage: " + CLI_NAME);
@ -131,14 +132,22 @@ class QPicoCliImplementationTest
public void test_metaData() public void test_metaData()
{ {
TestOutput testOutput = testCli("--meta-data"); TestOutput testOutput = testCli("--meta-data");
JSONObject metaData = JsonUtils.toJSONObject(testOutput.getOutput()); JSONObject metaData = JsonUtils.toJSONObject(testOutput.getOutput());
assertNotNull(metaData); assertNotNull(metaData);
assertEquals(1, metaData.keySet().size(), "Number of top-level keys"); assertEquals(2, metaData.keySet().size(), "Number of top-level keys");
assertTrue(metaData.has("tables")); assertTrue(metaData.has("tables"));
JSONObject tables = metaData.getJSONObject("tables"); JSONObject tables = metaData.getJSONObject("tables");
JSONObject personTable = tables.getJSONObject("person"); JSONObject personTable = tables.getJSONObject("person");
assertEquals("person", personTable.getString("name")); assertEquals("person", personTable.getString("name"));
assertEquals("Person", personTable.getString("label")); assertEquals("Person", personTable.getString("label"));
assertTrue(metaData.has("processes"));
JSONObject processes = metaData.getJSONObject("processes");
JSONObject greetProcess = processes.getJSONObject("greet");
assertEquals("greet", greetProcess.getString("name"));
assertEquals("Greet", greetProcess.getString("label"));
assertEquals("person", greetProcess.getString("tableName"));
} }
@ -173,7 +182,7 @@ class QPicoCliImplementationTest
@Test @Test
public void test_tableUnknownCommand() public void test_tableUnknownCommand()
{ {
String badCommand = "qwuijibo"; String badCommand = "qwuijibo";
TestOutput testOutput = testCli("person", badCommand); TestOutput testOutput = testCli("person", badCommand);
assertTestErrorContains(testOutput, "Unmatched argument at index 1: '" + badCommand + "'"); assertTestErrorContains(testOutput, "Unmatched argument at index 1: '" + badCommand + "'");
assertTestErrorContains(testOutput, "Usage: " + CLI_NAME + " person \\[COMMAND\\]"); assertTestErrorContains(testOutput, "Usage: " + CLI_NAME + " person \\[COMMAND\\]");
@ -189,7 +198,7 @@ class QPicoCliImplementationTest
public void test_tableMetaData() public void test_tableMetaData()
{ {
TestOutput testOutput = testCli("person", "meta-data"); TestOutput testOutput = testCli("person", "meta-data");
JSONObject metaData = JsonUtils.toJSONObject(testOutput.getOutput()); JSONObject metaData = JsonUtils.toJSONObject(testOutput.getOutput());
assertNotNull(metaData); assertNotNull(metaData);
assertEquals(1, metaData.keySet().size(), "Number of top-level keys"); assertEquals(1, metaData.keySet().size(), "Number of top-level keys");
JSONObject table = metaData.getJSONObject("table"); JSONObject table = metaData.getJSONObject("table");
@ -212,7 +221,7 @@ class QPicoCliImplementationTest
@Test @Test
public void test_tableQuery() public void test_tableQuery()
{ {
TestOutput testOutput = testCli("person", "query", "--skip=1", "--limit=2", "--criteria", "id NOT_EQUALS 3"); TestOutput testOutput = testCli("person", "query", "--skip=1", "--limit=2", "--criteria", "id NOT_EQUALS 3");
JSONObject queryResult = JsonUtils.toJSONObject(testOutput.getOutput()); JSONObject queryResult = JsonUtils.toJSONObject(testOutput.getOutput());
assertNotNull(queryResult); assertNotNull(queryResult);
JSONArray records = queryResult.getJSONArray("records"); JSONArray records = queryResult.getJSONArray("records");
@ -246,7 +255,8 @@ class QPicoCliImplementationTest
{ {
TestOutput testOutput = testCli("person", "insert", TestOutput testOutput = testCli("person", "insert",
"--field-firstName=Lucy", "--field-firstName=Lucy",
"--field-lastName=Lu"); "--field-lastName=Lu",
"--field-email=lucy@kingsrook.com");
JSONObject insertResult = JsonUtils.toJSONObject(testOutput.getOutput()); JSONObject insertResult = JsonUtils.toJSONObject(testOutput.getOutput());
assertNotNull(insertResult); assertNotNull(insertResult);
assertEquals(1, insertResult.getJSONArray("records").length()); assertEquals(1, insertResult.getJSONArray("records").length());
@ -263,20 +273,21 @@ class QPicoCliImplementationTest
public void test_tableInsertJsonObjectArgumentWithMapping() public void test_tableInsertJsonObjectArgumentWithMapping()
{ {
String mapping = """ String mapping = """
--mapping={"firstName":"first","lastName":"ln"} --mapping={"firstName":"first","lastName":"ln","email":"email"}
"""; """;
String jsonBody = """ String jsonBody = """
--jsonBody={"first":"Chester","ln":"Cheese"} --jsonBody={"first":"Chester","ln":"Cheese","email":"chester@kingsrook.com"}
"""; """;
TestOutput testOutput = testCli("person", "insert", mapping, jsonBody); TestOutput testOutput = testCli("person", "insert", mapping, jsonBody);
JSONObject insertResult = JsonUtils.toJSONObject(testOutput.getOutput()); JSONObject insertResult = JsonUtils.toJSONObject(testOutput.getOutput());
assertNotNull(insertResult); assertNotNull(insertResult);
assertEquals(1, insertResult.getJSONArray("records").length()); assertEquals(1, insertResult.getJSONArray("records").length());
assertEquals(6, insertResult.getJSONArray("records").getJSONObject(0).getJSONObject("values").getInt("id")); assertEquals(6, insertResult.getJSONArray("records").getJSONObject(0).getJSONObject("values").getInt("id"));
assertEquals("Chester", insertResult.getJSONArray("records").getJSONObject(0).getJSONObject("values").getString("firstName")); assertEquals("Chester", insertResult.getJSONArray("records").getJSONObject(0).getJSONObject("values").getString("firstName"));
assertEquals("Cheese", insertResult.getJSONArray("records").getJSONObject(0).getJSONObject("values").getString("lastName")); assertEquals("Cheese", insertResult.getJSONArray("records").getJSONObject(0).getJSONObject("values").getString("lastName"));
assertEquals("chester@kingsrook.com", insertResult.getJSONArray("records").getJSONObject(0).getJSONObject("values").getString("email"));
} }
@ -289,18 +300,21 @@ class QPicoCliImplementationTest
public void test_tableInsertJsonArrayFileWithMapping() throws IOException public void test_tableInsertJsonArrayFileWithMapping() throws IOException
{ {
String mapping = """ String mapping = """
--mapping={"firstName":"first","lastName":"ln"} --mapping={"firstName":"first","lastName":"ln","email":"email"}
"""; """;
String jsonContents = """ String jsonContents = """
[{"first":"Charlie","ln":"Bear"},{"first":"Coco","ln":"Bean"}] [
{"first":"Charlie","ln":"Bear","email":"charlie-bear@kingsrook.com"},
{"first":"Coco","ln":"Bean","email":"coco-bean@kingsrook.com"}
]
"""; """;
File file = new File("/tmp/" + UUID.randomUUID() + ".json"); File file = new File("/tmp/" + UUID.randomUUID() + ".json");
file.deleteOnExit(); file.deleteOnExit();
FileUtils.writeStringToFile(file, jsonContents); FileUtils.writeStringToFile(file, jsonContents);
TestOutput testOutput = testCli("person", "insert", mapping, "--jsonFile=" + file.getAbsolutePath()); TestOutput testOutput = testCli("person", "insert", mapping, "--jsonFile=" + file.getAbsolutePath());
JSONObject insertResult = JsonUtils.toJSONObject(testOutput.getOutput()); JSONObject insertResult = JsonUtils.toJSONObject(testOutput.getOutput());
assertNotNull(insertResult); assertNotNull(insertResult);
JSONArray records = insertResult.getJSONArray("records"); JSONArray records = insertResult.getJSONArray("records");
@ -309,8 +323,10 @@ class QPicoCliImplementationTest
assertEquals(7, insertResult.getJSONArray("records").getJSONObject(1).getJSONObject("values").getInt("id")); assertEquals(7, insertResult.getJSONArray("records").getJSONObject(1).getJSONObject("values").getInt("id"));
assertEquals("Charlie", records.getJSONObject(0).getJSONObject("values").getString("firstName")); assertEquals("Charlie", records.getJSONObject(0).getJSONObject("values").getString("firstName"));
assertEquals("Bear", records.getJSONObject(0).getJSONObject("values").getString("lastName")); assertEquals("Bear", records.getJSONObject(0).getJSONObject("values").getString("lastName"));
assertEquals("charlie-bear@kingsrook.com", records.getJSONObject(0).getJSONObject("values").getString("email"));
assertEquals("Coco", records.getJSONObject(1).getJSONObject("values").getString("firstName")); assertEquals("Coco", records.getJSONObject(1).getJSONObject("values").getString("firstName"));
assertEquals("Bean", records.getJSONObject(1).getJSONObject("values").getString("lastName")); assertEquals("Bean", records.getJSONObject(1).getJSONObject("values").getString("lastName"));
assertEquals("coco-bean@kingsrook.com", records.getJSONObject(1).getJSONObject("values").getString("email"));
} }
@ -323,12 +339,12 @@ class QPicoCliImplementationTest
public void test_tableInsertCsvFileWithIndexMapping() throws IOException public void test_tableInsertCsvFileWithIndexMapping() throws IOException
{ {
String mapping = """ String mapping = """
--mapping={"firstName":1,"lastName":3} --mapping={"firstName":1,"lastName":3,"email":5}
"""; """;
String csvContents = """ String csvContents = """
"Louis","P","Willikers",1024, "Louis","P","Willikers",1024,"louis@kingsrook.com",
"Nestle","G","Crunch",1701, "Nestle","G","Crunch",1701,"nestle@kingsrook.com",
"""; """;
@ -336,7 +352,7 @@ class QPicoCliImplementationTest
file.deleteOnExit(); file.deleteOnExit();
FileUtils.writeStringToFile(file, csvContents); FileUtils.writeStringToFile(file, csvContents);
TestOutput testOutput = testCli("person", "insert", mapping, "--csvFile=" + file.getAbsolutePath()); TestOutput testOutput = testCli("person", "insert", mapping, "--csvFile=" + file.getAbsolutePath());
JSONObject insertResult = JsonUtils.toJSONObject(testOutput.getOutput()); JSONObject insertResult = JsonUtils.toJSONObject(testOutput.getOutput());
assertNotNull(insertResult); assertNotNull(insertResult);
JSONArray records = insertResult.getJSONArray("records"); JSONArray records = insertResult.getJSONArray("records");
@ -408,7 +424,7 @@ class QPicoCliImplementationTest
@Test @Test
public void test_tableDelete() throws Exception public void test_tableDelete() throws Exception
{ {
TestOutput testOutput = testCli("person", "delete", "--primaryKey", "2,4"); TestOutput testOutput = testCli("person", "delete", "--primaryKey", "2,4");
JSONObject deleteResult = JsonUtils.toJSONObject(testOutput.getOutput()); JSONObject deleteResult = JsonUtils.toJSONObject(testOutput.getOutput());
assertNotNull(deleteResult); assertNotNull(deleteResult);
JSONArray records = deleteResult.getJSONArray("records"); JSONArray records = deleteResult.getJSONArray("records");
@ -452,8 +468,8 @@ class QPicoCliImplementationTest
@Test @Test
public void test_tableProcessUnknownName() throws Exception public void test_tableProcessUnknownName() throws Exception
{ {
String badProcessName = "not-a-process"; String badProcessName = "not-a-process";
TestOutput testOutput = testCli("person", "process", badProcessName); TestOutput testOutput = testCli("person", "process", badProcessName);
assertTestErrorContains(testOutput, "Unmatched argument at index 2: '" + badProcessName + "'"); assertTestErrorContains(testOutput, "Unmatched argument at index 2: '" + badProcessName + "'");
assertTestErrorContains(testOutput, "Usage: " + CLI_NAME + " person process \\[COMMAND\\]"); assertTestErrorContains(testOutput, "Usage: " + CLI_NAME + " person process \\[COMMAND\\]");
} }
@ -465,12 +481,25 @@ class QPicoCliImplementationTest
** **
*******************************************************************************/ *******************************************************************************/
@Test @Test
@Disabled // not yet done. public void test_tableProcessGreetUsingCallbackForFields() throws Exception
public void test_tableProcessGreet() throws Exception
{ {
setStandardInputLines("Hi", "How are you?");
TestOutput testOutput = testCli("person", "process", "greet"); TestOutput testOutput = testCli("person", "process", "greet");
assertTestOutputContains(testOutput, "Please supply a value for the field.*Greeting Prefix");
assertTestOutputContains(testOutput, "Hi X How are you?");
}
fail("Assertion not written...");
/*******************************************************************************
** test running a process on a table
**
*******************************************************************************/
@Test
public void test_tableProcessGreetUsingOptionsForFields() throws Exception
{
TestOutput testOutput = testCli("person", "process", "greet", "--field-greetingPrefix=Hello", "--field-greetingSuffix=There");
assertTestOutputDoesNotContain(testOutput, "Please supply a value for the field");
assertTestOutputContains(testOutput, "Hello X There");
} }
@ -536,7 +565,7 @@ class QPicoCliImplementationTest
QPicoCliImplementation qPicoCliImplementation = new QPicoCliImplementation(qInstance); QPicoCliImplementation qPicoCliImplementation = new QPicoCliImplementation(qInstance);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ByteArrayOutputStream errorStream = new ByteArrayOutputStream(); ByteArrayOutputStream errorStream = new ByteArrayOutputStream();
if(VERBOSE) if(VERBOSE)
{ {
@ -546,7 +575,7 @@ class QPicoCliImplementationTest
qPicoCliImplementation.runCli(CLI_NAME, args, new PrintStream(outputStream, true), new PrintStream(errorStream, true)); qPicoCliImplementation.runCli(CLI_NAME, args, new PrintStream(outputStream, true), new PrintStream(errorStream, true));
String output = outputStream.toString(StandardCharsets.UTF_8); String output = outputStream.toString(StandardCharsets.UTF_8);
String error = errorStream.toString(StandardCharsets.UTF_8); String error = errorStream.toString(StandardCharsets.UTF_8);
if(VERBOSE) if(VERBOSE)
{ {
@ -560,14 +589,34 @@ class QPicoCliImplementationTest
/*******************************************************************************
**
*******************************************************************************/
private void setStandardInputLines(String... lines)
{
StringBuilder stringBuilder = new StringBuilder();
for(String line : lines)
{
stringBuilder.append(line);
if(!line.endsWith("\n"))
{
stringBuilder.append("\n");
}
}
ByteArrayInputStream stdin = new ByteArrayInputStream(stringBuilder.toString().getBytes(Charset.defaultCharset()));
System.setIn(stdin);
}
/******************************************************************************* /*******************************************************************************
** **
*******************************************************************************/ *******************************************************************************/
private static class TestOutput private static class TestOutput
{ {
private String output; private String output;
private String[] outputLines; private String[] outputLines;
private String error; private String error;
private String[] errorLines; private String[] errorLines;

View File

@ -25,8 +25,8 @@ package com.kingsrook.qqq.frontend.picocli;
import java.io.InputStream; import java.io.InputStream;
import java.sql.Connection; import java.sql.Connection;
import java.util.List; import java.util.List;
import com.kingsrook.qqq.backend.core.interfaces.mock.MockFunctionBody;
import com.kingsrook.qqq.backend.core.model.metadata.QAuthenticationMetaData; import com.kingsrook.qqq.backend.core.model.metadata.QAuthenticationMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.QCodeReference; import com.kingsrook.qqq.backend.core.model.metadata.QCodeReference;
import com.kingsrook.qqq.backend.core.model.metadata.QCodeType; import com.kingsrook.qqq.backend.core.model.metadata.QCodeType;
import com.kingsrook.qqq.backend.core.model.metadata.QCodeUsage; import com.kingsrook.qqq.backend.core.model.metadata.QCodeUsage;
@ -41,7 +41,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.processes.QOutputView;
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.processes.QRecordListView; import com.kingsrook.qqq.backend.core.model.metadata.processes.QRecordListView;
import com.kingsrook.qqq.backend.module.rdbms.RDBMSBackendMetaData; import com.kingsrook.qqq.backend.module.rdbms.model.metadata.RDBMSBackendMetaData;
import com.kingsrook.qqq.backend.module.rdbms.jdbc.ConnectionManager; import com.kingsrook.qqq.backend.module.rdbms.jdbc.ConnectionManager;
import com.kingsrook.qqq.backend.module.rdbms.jdbc.QueryManager; import com.kingsrook.qqq.backend.module.rdbms.jdbc.QueryManager;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
@ -62,11 +62,12 @@ public class TestUtils
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static void primeTestDatabase() throws Exception public static void primeTestDatabase() throws Exception
{ {
ConnectionManager connectionManager = new ConnectionManager(); ConnectionManager connectionManager = new ConnectionManager();
Connection connection = connectionManager.getConnection(new RDBMSBackendMetaData(TestUtils.defineBackend())); Connection connection = connectionManager.getConnection(TestUtils.defineBackend());
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);
lines = lines.stream().filter(line -> !line.startsWith("-- ")).toList();
String joinedSQL = String.join("\n", lines); String joinedSQL = String.join("\n", lines);
for(String sql : joinedSQL.split(";")) for(String sql : joinedSQL.split(";"))
{ {
@ -83,7 +84,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(new RDBMSBackendMetaData(defineBackend())); Connection connection = connectionManager.getConnection(defineBackend());
QueryManager.executeStatement(connection, sql, resultSetProcessor); QueryManager.executeStatement(connection, sql, resultSetProcessor);
} }
@ -122,16 +123,15 @@ public class TestUtils
** Define the h2 rdbms backend ** Define the h2 rdbms backend
** **
*******************************************************************************/ *******************************************************************************/
public static QBackendMetaData defineBackend() public static RDBMSBackendMetaData defineBackend()
{ {
return new QBackendMetaData() return (new RDBMSBackendMetaData()
.withName("default") .withVendor("h2")
.withType("rdbms") .withHostName("mem")
.withValue("vendor", "h2") .withDatabaseName("test_database")
.withValue("hostName", "mem") .withUsername("sa")
.withValue("databaseName", "test_database") .withPassword("")
.withValue("username", "sa") .withName("default"));
.withValue("password", "");
} }
@ -169,7 +169,7 @@ public class TestUtils
.addFunction(new QFunctionMetaData() .addFunction(new QFunctionMetaData()
.withName("prepare") .withName("prepare")
.withCode(new QCodeReference() .withCode(new QCodeReference()
.withName("com.kingsrook.qqq.backend.core.interfaces.mock.MockFunctionBody") .withName(MockFunctionBody.class.getName())
.withCodeType(QCodeType.JAVA) .withCodeType(QCodeType.JAVA)
.withCodeUsage(QCodeUsage.FUNCTION)) // todo - needed, or implied in this context? .withCodeUsage(QCodeUsage.FUNCTION)) // todo - needed, or implied in this context?
.withInputData(new QFunctionInputMetaData() .withInputData(new QFunctionInputMetaData()

View File

@ -1,28 +1,28 @@
/* --
* QQQ - Low-code Application Framework for Engineers. -- QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2022. Kingsrook, LLC -- Copyright (C) 2021-2022. Kingsrook, LLC
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States -- 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
* contact@kingsrook.com -- contact@kingsrook.com
* https://github.com/Kingsrook/ -- https://github.com/Kingsrook/
* --
* This program is free software: you can redistribute it and/or modify -- This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as -- it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the -- published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version. -- License, or (at your option) any later version.
* --
* This program is distributed in the hope that it will be useful, -- This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of -- but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details. -- GNU Affero General Public License for more details.
* --
* You should have received a copy of the GNU Affero General Public License -- 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/>. -- along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ --
DROP TABLE IF EXISTS person; DROP TABLE IF EXISTS person;
CREATE TABLE person CREATE TABLE person
( (
id SERIAL, id INT AUTO_INCREMENT,
create_date TIMESTAMP DEFAULT now(), create_date TIMESTAMP DEFAULT now(),
modify_date TIMESTAMP DEFAULT now(), modify_date TIMESTAMP DEFAULT now(),