diff --git a/qqq-middleware-javalin/src/main/java/com/kingsrook/qqq/middleware/javalin/specs/v1/MetaDataSpecV1.java b/qqq-middleware-javalin/src/main/java/com/kingsrook/qqq/middleware/javalin/specs/v1/MetaDataSpecV1.java index 6a4e1645..4e092970 100644 --- a/qqq-middleware-javalin/src/main/java/com/kingsrook/qqq/middleware/javalin/specs/v1/MetaDataSpecV1.java +++ b/qqq-middleware-javalin/src/main/java/com/kingsrook/qqq/middleware/javalin/specs/v1/MetaDataSpecV1.java @@ -22,43 +22,21 @@ package com.kingsrook.qqq.middleware.javalin.specs.v1; -import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.TreeSet; import com.kingsrook.qqq.backend.core.actions.metadata.MetaDataAction; import com.kingsrook.qqq.backend.core.context.CapturedContext; import com.kingsrook.qqq.backend.core.context.QContext; -import com.kingsrook.qqq.backend.core.exceptions.QInstanceValidationException; -import com.kingsrook.qqq.backend.core.instances.QInstanceEnricher; -import com.kingsrook.qqq.backend.core.instances.QInstanceValidator; -import com.kingsrook.qqq.backend.core.instances.enrichment.plugins.QInstanceEnricherPluginInterface; -import com.kingsrook.qqq.backend.core.instances.validation.plugins.QInstanceValidatorPluginInterface; import com.kingsrook.qqq.backend.core.model.actions.metadata.MetaDataOutput; -import com.kingsrook.qqq.backend.core.model.metadata.QAuthenticationType; -import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData; -import com.kingsrook.qqq.backend.core.model.metadata.QInstance; -import com.kingsrook.qqq.backend.core.model.metadata.authentication.QAuthenticationMetaData; -import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData; -import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType; -import com.kingsrook.qqq.backend.core.model.metadata.layout.QAppMetaData; -import com.kingsrook.qqq.backend.core.model.metadata.layout.QIcon; -import com.kingsrook.qqq.backend.core.model.metadata.permissions.PermissionLevel; -import com.kingsrook.qqq.backend.core.model.metadata.permissions.QPermissionRules; -import com.kingsrook.qqq.backend.core.model.metadata.processes.QFrontendStepMetaData; -import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData; -import com.kingsrook.qqq.backend.core.model.metadata.tables.Capability; -import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData; import com.kingsrook.qqq.backend.core.model.session.QSystemUserSession; -import com.kingsrook.qqq.backend.core.modules.backend.implementations.memory.MemoryBackendModule; -import com.kingsrook.qqq.backend.core.utils.ListingHash; import com.kingsrook.qqq.middleware.javalin.executors.MetaDataExecutor; import com.kingsrook.qqq.middleware.javalin.executors.io.MetaDataInput; import com.kingsrook.qqq.middleware.javalin.specs.AbstractEndpointSpec; import com.kingsrook.qqq.middleware.javalin.specs.BasicOperation; import com.kingsrook.qqq.middleware.javalin.specs.BasicResponse; import com.kingsrook.qqq.middleware.javalin.specs.v1.responses.MetaDataResponseV1; +import com.kingsrook.qqq.middleware.javalin.specs.v1.utils.MetaDataSpecUtils; import com.kingsrook.qqq.middleware.javalin.specs.v1.utils.TagsV1; import com.kingsrook.qqq.openapi.model.Example; import com.kingsrook.qqq.openapi.model.HttpMethod; @@ -74,14 +52,6 @@ import io.javalin.http.Context; *******************************************************************************/ public class MetaDataSpecV1 extends AbstractEndpointSpec { - private static QInstance exampleInstance; - - static - { - exampleInstance = defineExampleInstance(); - validateExampleInstance(exampleInstance); - } - /*************************************************************************** ** ***************************************************************************/ @@ -203,9 +173,9 @@ public class MetaDataSpecV1 extends AbstractEndpointSpec + QContext.withTemporaryContext(new CapturedContext(MetaDataSpecUtils.getExampleInstance(), null), () -> { - QContext.withTemporaryContext(new CapturedContext(exampleInstance, new QSystemUserSession()), () -> + QContext.withTemporaryContext(new CapturedContext(MetaDataSpecUtils.getExampleInstance(), new QSystemUserSession()), () -> { try { @@ -231,92 +201,4 @@ public class MetaDataSpecV1 extends AbstractEndpointSpec capabilities = new TreeSet<>(Comparator.comparing((Capability c) -> c.name())); - capabilities.addAll(Capability.allReadCapabilities()); - capabilities.addAll(Capability.allWriteCapabilities()); - - QTableMetaData exampleTable = new QTableMetaData() - .withName("person") - .withLabel("Person") - .withBackendName("example") - .withPrimaryKeyField("id") - .withIsHidden(false) - .withIcon(new QIcon().withName("person_outline")) - .withEnabledCapabilities(capabilities) - .withPermissionRules(new QPermissionRules().withLevel(PermissionLevel.NOT_PROTECTED)) - .withField(new QFieldMetaData("id", QFieldType.INTEGER)); - exampleInstance.addTable(exampleTable); - - QProcessMetaData exampleProcess = new QProcessMetaData() - .withName("samplePersonProcess") - .withLabel("Sample Person Process") - .withTableName("person") - .withIsHidden(false) - .withIcon(new QIcon().withName("person_add")) - .withPermissionRules(new QPermissionRules().withLevel(PermissionLevel.NOT_PROTECTED)) - .withStep(new QFrontendStepMetaData().withName("example")); - exampleInstance.addProcess(exampleProcess); - - QAppMetaData childApp = new QAppMetaData() - .withName("childApp") - .withLabel("Child App") - .withIcon(new QIcon().withName("child_friendly")) - .withPermissionRules(new QPermissionRules().withLevel(PermissionLevel.NOT_PROTECTED)) - .withChild(exampleProcess); - exampleInstance.addApp(childApp); - - QAppMetaData exampleApp = new QAppMetaData() - .withName("homeApp") - .withLabel("Home App") - .withIcon(new QIcon().withName("home")) - .withPermissionRules(new QPermissionRules().withLevel(PermissionLevel.NOT_PROTECTED)) - .withChild(childApp) - .withChild(exampleTable); - exampleInstance.addApp(exampleApp); - return exampleInstance; - } - - - - /*************************************************************************** - ** - ***************************************************************************/ - private static void validateExampleInstance(QInstance exampleInstance) - { - ListingHash, QInstanceEnricherPluginInterface> enricherPlugins = QInstanceEnricher.getEnricherPlugins(); - QInstanceEnricher.removeAllEnricherPlugins(); - - ListingHash, QInstanceValidatorPluginInterface> validatorPlugins = QInstanceValidator.getValidatorPlugins(); - QInstanceValidator.removeAllValidatorPlugins(); - - try - { - new QInstanceValidator().validate(exampleInstance); - } - catch(QInstanceValidationException e) - { - System.err.println("Error validating example instance: " + e.getMessage()); - } - - enricherPlugins.values().forEach(l -> l.forEach(QInstanceEnricher::addEnricherPlugin)); - validatorPlugins.values().forEach(l -> l.forEach(QInstanceValidator::addValidatorPlugin)); - } } diff --git a/qqq-middleware-javalin/src/main/java/com/kingsrook/qqq/middleware/javalin/specs/v1/TableMetaDataSpecV1.java b/qqq-middleware-javalin/src/main/java/com/kingsrook/qqq/middleware/javalin/specs/v1/TableMetaDataSpecV1.java index 4a52c6ca..7bc0fff8 100644 --- a/qqq-middleware-javalin/src/main/java/com/kingsrook/qqq/middleware/javalin/specs/v1/TableMetaDataSpecV1.java +++ b/qqq-middleware-javalin/src/main/java/com/kingsrook/qqq/middleware/javalin/specs/v1/TableMetaDataSpecV1.java @@ -25,7 +25,12 @@ package com.kingsrook.qqq.middleware.javalin.specs.v1; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import com.kingsrook.qqq.backend.core.context.CapturedContext; +import com.kingsrook.qqq.backend.core.context.QContext; +import com.kingsrook.qqq.backend.core.model.actions.AbstractTableActionInput; +import com.kingsrook.qqq.backend.core.model.metadata.QInstance; import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendTableMetaData; +import com.kingsrook.qqq.backend.core.model.session.QSystemUserSession; import com.kingsrook.qqq.backend.core.utils.JsonUtils; import com.kingsrook.qqq.middleware.javalin.executors.TableMetaDataExecutor; import com.kingsrook.qqq.middleware.javalin.executors.io.TableMetaDataInput; @@ -33,6 +38,7 @@ import com.kingsrook.qqq.middleware.javalin.specs.AbstractEndpointSpec; import com.kingsrook.qqq.middleware.javalin.specs.BasicOperation; import com.kingsrook.qqq.middleware.javalin.specs.BasicResponse; import com.kingsrook.qqq.middleware.javalin.specs.v1.responses.TableMetaDataResponseV1; +import com.kingsrook.qqq.middleware.javalin.specs.v1.utils.MetaDataSpecUtils; import com.kingsrook.qqq.middleware.javalin.specs.v1.utils.TagsV1; import com.kingsrook.qqq.openapi.model.Example; import com.kingsrook.qqq.openapi.model.HttpMethod; @@ -116,11 +122,32 @@ public class TableMetaDataSpecV1 extends AbstractEndpointSpec examples = new LinkedHashMap<>(); - examples.put("TODO", new Example() - .withValue(new TableMetaDataResponseV1().withTableMetaData(frontendTableMetaData))); + + ////////////////////////////////////////////////////////////////////////////////////////////////////// + // double-wrap the context here, so the instance will exist when the system-user-session is created // + // to avoid warnings out of system-user-session about there not being an instance in context. // + ////////////////////////////////////////////////////////////////////////////////////////////////////// + QInstance exampleInstance = MetaDataSpecUtils.getExampleInstance(); + QContext.withTemporaryContext(new CapturedContext(exampleInstance, null), () -> + { + QContext.withTemporaryContext(new CapturedContext(exampleInstance, new QSystemUserSession()), () -> + { + String tableName = "person"; + AbstractTableActionInput actionInput = new com.kingsrook.qqq.backend.core.model.actions.metadata.TableMetaDataInput().withTableName(tableName); + QFrontendTableMetaData frontendTableMetaData = new QFrontendTableMetaData(actionInput, exampleInstance.getBackendForTable(tableName), exampleInstance.getTable(tableName), true, true); + + try + { + examples.put("Example", new Example() + .withValue(new TableMetaDataResponseV1().withTableMetaData(frontendTableMetaData))); + } + catch(Exception e) + { + examples.put("Example", new Example().withValue("Error building example: " + e.getMessage())); + } + }); + }); return new BasicResponse(""" The full table metadata""", diff --git a/qqq-middleware-javalin/src/main/java/com/kingsrook/qqq/middleware/javalin/specs/v1/utils/MetaDataSpecUtils.java b/qqq-middleware-javalin/src/main/java/com/kingsrook/qqq/middleware/javalin/specs/v1/utils/MetaDataSpecUtils.java new file mode 100644 index 00000000..27fcef71 --- /dev/null +++ b/qqq-middleware-javalin/src/main/java/com/kingsrook/qqq/middleware/javalin/specs/v1/utils/MetaDataSpecUtils.java @@ -0,0 +1,160 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2025. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.kingsrook.qqq.middleware.javalin.specs.v1.utils; + + +import java.util.Comparator; +import java.util.TreeSet; +import com.kingsrook.qqq.backend.core.exceptions.QInstanceValidationException; +import com.kingsrook.qqq.backend.core.instances.QInstanceEnricher; +import com.kingsrook.qqq.backend.core.instances.QInstanceValidator; +import com.kingsrook.qqq.backend.core.instances.enrichment.plugins.QInstanceEnricherPluginInterface; +import com.kingsrook.qqq.backend.core.instances.validation.plugins.QInstanceValidatorPluginInterface; +import com.kingsrook.qqq.backend.core.model.metadata.QAuthenticationType; +import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData; +import com.kingsrook.qqq.backend.core.model.metadata.QInstance; +import com.kingsrook.qqq.backend.core.model.metadata.authentication.QAuthenticationMetaData; +import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData; +import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType; +import com.kingsrook.qqq.backend.core.model.metadata.layout.QAppMetaData; +import com.kingsrook.qqq.backend.core.model.metadata.layout.QIcon; +import com.kingsrook.qqq.backend.core.model.metadata.permissions.PermissionLevel; +import com.kingsrook.qqq.backend.core.model.metadata.permissions.QPermissionRules; +import com.kingsrook.qqq.backend.core.model.metadata.processes.QFrontendStepMetaData; +import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData; +import com.kingsrook.qqq.backend.core.model.metadata.tables.Capability; +import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData; +import com.kingsrook.qqq.backend.core.modules.backend.implementations.memory.MemoryBackendModule; +import com.kingsrook.qqq.backend.core.utils.ListingHash; + + +/******************************************************************************* + ** + *******************************************************************************/ +public class MetaDataSpecUtils +{ + static QInstance exampleInstance; + + static + { + exampleInstance = defineExampleInstance(); + validateExampleInstance(exampleInstance); + } + + /******************************************************************************* + ** Getter for exampleInstance + ** + *******************************************************************************/ + public static QInstance getExampleInstance() + { + return exampleInstance; + } + + + + /*************************************************************************** + ** + ***************************************************************************/ + private static QInstance defineExampleInstance() + { + QInstance exampleInstance = new QInstance(); + exampleInstance.setAuthentication(new QAuthenticationMetaData().withName("anonymous").withType(QAuthenticationType.FULLY_ANONYMOUS)); + + QBackendMetaData exampleBackend = new QBackendMetaData() + .withName("example") + .withBackendType(MemoryBackendModule.class); + exampleInstance.addBackend(exampleBackend); + + ////////////////////////////////////// + // create stable sorting of entries // + ////////////////////////////////////// + TreeSet capabilities = new TreeSet<>(Comparator.comparing((Capability c) -> c.name())); + capabilities.addAll(Capability.allReadCapabilities()); + capabilities.addAll(Capability.allWriteCapabilities()); + + QTableMetaData exampleTable = new QTableMetaData() + .withName("person") + .withLabel("Person") + .withBackendName("example") + .withPrimaryKeyField("id") + .withIsHidden(false) + .withIcon(new QIcon().withName("person_outline")) + .withEnabledCapabilities(capabilities) + .withPermissionRules(new QPermissionRules().withLevel(PermissionLevel.NOT_PROTECTED)) + .withField(new QFieldMetaData("id", QFieldType.INTEGER)); + exampleInstance.addTable(exampleTable); + + QProcessMetaData exampleProcess = new QProcessMetaData() + .withName("samplePersonProcess") + .withLabel("Sample Person Process") + .withTableName("person") + .withIsHidden(false) + .withIcon(new QIcon().withName("person_add")) + .withPermissionRules(new QPermissionRules().withLevel(PermissionLevel.NOT_PROTECTED)) + .withStep(new QFrontendStepMetaData().withName("example")); + exampleInstance.addProcess(exampleProcess); + + QAppMetaData childApp = new QAppMetaData() + .withName("childApp") + .withLabel("Child App") + .withIcon(new QIcon().withName("child_friendly")) + .withPermissionRules(new QPermissionRules().withLevel(PermissionLevel.NOT_PROTECTED)) + .withChild(exampleProcess); + exampleInstance.addApp(childApp); + + QAppMetaData exampleApp = new QAppMetaData() + .withName("homeApp") + .withLabel("Home App") + .withIcon(new QIcon().withName("home")) + .withPermissionRules(new QPermissionRules().withLevel(PermissionLevel.NOT_PROTECTED)) + .withChild(childApp) + .withChild(exampleTable); + exampleInstance.addApp(exampleApp); + return exampleInstance; + } + + + + /*************************************************************************** + ** + ***************************************************************************/ + private static void validateExampleInstance(QInstance exampleInstance) + { + ListingHash, QInstanceEnricherPluginInterface> enricherPlugins = QInstanceEnricher.getEnricherPlugins(); + QInstanceEnricher.removeAllEnricherPlugins(); + + ListingHash, QInstanceValidatorPluginInterface> validatorPlugins = QInstanceValidator.getValidatorPlugins(); + QInstanceValidator.removeAllValidatorPlugins(); + + try + { + new QInstanceValidator().validate(exampleInstance); + } + catch(QInstanceValidationException e) + { + System.err.println("Error validating example instance: " + e.getMessage()); + } + + enricherPlugins.values().forEach(l -> l.forEach(QInstanceEnricher::addEnricherPlugin)); + validatorPlugins.values().forEach(l -> l.forEach(QInstanceValidator::addValidatorPlugin)); + } +}