mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-18 13:10:44 +00:00
QQQ-7 first version of actual execution of processes
This commit is contained in:
@ -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>
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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);
|
||||||
|
@ -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 runTableProcess(subCommandLine, null, 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":
|
||||||
@ -322,7 +339,7 @@ public class QPicoCliImplementation
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
String subCommandName = subParseResult.subcommand().commandSpec().name();
|
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 runTableProcessLevelCommand(subCommandLine, tableName, subParseResult.subcommand());
|
||||||
}
|
}
|
||||||
@ -335,11 +352,44 @@ public class QPicoCliImplementation
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
private int runTableProcessLevelCommand(CommandLine subCommandLine, String tableName, ParseResult processParseResult)
|
private int runTableProcessLevelCommand(CommandLine subCommandLine, String tableName, 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: " + e); // todo better!
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -379,7 +429,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 +490,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 +547,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 +596,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));
|
||||||
|
|
||||||
|
@ -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"));
|
||||||
|
// todo - need label assertEquals("Person", 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");
|
||||||
@ -271,7 +280,7 @@ class QPicoCliImplementationTest
|
|||||||
--jsonBody={"first":"Chester","ln":"Cheese","email":"chester@kingsrook.com"}
|
--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());
|
||||||
@ -305,7 +314,7 @@ class QPicoCliImplementationTest
|
|||||||
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");
|
||||||
@ -343,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");
|
||||||
@ -415,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");
|
||||||
@ -459,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\\]");
|
||||||
}
|
}
|
||||||
@ -472,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");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -543,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)
|
||||||
{
|
{
|
||||||
@ -553,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)
|
||||||
{
|
{
|
||||||
@ -567,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;
|
||||||
|
|
||||||
|
|
||||||
|
@ -26,7 +26,6 @@ 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.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 +40,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,9 +61,9 @@ 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();
|
lines = lines.stream().filter(line -> !line.startsWith("-- ")).toList();
|
||||||
@ -84,7 +83,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,16 +122,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", "");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user