Use same example qinstance in meta-data and table-meta-data specs

This commit is contained in:
2025-05-27 16:42:01 -05:00
parent 35c6a13ce3
commit 6314ad310b
3 changed files with 194 additions and 125 deletions

View File

@ -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<MetaDataInput, MetaDataResponseV1, MetaDataExecutor>
{
private static QInstance exampleInstance;
static
{
exampleInstance = defineExampleInstance();
validateExampleInstance(exampleInstance);
}
/***************************************************************************
**
***************************************************************************/
@ -203,9 +173,9 @@ public class MetaDataSpecV1 extends AbstractEndpointSpec<MetaDataInput, MetaData
// 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. //
//////////////////////////////////////////////////////////////////////////////////////////////////////
QContext.withTemporaryContext(new CapturedContext(exampleInstance, null), () ->
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<MetaDataInput, MetaData
);
}
/***************************************************************************
**
***************************************************************************/
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<Capability> 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<Class<?>, QInstanceEnricherPluginInterface<?>> enricherPlugins = QInstanceEnricher.getEnricherPlugins();
QInstanceEnricher.removeAllEnricherPlugins();
ListingHash<Class<?>, 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));
}
}

View File

@ -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<TableMetaDataInput
@Override
public BasicResponse defineBasicSuccessResponse()
{
QFrontendTableMetaData frontendTableMetaData = null; // todo
Map<String, Example> examples = new LinkedHashMap<>();
examples.put("TODO", new Example()
//////////////////////////////////////////////////////////////////////////////////////////////////////
// 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""",

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
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<Capability> 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<Class<?>, QInstanceEnricherPluginInterface<?>> enricherPlugins = QInstanceEnricher.getEnricherPlugins();
QInstanceEnricher.removeAllEnricherPlugins();
ListingHash<Class<?>, 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));
}
}