Initial checkin of QBits, mostly.

This commit is contained in:
2025-02-21 16:24:30 -06:00
parent f4f2f3c80e
commit 001860fc91
16 changed files with 1534 additions and 6 deletions

View File

@ -24,6 +24,7 @@ package com.kingsrook.qqq.backend.core.model.metadata;
import java.util.ArrayList;
import java.util.List;
import com.kingsrook.qqq.backend.core.model.metadata.qbits.SourceQBitAware;
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
@ -31,10 +32,12 @@ import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
** Output object for a MetaDataProducer, which contains multiple meta-data
** objects.
*******************************************************************************/
public class MetaDataProducerMultiOutput implements MetaDataProducerOutput
public class MetaDataProducerMultiOutput implements MetaDataProducerOutput, SourceQBitAware
{
private List<MetaDataProducerOutput> contents;
private String sourceQBitName;
/*******************************************************************************
@ -98,4 +101,48 @@ public class MetaDataProducerMultiOutput implements MetaDataProducerOutput
return (rs);
}
/***************************************************************************
**
***************************************************************************/
@Override
public String getSourceQBitName()
{
return (this.sourceQBitName);
}
/***************************************************************************
**
***************************************************************************/
@Override
public void setSourceQBitName(String sourceQBitName)
{
this.sourceQBitName = sourceQBitName;
/////////////////////////////////////////////
// propagate the name down to the children //
/////////////////////////////////////////////
for(MetaDataProducerOutput content : contents)
{
if(content instanceof SourceQBitAware aware)
{
aware.setSourceQBitName(sourceQBitName);
}
}
}
/***************************************************************************
**
***************************************************************************/
@Override
public MetaDataProducerMultiOutput withSourceQBitName(String sourceQBitName)
{
setSourceQBitName(sourceQBitName);
return this;
}
}

View File

@ -56,6 +56,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.permissions.QPermissionRule
import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.QPossibleValueSource;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QStepMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.qbits.QBitMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.queues.QQueueMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.queues.QQueueProviderMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.reporting.QReportMetaData;
@ -89,6 +90,7 @@ public class QInstance
////////////////////////////////////////////////////////////////////////////////////////////
// Important to use LinkedHashmap here, to preserve the order in which entries are added. //
////////////////////////////////////////////////////////////////////////////////////////////
private Map<String, QBitMetaData> qBits = new LinkedHashMap<>();
private Map<String, QTableMetaData> tables = new LinkedHashMap<>();
private Map<String, QJoinMetaData> joins = new LinkedHashMap<>();
private Map<String, QPossibleValueSource> possibleValueSources = new LinkedHashMap<>();
@ -1489,6 +1491,7 @@ public class QInstance
}
/*******************************************************************************
** Getter for metaDataFilter
*******************************************************************************/
@ -1519,4 +1522,68 @@ public class QInstance
}
/*******************************************************************************
**
*******************************************************************************/
public void addQBit(QBitMetaData qBitMetaData)
{
List<String> missingParts = new ArrayList<>();
if(!StringUtils.hasContent(qBitMetaData.getGroupId()))
{
missingParts.add("groupId");
}
if(!StringUtils.hasContent(qBitMetaData.getArtifactId()))
{
missingParts.add("artifactId");
}
if(!StringUtils.hasContent(qBitMetaData.getVersion()))
{
missingParts.add("version");
}
if(!missingParts.isEmpty())
{
throw (new IllegalArgumentException("Attempted to add a qBit without a " + StringUtils.joinWithCommasAndAnd(missingParts)));
}
String name = qBitMetaData.getName();
if(this.qBits.containsKey(name))
{
throw (new IllegalArgumentException("Attempted to add a second qBit with name (formed from 'groupId:artifactId:version[:namespace]'): " + name));
}
this.qBits.put(name, qBitMetaData);
}
/*******************************************************************************
** Getter for qBits
*******************************************************************************/
public Map<String, QBitMetaData> getQBits()
{
return (this.qBits);
}
/*******************************************************************************
** Setter for qBits
*******************************************************************************/
public void setQBits(Map<String, QBitMetaData> qBits)
{
this.qBits = qBits;
}
/*******************************************************************************
** Fluent setter for qBits
*******************************************************************************/
public QInstance withQBits(Map<String, QBitMetaData> qBits)
{
this.qBits = qBits;
return (this);
}
}

View File

@ -37,6 +37,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.layout.QAppChildMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.layout.QIcon;
import com.kingsrook.qqq.backend.core.model.metadata.permissions.MetaDataWithPermissionRules;
import com.kingsrook.qqq.backend.core.model.metadata.permissions.QPermissionRules;
import com.kingsrook.qqq.backend.core.model.metadata.qbits.SourceQBitAware;
import com.kingsrook.qqq.backend.core.model.metadata.scheduleing.QScheduleMetaData;
import com.kingsrook.qqq.backend.core.processes.implementations.basepull.BasepullConfiguration;
import com.kingsrook.qqq.backend.core.utils.StringUtils;
@ -46,11 +47,14 @@ import com.kingsrook.qqq.backend.core.utils.StringUtils;
** Meta-Data to define a process in a QQQ instance.
**
*******************************************************************************/
public class QProcessMetaData implements QAppChildMetaData, MetaDataWithPermissionRules, TopLevelMetaDataInterface
public class QProcessMetaData implements QAppChildMetaData, MetaDataWithPermissionRules, TopLevelMetaDataInterface, SourceQBitAware
{
private String name;
private String label;
private String tableName;
private String name;
private String label;
private String tableName;
private String sourceQBitName;
private boolean isHidden = false;
private BasepullConfiguration basepullConfiguration;
private QPermissionRules permissionRules;
@ -870,6 +874,7 @@ public class QProcessMetaData implements QAppChildMetaData, MetaDataWithPermissi
}
/*******************************************************************************
** Getter for processTracerCodeReference
*******************************************************************************/
@ -900,4 +905,37 @@ public class QProcessMetaData implements QAppChildMetaData, MetaDataWithPermissi
}
/*******************************************************************************
** Getter for sourceQBitName
*******************************************************************************/
@Override
public String getSourceQBitName()
{
return (this.sourceQBitName);
}
/*******************************************************************************
** Setter for sourceQBitName
*******************************************************************************/
@Override
public void setSourceQBitName(String sourceQBitName)
{
this.sourceQBitName = sourceQBitName;
}
/*******************************************************************************
** Fluent setter for sourceQBitName
*******************************************************************************/
@Override
public QProcessMetaData withSourceQBitName(String sourceQBitName)
{
this.sourceQBitName = sourceQBitName;
return (this);
}
}

View File

@ -0,0 +1,122 @@
/*
* 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.backend.core.model.metadata.qbits;
/***************************************************************************
** Common (maybe)? qbit config pattern, where the qbit may be able to provide
** a particular table, or, the application may supply it itself.
**
** If the qbit provides it, then we need to be told (by the application)
** what backendName to use for the table.
**
** Else if the application supplies it, it needs to tell the qBit what the
** tableName is.
***************************************************************************/
public class ProvidedOrSuppliedTableConfig
{
private boolean doProvideTable;
private String backendName;
private String tableName;
/***************************************************************************
**
***************************************************************************/
public ProvidedOrSuppliedTableConfig(boolean doProvideTable, String backendName, String tableName)
{
this.doProvideTable = doProvideTable;
this.backendName = backendName;
this.tableName = tableName;
}
/***************************************************************************
**
***************************************************************************/
public static ProvidedOrSuppliedTableConfig provideTableUsingBackendNamed(String backendName)
{
return (new ProvidedOrSuppliedTableConfig(true, backendName, null));
}
/***************************************************************************
**
***************************************************************************/
public static ProvidedOrSuppliedTableConfig useSuppliedTaleNamed(String tableName)
{
return (new ProvidedOrSuppliedTableConfig(false, null, tableName));
}
/***************************************************************************
**
***************************************************************************/
public String getEffectiveTableName(String tableNameIfProviding)
{
if (getDoProvideTable())
{
return tableNameIfProviding;
}
else
{
return getTableName();
}
}
/*******************************************************************************
** Getter for tableName
**
*******************************************************************************/
public String getTableName()
{
return tableName;
}
/*******************************************************************************
** Getter for doProvideTable
**
*******************************************************************************/
public boolean getDoProvideTable()
{
return doProvideTable;
}
/*******************************************************************************
** Getter for backendName
**
*******************************************************************************/
public String getBackendName()
{
return backendName;
}
}

View File

@ -0,0 +1,71 @@
/*
* 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.backend.core.model.metadata.qbits;
import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducerInterface;
import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducerOutput;
/*******************************************************************************
** extension of MetaDataProducerInterface, designed for producing meta data
** within a (java-defined, at this time) QBit.
**
** Specifically exists to accept the QBitConfig as a type parameter and a value,
** easily accessed in the producer's methods as getQBitConfig()
*******************************************************************************/
public abstract class QBitComponentMetaDataProducer<T extends MetaDataProducerOutput, C extends QBitConfig> implements MetaDataProducerInterface<T>
{
private C qBitConfig = null;
/*******************************************************************************
** Getter for qBitConfig
*******************************************************************************/
public C getQBitConfig()
{
return (this.qBitConfig);
}
/*******************************************************************************
** Setter for qBitConfig
*******************************************************************************/
public void setQBitConfig(C qBitConfig)
{
this.qBitConfig = qBitConfig;
}
/*******************************************************************************
** Fluent setter for qBitConfig
*******************************************************************************/
public QBitComponentMetaDataProducer<T, C> withQBitConfig(C qBitConfig)
{
this.qBitConfig = qBitConfig;
return (this);
}
}

View File

@ -0,0 +1,110 @@
/*
* 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.backend.core.model.metadata.qbits;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import com.kingsrook.qqq.backend.core.logging.QLogger;
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
import com.kingsrook.qqq.backend.core.model.metadata.producers.MetaDataCustomizerInterface;
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
/*******************************************************************************
** Interface for configuration settings used both in the production of meta-data
** for a QBit, but also at runtime, e.g., to be aware of exactly how the qbit
** has been incorporated into an application.
**
** For example:
** - should the QBit define certain tables, or will they be supplied by the application?
** - what other meta-data names should the qbit reference (backends, schedulers)
** - what meta-data-customizer(s) should be used?
**
** When implementing a QBit, you'll implement this interface - adding whatever
** (if any) properties you need, and if you have any rules, then overriding
** the validate method (ideally the one that takes the List-of-String errors)
**
** When using a QBit, you'll create an instance of the QBit's config object,
** and pass it through to the QBit producer.
*******************************************************************************/
public interface QBitConfig extends Serializable
{
QLogger LOG = QLogger.getLogger(QBitConfig.class);
/***************************************************************************
**
***************************************************************************/
default void validate(QInstance qInstance) throws QBitConfigValidationException
{
List<String> errors = new ArrayList<>();
try
{
validate(qInstance, errors);
}
catch(Exception e)
{
LOG.warn("Error validating QBitConfig: " + this.getClass().getName(), e);
}
if(!errors.isEmpty())
{
throw (new QBitConfigValidationException(this, errors));
}
}
/***************************************************************************
**
***************************************************************************/
default void validate(QInstance qInstance, List<String> errors)
{
/////////////////////////////////////
// nothing to validate by default! //
/////////////////////////////////////
}
/***************************************************************************
**
***************************************************************************/
default boolean assertCondition(boolean condition, String message, List<String> errors)
{
if(!condition)
{
errors.add(message);
}
return (condition);
}
/***************************************************************************
**
***************************************************************************/
default MetaDataCustomizerInterface<QTableMetaData> getTableMetaDataCustomizer()
{
return (null);
}
}

View File

@ -0,0 +1,44 @@
/*
* 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.backend.core.model.metadata.qbits;
import java.util.List;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.utils.StringUtils;
/*******************************************************************************
** thrown by QBitConfig.validate() if there's an issue.
*******************************************************************************/
public class QBitConfigValidationException extends QException
{
/***************************************************************************
**
***************************************************************************/
public QBitConfigValidationException(QBitConfig qBitConfig, List<String> errors)
{
super("Validation failed for QBitConfig: " + qBitConfig.getClass().getName() + ":\n" + StringUtils.join("\n", errors));
}
}

View File

@ -0,0 +1,237 @@
/*
* 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.backend.core.model.metadata.qbits;
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
import com.kingsrook.qqq.backend.core.model.metadata.TopLevelMetaDataInterface;
import com.kingsrook.qqq.backend.core.utils.StringUtils;
/*******************************************************************************
** Meta-data to define an active QBit in a QQQ Instance.
**
** The unique "name" for the QBit is composed of its groupId and artifactId
** (maven style). There is also a version - but it is not part of the unique
** name. But - there is also a namespace attribute, which IS part of the
** unique name. This will (eventually?) allow us to have multiple instances
** of the same qbit in a qInstance at the same time (e.g., 2 versions of some
** table, which should be namespace-prefixed);
**
** QBitMetaData also retains the QBitConfig that was used to produce the QBit.
**
** Some meta-data objects are aware of the fact that they may have come from a
** QBit - see SourceQBitAware interface. These objects can get their source
** QBitMetaData (this object) and its config,via that interface.
*******************************************************************************/
public class QBitMetaData implements TopLevelMetaDataInterface
{
private String groupId;
private String artifactId;
private String version;
private String namespace;
private QBitConfig config;
/***************************************************************************
**
***************************************************************************/
@Override
public String getName()
{
String name = groupId + ":" + artifactId;
if(StringUtils.hasContent(namespace))
{
name += ":" + namespace;
}
return name;
}
/***************************************************************************
**
***************************************************************************/
@Override
public void addSelfToInstance(QInstance qInstance)
{
qInstance.addQBit(this);
}
/*******************************************************************************
** Getter for config
*******************************************************************************/
public QBitConfig getConfig()
{
return (this.config);
}
/*******************************************************************************
** Setter for config
*******************************************************************************/
public void setConfig(QBitConfig config)
{
this.config = config;
}
/*******************************************************************************
** Fluent setter for config
*******************************************************************************/
public QBitMetaData withConfig(QBitConfig config)
{
this.config = config;
return (this);
}
/*******************************************************************************
** Getter for groupId
*******************************************************************************/
public String getGroupId()
{
return (this.groupId);
}
/*******************************************************************************
** Setter for groupId
*******************************************************************************/
public void setGroupId(String groupId)
{
this.groupId = groupId;
}
/*******************************************************************************
** Fluent setter for groupId
*******************************************************************************/
public QBitMetaData withGroupId(String groupId)
{
this.groupId = groupId;
return (this);
}
/*******************************************************************************
** Getter for artifactId
*******************************************************************************/
public String getArtifactId()
{
return (this.artifactId);
}
/*******************************************************************************
** Setter for artifactId
*******************************************************************************/
public void setArtifactId(String artifactId)
{
this.artifactId = artifactId;
}
/*******************************************************************************
** Fluent setter for artifactId
*******************************************************************************/
public QBitMetaData withArtifactId(String artifactId)
{
this.artifactId = artifactId;
return (this);
}
/*******************************************************************************
** Getter for version
*******************************************************************************/
public String getVersion()
{
return (this.version);
}
/*******************************************************************************
** Setter for version
*******************************************************************************/
public void setVersion(String version)
{
this.version = version;
}
/*******************************************************************************
** Fluent setter for version
*******************************************************************************/
public QBitMetaData withVersion(String version)
{
this.version = version;
return (this);
}
/*******************************************************************************
** Getter for namespace
*******************************************************************************/
public String getNamespace()
{
return (this.namespace);
}
/*******************************************************************************
** Setter for namespace
*******************************************************************************/
public void setNamespace(String namespace)
{
this.namespace = namespace;
}
/*******************************************************************************
** Fluent setter for namespace
*******************************************************************************/
public QBitMetaData withNamespace(String namespace)
{
this.namespace = namespace;
return (this);
}
}

View File

@ -0,0 +1,117 @@
/*
* 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.backend.core.model.metadata.qbits;
import java.util.List;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.logging.QLogger;
import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducerInterface;
import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducerOutput;
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair;
/*******************************************************************************
** interface for how a QBit's meta-data gets produced and added to a QInstance.
**
** When implementing a QBit, you'll implement this interface:
** - adding a QBitConfig subclass as a property
** - overriding the produce(qInstance, namespace) method - where you'll:
** -- create and add your QBitMetaData
** -- call MetaDataProducerHelper.findProducers
** -- hand off to finishProducing() in this interface
**
** When using a QBit, you'll create an instance of the QBit's config object,
** pass it in to the producer, then call produce, ala:
**
** new SomeQBitProducer()
** .withQBitConfig(someQBitConfig)
** .produce(qInstance);
**
*******************************************************************************/
public interface QBitProducer
{
QLogger LOG = QLogger.getLogger(QBitProducer.class);
/***************************************************************************
**
***************************************************************************/
default void produce(QInstance qInstance) throws QException
{
produce(qInstance, null);
}
/***************************************************************************
**
***************************************************************************/
void produce(QInstance qInstance, String namespace) throws QException;
/***************************************************************************
*
***************************************************************************/
default <C extends QBitConfig> void finishProducing(QInstance qInstance, QBitMetaData qBitMetaData, C qBitConfig, List<MetaDataProducerInterface<?>> producers) throws QException
{
qBitConfig.validate(qInstance);
///////////////////////////////
// todo - move to base class //
///////////////////////////////
for(MetaDataProducerInterface<?> producer : producers)
{
if(producer instanceof QBitComponentMetaDataProducer<?, ?>)
{
QBitComponentMetaDataProducer<?, C> qBitComponentMetaDataProducer = (QBitComponentMetaDataProducer<?, C>) producer;
qBitComponentMetaDataProducer.setQBitConfig(qBitConfig);
}
if(!producer.isEnabled())
{
LOG.debug("Not using producer which is not enabled", logPair("producer", producer.getClass().getSimpleName()));
continue;
}
MetaDataProducerOutput output = producer.produce(qInstance);
/////////////////////////////////////////
// apply table customizer, if provided //
/////////////////////////////////////////
if(qBitConfig.getTableMetaDataCustomizer() != null && output instanceof QTableMetaData table)
{
output = qBitConfig.getTableMetaDataCustomizer().customizeMetaData(qInstance, table);
}
/////////////////////////////////////////////////
// set source qbit, if output is aware of such //
/////////////////////////////////////////////////
if(output instanceof SourceQBitAware sourceQBitAware)
{
sourceQBitAware.setSourceQBitName(qBitMetaData.getName());
}
output.addSelfToInstance(qInstance);
}
}
}

View File

@ -0,0 +1,77 @@
/*
* 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.backend.core.model.metadata.qbits;
import com.kingsrook.qqq.backend.core.context.QContext;
/*******************************************************************************
** interface for meta data objects that may have come from a qbit, and where we
** might want to get data about that qbit (e.g., config or meta-data).
*******************************************************************************/
public interface SourceQBitAware
{
/*******************************************************************************
** Getter for sourceQBitName
*******************************************************************************/
String getSourceQBitName();
/*******************************************************************************
** Setter for sourceQBitName
*******************************************************************************/
void setSourceQBitName(String sourceQBitName);
/*******************************************************************************
** Fluent setter for sourceQBitName
*******************************************************************************/
Object withSourceQBitName(String sourceQBitName);
/***************************************************************************
**
***************************************************************************/
default QBitMetaData getSourceQBit()
{
String qbitName = getSourceQBitName();
return (QContext.getQInstance().getQBits().get(qbitName));
}
/***************************************************************************
**
***************************************************************************/
default QBitConfig getSourceQBitConfig()
{
QBitMetaData sourceQBit = getSourceQBit();
if(sourceQBit == null)
{
return null;
}
else
{
return sourceQBit.getConfig();
}
}
}

View File

@ -50,6 +50,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.layout.QAppChildMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.layout.QIcon;
import com.kingsrook.qqq.backend.core.model.metadata.permissions.MetaDataWithPermissionRules;
import com.kingsrook.qqq.backend.core.model.metadata.permissions.QPermissionRules;
import com.kingsrook.qqq.backend.core.model.metadata.qbits.SourceQBitAware;
import com.kingsrook.qqq.backend.core.model.metadata.security.RecordSecurityLock;
import com.kingsrook.qqq.backend.core.model.metadata.sharing.ShareableTableMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.tables.automation.QTableAutomationDetails;
@ -62,7 +63,7 @@ import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair;
** Meta-Data to define a table in a QQQ instance.
**
*******************************************************************************/
public class QTableMetaData implements QAppChildMetaData, Serializable, MetaDataWithPermissionRules, TopLevelMetaDataInterface
public class QTableMetaData implements QAppChildMetaData, Serializable, MetaDataWithPermissionRules, TopLevelMetaDataInterface, SourceQBitAware
{
private static final QLogger LOG = QLogger.getLogger(QTableMetaData.class);
@ -73,6 +74,8 @@ public class QTableMetaData implements QAppChildMetaData, Serializable, MetaData
private String primaryKeyField;
private boolean isHidden = false;
private String sourceQBitName;
private Map<String, QFieldMetaData> fields;
private List<UniqueKey> uniqueKeys;
private List<Association> associations;
@ -1554,4 +1557,38 @@ public class QTableMetaData implements QAppChildMetaData, Serializable, MetaData
QInstanceHelpContentManager.removeHelpContentByRoleSetFromList(roles, listForSlot);
}
/*******************************************************************************
** Getter for sourceQBitName
*******************************************************************************/
@Override
public String getSourceQBitName()
{
return (this.sourceQBitName);
}
/*******************************************************************************
** Setter for sourceQBitName
*******************************************************************************/
@Override
public void setSourceQBitName(String sourceQBitName)
{
this.sourceQBitName = sourceQBitName;
}
/*******************************************************************************
** Fluent setter for sourceQBitName
*******************************************************************************/
@Override
public QTableMetaData withSourceQBitName(String sourceQBitName)
{
this.sourceQBitName = sourceQBitName;
return (this);
}
}