diff --git a/checkstyle.xml b/checkstyle.xml index 76f872ed..f5e7412d 100644 --- a/checkstyle.xml +++ b/checkstyle.xml @@ -181,8 +181,8 @@ --> - @@ -47,31 +47,31 @@ com.kingsrook.qqq qqq-backend-core - 0.1.0-SNAPSHOT + 0.2.0-SNAPSHOT compile com.kingsrook.qqq qqq-backend-module-rdbms - 0.1.0-SNAPSHOT + 0.2.0-SNAPSHOT compile com.kingsrook.qqq qqq-backend-module-filesystem - 0.1.0-SNAPSHOT + 0.2.0-SNAPSHOT compile com.kingsrook.qqq qqq-middleware-javalin - 0.1.0-SNAPSHOT + 0.2.0-SNAPSHOT compile com.kingsrook.qqq qqq-middleware-picocli - 0.1.0-SNAPSHOT + 0.2.0-SNAPSHOT compile diff --git a/src/main/java/com/kingsrook/sampleapp/SampleMetaDataProvider.java b/src/main/java/com/kingsrook/sampleapp/SampleMetaDataProvider.java index eeb94553..ff3e4fc8 100644 --- a/src/main/java/com/kingsrook/sampleapp/SampleMetaDataProvider.java +++ b/src/main/java/com/kingsrook/sampleapp/SampleMetaDataProvider.java @@ -24,7 +24,11 @@ package com.kingsrook.sampleapp; import java.util.List; import com.kingsrook.qqq.backend.core.exceptions.QException; +import com.kingsrook.qqq.backend.core.exceptions.QValueException; +import com.kingsrook.qqq.backend.core.interfaces.BackendStep; import com.kingsrook.qqq.backend.core.interfaces.mock.MockBackendStep; +import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepRequest; +import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepResult; 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; @@ -35,10 +39,12 @@ import com.kingsrook.qqq.backend.core.model.metadata.QFieldType; 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.processes.QBackendStepMetaData; +import com.kingsrook.qqq.backend.core.model.metadata.processes.QFrontendStepMetaData; import com.kingsrook.qqq.backend.core.model.metadata.processes.QFunctionInputMetaData; import com.kingsrook.qqq.backend.core.model.metadata.processes.QFunctionOutputMetaData; import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData; import com.kingsrook.qqq.backend.core.model.metadata.processes.QRecordListMetaData; +import com.kingsrook.qqq.backend.core.processes.implementations.LoadInitialRecordsStep; import com.kingsrook.qqq.backend.module.filesystem.base.model.metadata.Cardinality; import com.kingsrook.qqq.backend.module.filesystem.base.model.metadata.RecordFormat; import com.kingsrook.qqq.backend.module.filesystem.local.model.metadata.FilesystemBackendMetaData; @@ -51,9 +57,20 @@ import com.kingsrook.qqq.backend.module.rdbms.model.metadata.RDBMSBackendMetaDat *******************************************************************************/ public class SampleMetaDataProvider { - public static final String MYSQL_BACKEND_NAME = "mysql"; + public static final String MYSQL_BACKEND_NAME = "mysql"; public static final String FILESYSTEM_BACKEND_NAME = "filesystem"; - public static final String PROCESS_NAME_GREET = "greet"; + + public static final String PROCESS_NAME_GREET = "greet"; + public static final String PROCESS_NAME_GREET_INTERACTIVE = "greetInteractive"; + public static final String PROCESS_NAME_SIMPLE_SLEEP = "simpleSleep"; + public static final String PROCESS_NAME_SIMPLE_THROW = "simpleThrow"; + public static final String PROCESS_NAME_SLEEP_INTERACTIVE = "sleepInteractive"; + + public static final String STEP_NAME_SLEEPER = "sleeper"; + public static final String STEP_NAME_THROWER = "thrower"; + + public static final String SCREEN_0 = "screen0"; + public static final String SCREEN_1 = "screen1"; @@ -64,13 +81,17 @@ public class SampleMetaDataProvider { QInstance qInstance = new QInstance(); - qInstance.setAuthentication(SampleMetaDataProvider.defineAuthentication()); - qInstance.addBackend(SampleMetaDataProvider.defineMysqlBackend()); - qInstance.addBackend(SampleMetaDataProvider.defineFilesystemBackend()); - qInstance.addTable(SampleMetaDataProvider.defineTableCarrier()); - qInstance.addTable(SampleMetaDataProvider.defineTablePerson()); - qInstance.addTable(SampleMetaDataProvider.defineTableCityFile()); - qInstance.addProcess(SampleMetaDataProvider.defineProcessGreetPeople()); + qInstance.setAuthentication(defineAuthentication()); + qInstance.addBackend(defineMysqlBackend()); + qInstance.addBackend(defineFilesystemBackend()); + qInstance.addTable(defineTableCarrier()); + qInstance.addTable(defineTablePerson()); + qInstance.addTable(defineTableCityFile()); + qInstance.addProcess(defineProcessGreetPeople()); + qInstance.addProcess(defineProcessGreetPeopleInteractive()); + qInstance.addProcess(defineProcessSimpleSleep()); + qInstance.addProcess(defineProcessScreenThenSleep()); + qInstance.addProcess(defineProcessSimpleThrow()); return (qInstance); } @@ -172,6 +193,7 @@ public class SampleMetaDataProvider return new QTableMetaData() .withName("city") .withLabel("Cities") + .withIsHidden(true) .withBackendName(FILESYSTEM_BACKEND_NAME) .withPrimaryKeyField("id") .withField(new QFieldMetaData("id", QFieldType.INTEGER)) @@ -195,12 +217,13 @@ public class SampleMetaDataProvider .withName(PROCESS_NAME_GREET) .withLabel("Greet People") .withTableName("person") + .withIsHidden(true) .addStep(new QBackendStepMetaData() .withName("prepare") .withCode(new QCodeReference() .withName(MockBackendStep.class.getName()) .withCodeType(QCodeType.JAVA) - .withCodeUsage(QCodeUsage.FUNCTION)) // todo - needed, or implied in this context? + .withCodeUsage(QCodeUsage.BACKEND_STEP)) // todo - needed, or implied in this context? .withInputData(new QFunctionInputMetaData() .withRecordListMetaData(new QRecordListMetaData().withTableName("person")) .withFieldList(List.of( @@ -216,4 +239,222 @@ public class SampleMetaDataProvider ); } + + + /******************************************************************************* + ** Define an interactive version of the 'greet people' process + *******************************************************************************/ + private static QProcessMetaData defineProcessGreetPeopleInteractive() + { + return new QProcessMetaData() + .withName(PROCESS_NAME_GREET_INTERACTIVE) + .withTableName("person") + + .addStep(LoadInitialRecordsStep.defineMetaData("person")) + + .addStep(new QFrontendStepMetaData() + .withName("setup") + .withFormField(new QFieldMetaData("greetingPrefix", QFieldType.STRING)) + .withFormField(new QFieldMetaData("greetingSuffix", QFieldType.STRING)) + ) + + .addStep(new QBackendStepMetaData() + .withName("doWork") + .withCode(new QCodeReference() + .withName(MockBackendStep.class.getName()) + .withCodeType(QCodeType.JAVA) + .withCodeUsage(QCodeUsage.BACKEND_STEP)) // todo - needed, or implied in this context? + .withInputData(new QFunctionInputMetaData() + .withRecordListMetaData(new QRecordListMetaData().withTableName("person")) + .withFieldList(List.of( + new QFieldMetaData("greetingPrefix", QFieldType.STRING), + new QFieldMetaData("greetingSuffix", QFieldType.STRING) + ))) + .withOutputMetaData(new QFunctionOutputMetaData() + .withRecordListMetaData(new QRecordListMetaData() + .withTableName("person") + .addField(new QFieldMetaData("fullGreeting", QFieldType.STRING)) + ) + .withFieldList(List.of(new QFieldMetaData("outputMessage", QFieldType.STRING)))) + ) + + .addStep(new QFrontendStepMetaData() + .withName("results") + .withViewField(new QFieldMetaData("noOfPeopleGreeted", QFieldType.INTEGER)) + .withViewField(new QFieldMetaData("outputMessage", QFieldType.STRING)) + .withRecordListField(new QFieldMetaData("id", QFieldType.INTEGER)) + .withRecordListField(new QFieldMetaData("firstName", QFieldType.STRING)) + // .withRecordListField(new QFieldMetaData(MockBackendStep.FIELD_MOCK_VALUE, QFieldType.STRING)) + .withRecordListField(new QFieldMetaData("greetingMessage", QFieldType.STRING)) + ); + } + + + + /******************************************************************************* + ** Define a process with just one step that sleeps + *******************************************************************************/ + private static QProcessMetaData defineProcessSimpleSleep() + { + return new QProcessMetaData() + .withName(PROCESS_NAME_SIMPLE_SLEEP) + .withIsHidden(true) + .addStep(SleeperStep.getMetaData()); + } + + + + /******************************************************************************* + ** Define a process with a screen, then a sleep step + *******************************************************************************/ + private static QProcessMetaData defineProcessScreenThenSleep() + { + return new QProcessMetaData() + .withName(PROCESS_NAME_SLEEP_INTERACTIVE) + .addStep(new QFrontendStepMetaData() + .withName(SCREEN_0) + .withFormField(new QFieldMetaData("outputMessage", QFieldType.STRING))) + .addStep(SleeperStep.getMetaData()) + .addStep(new QFrontendStepMetaData() + .withName(SCREEN_1) + .withFormField(new QFieldMetaData("outputMessage", QFieldType.STRING))); + } + + + + /******************************************************************************* + ** Define a process with just one step that sleeps and then throws + *******************************************************************************/ + private static QProcessMetaData defineProcessSimpleThrow() + { + return new QProcessMetaData() + .withName(PROCESS_NAME_SIMPLE_THROW) + .addStep(ThrowerStep.getMetaData()); + } + + + + /******************************************************************************* + ** Testing backend step - just sleeps however long you ask it to (or, throws if + ** you don't provide a number of seconds to sleep). + *******************************************************************************/ + public static class SleeperStep implements BackendStep + { + public static final String FIELD_SLEEP_MILLIS = "sleepMillis"; + + + + /******************************************************************************* + ** Execute the backend step - using the request as input, and the result as output. + ** + ******************************************************************************/ + @Override + public void run(RunBackendStepRequest runBackendStepRequest, RunBackendStepResult runBackendStepResult) throws QException + { + try + { + Thread.sleep(runBackendStepRequest.getValueInteger(FIELD_SLEEP_MILLIS)); + } + catch(InterruptedException e) + { + throw (new QException("Interrupted while sleeping...")); + } + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + public static QBackendStepMetaData getMetaData() + { + return (new QBackendStepMetaData() + .withName(STEP_NAME_SLEEPER) + .withCode(new QCodeReference() + .withName(SleeperStep.class.getName()) + .withCodeType(QCodeType.JAVA) + .withCodeUsage(QCodeUsage.BACKEND_STEP)) + .withInputData(new QFunctionInputMetaData() + .addField(new QFieldMetaData(SleeperStep.FIELD_SLEEP_MILLIS, QFieldType.INTEGER)))); + } + } + + + + /******************************************************************************* + ** Testing backend step - just throws an exception after however long you ask it to sleep. + *******************************************************************************/ + public static class ThrowerStep implements BackendStep + { + public static final String FIELD_SLEEP_MILLIS = "sleepMillis"; + + + + /******************************************************************************* + ** Execute the backend step - using the request as input, and the result as output. + ** + ******************************************************************************/ + @Override + public void run(RunBackendStepRequest runBackendStepRequest, RunBackendStepResult runBackendStepResult) throws QException + { + int sleepMillis; + try + { + sleepMillis = runBackendStepRequest.getValueInteger(FIELD_SLEEP_MILLIS); + } + catch(QValueException qve) + { + sleepMillis = 50; + } + + try + { + Thread.sleep(sleepMillis); + } + catch(InterruptedException e) + { + throw (new QException("Interrupted while sleeping...")); + } + + throw (new QException("I always throw.")); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + public static QBackendStepMetaData getMetaData() + { + return (new QBackendStepMetaData() + .withName(STEP_NAME_THROWER) + .withCode(new QCodeReference() + .withName(ThrowerStep.class.getName()) + .withCodeType(QCodeType.JAVA) + .withCodeUsage(QCodeUsage.BACKEND_STEP)) + .withInputData(new QFunctionInputMetaData() + .addField(new QFieldMetaData(ThrowerStep.FIELD_SLEEP_MILLIS, QFieldType.INTEGER)))); + } + } + + + + public static class NoopBackendStep implements BackendStep + { + public NoopBackendStep() + { + + } + + + + @Override + public void run(RunBackendStepRequest runBackendStepRequest, RunBackendStepResult runBackendStepResult) throws QException + { + ////////// + // noop // + ////////// + } + } + } diff --git a/src/test/java/com/kingsrook/sampleapp/SampleMetaDataProviderTest.java b/src/test/java/com/kingsrook/sampleapp/SampleMetaDataProviderTest.java index 097b9764..dd2c13b6 100644 --- a/src/test/java/com/kingsrook/sampleapp/SampleMetaDataProviderTest.java +++ b/src/test/java/com/kingsrook/sampleapp/SampleMetaDataProviderTest.java @@ -40,7 +40,6 @@ import org.apache.commons.io.FileUtils; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -118,7 +117,6 @@ class SampleMetaDataProviderTest RunProcessResult result = new RunProcessAction().execute(request); assertNotNull(result); - assertNull(result.getError()); assertTrue(result.getRecords().stream().allMatch(r -> r.getValues().containsKey("id")), "records should have an id, set by the process"); }