CE-882 Initial checkin - Meta-data for making a table shareable

This commit is contained in:
2024-04-24 08:46:35 -05:00
parent 97132665a8
commit 8a74609c51
7 changed files with 774 additions and 2 deletions

View File

@ -624,6 +624,11 @@ public class QInstanceValidator
supplementalTableMetaData.validate(qInstance, table, this); supplementalTableMetaData.validate(qInstance, table, this);
} }
if(table.getShareableTableMetaData() != null)
{
table.getShareableTableMetaData().validate(qInstance, table, this);
}
runPlugins(QTableMetaData.class, table, qInstance); runPlugins(QTableMetaData.class, table, qInstance);
}); });
} }

View File

@ -0,0 +1,48 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2024. 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.sharing;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.model.MetaDataProducerInterface;
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.QPossibleValueSource;
import com.kingsrook.qqq.backend.core.processes.implementations.sharing.ShareScope;
/*******************************************************************************
**
*******************************************************************************/
public class ShareScopePossibleValueMetaDataProducer implements MetaDataProducerInterface<QPossibleValueSource>
{
public static final String NAME = "shareScope";
/*******************************************************************************
**
*******************************************************************************/
@Override
public QPossibleValueSource produce(QInstance qInstance) throws QException
{
return QPossibleValueSource.newForEnum(NAME, ShareScope.values());
}
}

View File

@ -0,0 +1,186 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2024. 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.sharing;
import java.io.Serializable;
/*******************************************************************************
** As a component of a ShareableTableMetaData instance, define details about
** one particular audience type.
**
** e.g., if a table can be shared to users and groups, there'd be 2 instances of
** this object - one like:
** - name: user
** - fieldName: userId
** - sourceTableName: User.TABLE_NAME
** - sourceTableKeyFieldName: email (e.g., can be a UK, not just the PKey)
**
** and another similar, w/ the group-type details.
*******************************************************************************/
public class ShareableAudienceType implements Serializable
{
private String name;
private String fieldName;
private String sourceTableName;
/////////////////////////////////////////////////////////////////////////////////////////////////////
// maybe normally the primary key in the source table, but could be a unique-key instead sometimes //
/////////////////////////////////////////////////////////////////////////////////////////////////////
private String sourceTableKeyFieldName;
/*******************************************************************************
** Constructor
**
*******************************************************************************/
public ShareableAudienceType()
{
}
/*******************************************************************************
** Getter for name
*******************************************************************************/
public String getName()
{
return (this.name);
}
/*******************************************************************************
** Setter for name
*******************************************************************************/
public void setName(String name)
{
this.name = name;
}
/*******************************************************************************
** Fluent setter for name
*******************************************************************************/
public ShareableAudienceType withName(String name)
{
this.name = name;
return (this);
}
/*******************************************************************************
** Getter for fieldName
*******************************************************************************/
public String getFieldName()
{
return (this.fieldName);
}
/*******************************************************************************
** Setter for fieldName
*******************************************************************************/
public void setFieldName(String fieldName)
{
this.fieldName = fieldName;
}
/*******************************************************************************
** Fluent setter for fieldName
*******************************************************************************/
public ShareableAudienceType withFieldName(String fieldName)
{
this.fieldName = fieldName;
return (this);
}
/*******************************************************************************
** Getter for sourceTableName
*******************************************************************************/
public String getSourceTableName()
{
return (this.sourceTableName);
}
/*******************************************************************************
** Setter for sourceTableName
*******************************************************************************/
public void setSourceTableName(String sourceTableName)
{
this.sourceTableName = sourceTableName;
}
/*******************************************************************************
** Fluent setter for sourceTableName
*******************************************************************************/
public ShareableAudienceType withSourceTableName(String sourceTableName)
{
this.sourceTableName = sourceTableName;
return (this);
}
/*******************************************************************************
** Getter for sourceTableKeyFieldName
*******************************************************************************/
public String getSourceTableKeyFieldName()
{
return (this.sourceTableKeyFieldName);
}
/*******************************************************************************
** Setter for sourceTableKeyFieldName
*******************************************************************************/
public void setSourceTableKeyFieldName(String sourceTableKeyFieldName)
{
this.sourceTableKeyFieldName = sourceTableKeyFieldName;
}
/*******************************************************************************
** Fluent setter for sourceTableKeyFieldName
*******************************************************************************/
public ShareableAudienceType withSourceTableKeyFieldName(String sourceTableKeyFieldName)
{
this.sourceTableKeyFieldName = sourceTableKeyFieldName;
return (this);
}
}

View File

@ -0,0 +1,356 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2024. 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.sharing;
import java.io.Serializable;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import com.kingsrook.qqq.backend.core.instances.QInstanceValidator;
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
import com.kingsrook.qqq.backend.core.utils.StringUtils;
/*******************************************************************************
** meta data to attach to a table, to describe that its records are shareable.
*******************************************************************************/
public class ShareableTableMetaData implements Serializable
{
////////////////////////////////////////////////////////////////////////////////////////////////////////////
// this is the name of the table that is a many-to-one join to the table whose records are being shared. //
// not the table whose records are shared (the asset table) //
// for example: given that we want to share "savedReports", the value here could be "sharedSavedReports" //
// and this object will be attached to the savedReports table. //
////////////////////////////////////////////////////////////////////////////////////////////////////////////
private String sharedRecordTableName;
///////////////////////////////////////////////////////////////////////////////////////////////////////
// name of the field in the sharedRecordTable that has a foreign key pointing at the asset table //
///////////////////////////////////////////////////////////////////////////////////////////////////////
private String assetIdFieldName;
//////////////////////////////////////////////////////
// name of the scope field in the sharedRecordTable //
//////////////////////////////////////////////////////
private String scopeFieldName;
///////////////////////////////////////////////////////////
// map of audienceTypes names to type definition objects //
///////////////////////////////////////////////////////////
private Map<String, ShareableAudienceType> audienceTypes;
/////////////////////////////////////////////////
// PVS that lists the available audience types //
/////////////////////////////////////////////////
private String audienceTypesPossibleValueSourceName;
//////////////////////////////////////////////////////////////
// name of a field in "this" table, that has the owner's id //
//////////////////////////////////////////////////////////////
private String thisTableOwnerIdFieldName;
/*******************************************************************************
** Constructor
**
*******************************************************************************/
public ShareableTableMetaData()
{
}
/*******************************************************************************
** Getter for sharedRecordTableName
*******************************************************************************/
public String getSharedRecordTableName()
{
return (this.sharedRecordTableName);
}
/*******************************************************************************
** Setter for sharedRecordTableName
*******************************************************************************/
public void setSharedRecordTableName(String sharedRecordTableName)
{
this.sharedRecordTableName = sharedRecordTableName;
}
/*******************************************************************************
** Fluent setter for sharedRecordTableName
*******************************************************************************/
public ShareableTableMetaData withSharedRecordTableName(String sharedRecordTableName)
{
this.sharedRecordTableName = sharedRecordTableName;
return (this);
}
/*******************************************************************************
** Getter for assetIdFieldName
*******************************************************************************/
public String getAssetIdFieldName()
{
return (this.assetIdFieldName);
}
/*******************************************************************************
** Setter for assetIdFieldName
*******************************************************************************/
public void setAssetIdFieldName(String assetIdFieldName)
{
this.assetIdFieldName = assetIdFieldName;
}
/*******************************************************************************
** Fluent setter for assetIdFieldName
*******************************************************************************/
public ShareableTableMetaData withAssetIdFieldName(String assetIdFieldName)
{
this.assetIdFieldName = assetIdFieldName;
return (this);
}
/*******************************************************************************
** Getter for scopeFieldName
*******************************************************************************/
public String getScopeFieldName()
{
return (this.scopeFieldName);
}
/*******************************************************************************
** Setter for scopeFieldName
*******************************************************************************/
public void setScopeFieldName(String scopeFieldName)
{
this.scopeFieldName = scopeFieldName;
}
/*******************************************************************************
** Fluent setter for scopeFieldName
*******************************************************************************/
public ShareableTableMetaData withScopeFieldName(String scopeFieldName)
{
this.scopeFieldName = scopeFieldName;
return (this);
}
/*******************************************************************************
** Getter for audienceTypes
*******************************************************************************/
public Map<String, ShareableAudienceType> getAudienceTypes()
{
return (this.audienceTypes);
}
/*******************************************************************************
** Setter for audienceTypes
*******************************************************************************/
public void setAudienceTypes(Map<String, ShareableAudienceType> audienceTypes)
{
this.audienceTypes = audienceTypes;
}
/*******************************************************************************
** Fluent setter for audienceTypes
*******************************************************************************/
public ShareableTableMetaData withAudienceTypes(Map<String, ShareableAudienceType> audienceTypes)
{
this.audienceTypes = audienceTypes;
return (this);
}
/*******************************************************************************
** Fluent setter for audienceTypes
*******************************************************************************/
public ShareableTableMetaData withAudienceType(ShareableAudienceType audienceType)
{
if(this.audienceTypes == null)
{
this.audienceTypes = new LinkedHashMap<>();
}
if(audienceType.getName() == null)
{
throw (new IllegalArgumentException("Attempt to add an audience type without a name"));
}
if(this.audienceTypes.containsKey(audienceType.getName()))
{
throw (new IllegalArgumentException("Attempt to add more than 1 audience type with the same name [" + audienceType.getName() + "]"));
}
this.audienceTypes.put(audienceType.getName(), audienceType);
return (this);
}
/*******************************************************************************
** Getter for audienceTypesPossibleValueSourceName
*******************************************************************************/
public String getAudienceTypesPossibleValueSourceName()
{
return (this.audienceTypesPossibleValueSourceName);
}
/*******************************************************************************
** Setter for audienceTypesPossibleValueSourceName
*******************************************************************************/
public void setAudienceTypesPossibleValueSourceName(String audienceTypesPossibleValueSourceName)
{
this.audienceTypesPossibleValueSourceName = audienceTypesPossibleValueSourceName;
}
/*******************************************************************************
** Fluent setter for audienceTypesPossibleValueSourceName
*******************************************************************************/
public ShareableTableMetaData withAudienceTypesPossibleValueSourceName(String audienceTypesPossibleValueSourceName)
{
this.audienceTypesPossibleValueSourceName = audienceTypesPossibleValueSourceName;
return (this);
}
/*******************************************************************************
** Getter for thisTableOwnerIdFieldName
*******************************************************************************/
public String getThisTableOwnerIdFieldName()
{
return (this.thisTableOwnerIdFieldName);
}
/*******************************************************************************
** Setter for thisTableOwnerIdFieldName
*******************************************************************************/
public void setThisTableOwnerIdFieldName(String thisTableOwnerIdFieldName)
{
this.thisTableOwnerIdFieldName = thisTableOwnerIdFieldName;
}
/*******************************************************************************
** Fluent setter for thisTableOwnerIdFieldName
*******************************************************************************/
public ShareableTableMetaData withThisTableOwnerIdFieldName(String thisTableOwnerIdFieldName)
{
this.thisTableOwnerIdFieldName = thisTableOwnerIdFieldName;
return (this);
}
/*******************************************************************************
**
*******************************************************************************/
public void validate(QInstance qInstance, QTableMetaData tableMetaData, QInstanceValidator qInstanceValidator)
{
String prefix = "ShareableTableMetaData for table [" + tableMetaData.getName() + "]: ";
if(qInstanceValidator.assertCondition(StringUtils.hasContent(sharedRecordTableName), prefix + "missing sharedRecordTableName."))
{
boolean hasAssetIdFieldName = qInstanceValidator.assertCondition(StringUtils.hasContent(assetIdFieldName), prefix + "missing assetIdFieldName");
boolean hasScopeFieldName = qInstanceValidator.assertCondition(StringUtils.hasContent(scopeFieldName), prefix + "missing scopeFieldName");
QTableMetaData sharedRecordTable = qInstance.getTable(sharedRecordTableName);
boolean hasValidSharedRecordTable = qInstanceValidator.assertCondition(sharedRecordTable != null, prefix + "unrecognized sharedRecordTableName [" + sharedRecordTableName + "]");
if(hasValidSharedRecordTable && hasAssetIdFieldName)
{
qInstanceValidator.assertCondition(sharedRecordTable.getFields().containsKey(assetIdFieldName), prefix + "unrecognized assertIdFieldName [" + assetIdFieldName + "] in sharedRecordTable [" + sharedRecordTableName + "]");
}
if(hasValidSharedRecordTable && hasScopeFieldName)
{
qInstanceValidator.assertCondition(sharedRecordTable.getFields().containsKey(scopeFieldName), prefix + "unrecognized scopeFieldName [" + scopeFieldName + "] in sharedRecordTable [" + sharedRecordTableName + "]");
}
if(qInstanceValidator.assertCondition(CollectionUtils.nullSafeHasContents(audienceTypes), prefix + "missing audienceTypes"))
{
for(Map.Entry<String, ShareableAudienceType> entry : audienceTypes.entrySet())
{
ShareableAudienceType audienceType = entry.getValue();
qInstanceValidator.assertCondition(Objects.equals(entry.getKey(), audienceType.getName()), prefix + "inconsistent naming for shareableAudienceType [" + entry.getKey() + "] != [" + audienceType.getName() + "]");
if(qInstanceValidator.assertCondition(StringUtils.hasContent(audienceType.getFieldName()), prefix + "missing fieldName for shareableAudienceType [" + entry.getKey() + "]") && hasValidSharedRecordTable)
{
qInstanceValidator.assertCondition(sharedRecordTable.getFields().containsKey(audienceType.getFieldName()), prefix + "unrecognized fieldName [" + audienceType.getFieldName() + "] for shareableAudienceType [" + entry.getKey() + "] in sharedRecordTable [" + sharedRecordTableName + "]");
}
/* todo - make these optional i guess, because i didn't put user table in qqq
boolean hasSourceTableKeyFieldName = qInstanceValidator.assertCondition(StringUtils.hasContent(audienceType.getSourceTableKeyFieldName()), prefix + "missing sourceTableKeyFieldName for shareableAudienceType [" + entry.getKey() + "]");
if(qInstanceValidator.assertCondition(qInstance.getTable(audienceType.getSourceTableName()) != null, prefix + "unrecognized sourceTableName [" + audienceType.getSourceTableName() + "] for shareableAudienceType [" + entry.getKey() + "] in sharedRecordTable [" + sharedRecordTableName + "]") && hasSourceTableKeyFieldName)
{
qInstanceValidator.assertCondition(qInstance.getTable(audienceType.getSourceTableName()).getFields().containsKey(audienceType.getSourceTableKeyFieldName()), prefix + "unrecognized sourceTableKeyFieldName [" + audienceType.getSourceTableKeyFieldName() + "] for shareableAudienceType [" + entry.getKey() + "] in sharedRecordTable [" + sharedRecordTableName + "]");
}
*/
}
}
}
if(StringUtils.hasContent(thisTableOwnerIdFieldName))
{
qInstanceValidator.assertCondition(tableMetaData.getFields().containsKey(thisTableOwnerIdFieldName), prefix + "unrecognized thisTableOwnerIdFieldName [" + thisTableOwnerIdFieldName + "]");
}
if(StringUtils.hasContent(audienceTypesPossibleValueSourceName))
{
qInstanceValidator.assertCondition(qInstance.getPossibleValueSource(audienceTypesPossibleValueSourceName) != null, prefix + "unrecognized audienceTypesPossibleValueSourceName [" + audienceTypesPossibleValueSourceName + "]");
}
}
}

View File

@ -48,6 +48,7 @@ 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.MetaDataWithPermissionRules;
import com.kingsrook.qqq.backend.core.model.metadata.permissions.QPermissionRules; import com.kingsrook.qqq.backend.core.model.metadata.permissions.QPermissionRules;
import com.kingsrook.qqq.backend.core.model.metadata.security.RecordSecurityLock; 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; import com.kingsrook.qqq.backend.core.model.metadata.tables.automation.QTableAutomationDetails;
import com.kingsrook.qqq.backend.core.model.metadata.tables.cache.CacheOf; import com.kingsrook.qqq.backend.core.model.metadata.tables.cache.CacheOf;
import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair; import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair;
@ -107,6 +108,7 @@ public class QTableMetaData implements QAppChildMetaData, Serializable, MetaData
private List<ExposedJoin> exposedJoins; private List<ExposedJoin> exposedJoins;
private ShareableTableMetaData shareableTableMetaData;
/******************************************************************************* /*******************************************************************************
@ -1385,4 +1387,35 @@ public class QTableMetaData implements QAppChildMetaData, Serializable, MetaData
return (this); return (this);
} }
/*******************************************************************************
** Getter for shareableTableMetaData
*******************************************************************************/
public ShareableTableMetaData getShareableTableMetaData()
{
return (this.shareableTableMetaData);
}
/*******************************************************************************
** Setter for shareableTableMetaData
*******************************************************************************/
public void setShareableTableMetaData(ShareableTableMetaData shareableTableMetaData)
{
this.shareableTableMetaData = shareableTableMetaData;
}
/*******************************************************************************
** Fluent setter for shareableTableMetaData
*******************************************************************************/
public QTableMetaData withShareableTableMetaData(ShareableTableMetaData shareableTableMetaData)
{
this.shareableTableMetaData = shareableTableMetaData;
return (this);
}
} }

View File

@ -78,6 +78,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.scheduleing.QScheduleMetaDa
import com.kingsrook.qqq.backend.core.model.metadata.security.FieldSecurityLock; import com.kingsrook.qqq.backend.core.model.metadata.security.FieldSecurityLock;
import com.kingsrook.qqq.backend.core.model.metadata.security.QSecurityKeyType; import com.kingsrook.qqq.backend.core.model.metadata.security.QSecurityKeyType;
import com.kingsrook.qqq.backend.core.model.metadata.security.RecordSecurityLock; 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.Association; import com.kingsrook.qqq.backend.core.model.metadata.tables.Association;
import com.kingsrook.qqq.backend.core.model.metadata.tables.ExposedJoin; import com.kingsrook.qqq.backend.core.model.metadata.tables.ExposedJoin;
import com.kingsrook.qqq.backend.core.model.metadata.tables.QFieldSection; import com.kingsrook.qqq.backend.core.model.metadata.tables.QFieldSection;
@ -2004,7 +2005,21 @@ public class QInstanceValidatorTest extends BaseTest
qInstance.addTable(newTable("B", "id", "aId")); qInstance.addTable(newTable("B", "id", "aId"));
qInstance.addJoin(new QJoinMetaData().withLeftTable("A").withRightTable("B").withName("AB").withType(JoinType.ONE_TO_ONE).withJoinOn(new JoinOn("id", "aId"))); qInstance.addJoin(new QJoinMetaData().withLeftTable("A").withRightTable("B").withName("AB").withType(JoinType.ONE_TO_ONE).withJoinOn(new JoinOn("id", "aId")));
}); });
}
/*******************************************************************************
**
*******************************************************************************/
@Test
void testShareableTableMetaData()
{
////////////////////////////////////////////////////////////////////////////////////////////////////////////
// just make sure we call this class's validator - the rest of its conditions are covered in its own test //
////////////////////////////////////////////////////////////////////////////////////////////////////////////
assertValidationFailureReasonsAllowingExtraReasons(qInstance -> qInstance.addTable(newTable("A", "id").withShareableTableMetaData(new ShareableTableMetaData())),
"missing sharedRecordTableName");
} }
@ -2113,7 +2128,7 @@ public class QInstanceValidatorTest extends BaseTest
/******************************************************************************* /*******************************************************************************
** **
*******************************************************************************/ *******************************************************************************/
private QTableMetaData newTable(String tableName, String... fieldNames) protected QTableMetaData newTable(String tableName, String... fieldNames)
{ {
QTableMetaData tableMetaData = new QTableMetaData() QTableMetaData tableMetaData = new QTableMetaData()
.withName(tableName) .withName(tableName)
@ -2207,7 +2222,7 @@ public class QInstanceValidatorTest extends BaseTest
/******************************************************************************* /*******************************************************************************
** Assert that an instance is valid! ** Assert that an instance is valid!
*******************************************************************************/ *******************************************************************************/
private void assertValidationSuccess(Consumer<QInstance> setup) public static void assertValidationSuccess(Consumer<QInstance> setup)
{ {
try try
{ {

View File

@ -0,0 +1,129 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2024. 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.sharing;
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.tables.QTableMetaData;
import com.kingsrook.qqq.backend.core.utils.TestUtils;
import org.junit.jupiter.api.Test;
import static com.kingsrook.qqq.backend.core.instances.QInstanceValidatorTest.assertValidationFailureReasons;
import static com.kingsrook.qqq.backend.core.instances.QInstanceValidatorTest.assertValidationFailureReasonsAllowingExtraReasons;
import static com.kingsrook.qqq.backend.core.instances.QInstanceValidatorTest.assertValidationSuccess;
/*******************************************************************************
** Unit test for ShareableTableMetaData
*******************************************************************************/
class ShareableTableMetaDataTest
{
/*******************************************************************************
**
*******************************************************************************/
@Test
void testValidation()
{
assertValidationFailureReasonsAllowingExtraReasons(qInstance -> qInstance.addTable(newTable().withShareableTableMetaData(new ShareableTableMetaData())),
"missing sharedRecordTableName");
assertValidationFailureReasonsAllowingExtraReasons(qInstance -> qInstance.addTable(newTable().withShareableTableMetaData(new ShareableTableMetaData()
.withSharedRecordTableName("notATable")
)), "unrecognized sharedRecordTableName");
assertValidationFailureReasonsAllowingExtraReasons(qInstance -> qInstance.addTable(newTable().withShareableTableMetaData(new ShareableTableMetaData()
.withAudienceTypesPossibleValueSourceName("notAPVS")
)), "unrecognized audienceTypesPossibleValueSourceName");
assertValidationFailureReasons(qInstance -> qInstance.addTable(newTable().withShareableTableMetaData(new ShareableTableMetaData()
.withSharedRecordTableName(TestUtils.TABLE_NAME_PERSON_MEMORY)
)), "missing assetIdFieldName",
"missing scopeFieldName",
"missing audienceTypes");
assertValidationFailureReasonsAllowingExtraReasons(qInstance -> qInstance.addTable(newTable().withShareableTableMetaData(new ShareableTableMetaData()
.withSharedRecordTableName(TestUtils.TABLE_NAME_PERSON_MEMORY)
.withAssetIdFieldName("notAField")
)), "unrecognized assertIdFieldName");
assertValidationFailureReasonsAllowingExtraReasons(qInstance -> qInstance.addTable(newTable().withShareableTableMetaData(new ShareableTableMetaData()
.withSharedRecordTableName(TestUtils.TABLE_NAME_PERSON_MEMORY)
.withScopeFieldName("notAField")
)), "unrecognized scopeFieldName");
assertValidationFailureReasonsAllowingExtraReasons(qInstance -> qInstance.addTable(newTable().withShareableTableMetaData(new ShareableTableMetaData()
.withSharedRecordTableName(TestUtils.TABLE_NAME_PERSON_MEMORY)
.withAudienceType(new ShareableAudienceType().withName("myType"))
)), "missing fieldName for shareableAudienceType");
assertValidationFailureReasonsAllowingExtraReasons(qInstance -> qInstance.addTable(newTable().withShareableTableMetaData(new ShareableTableMetaData()
.withSharedRecordTableName(TestUtils.TABLE_NAME_PERSON_MEMORY)
.withAudienceType(new ShareableAudienceType().withName("myType").withFieldName("notAField"))
)), "unrecognized fieldName");
/* todo - corresponding todo in main class
assertValidationFailureReasonsAllowingExtraReasons(qInstance -> qInstance.addTable(newTable().withShareableTableMetaData(new ShareableTableMetaData()
.withSharedRecordTableName(TestUtils.TABLE_NAME_PERSON_MEMORY)
.withAudienceType(new ShareableAudienceType().withName("myType").withFieldName("firstName").withSourceTableName("notATable"))
)), "unrecognized sourceTableName");
assertValidationFailureReasonsAllowingExtraReasons(qInstance -> qInstance.addTable(newTable().withShareableTableMetaData(new ShareableTableMetaData()
.withSharedRecordTableName(TestUtils.TABLE_NAME_PERSON_MEMORY)
.withAudienceType(new ShareableAudienceType().withName("myType").withFieldName("firstName").withSourceTableName(TestUtils.TABLE_NAME_SHAPE).withSourceTableKeyFieldName("notAField"))
)), "unrecognized sourceTableKeyFieldName");
*/
assertValidationFailureReasonsAllowingExtraReasons(qInstance -> qInstance.addTable(newTable().withShareableTableMetaData(new ShareableTableMetaData()
.withThisTableOwnerIdFieldName("notAField")
)), "unrecognized thisTableOwnerIdFieldName");
assertValidationSuccess(qInstance -> qInstance.addTable(newTable()
.withField(new QFieldMetaData("userId", QFieldType.INTEGER))
.withShareableTableMetaData(new ShareableTableMetaData()
.withSharedRecordTableName(TestUtils.TABLE_NAME_PERSON_MEMORY)
.withAssetIdFieldName("firstName")
.withScopeFieldName("firstName")
.withThisTableOwnerIdFieldName("userId")
.withAudienceTypesPossibleValueSourceName(TestUtils.POSSIBLE_VALUE_SOURCE_STATE)
.withAudienceType(new ShareableAudienceType().withName("myType").withFieldName("lastName").withSourceTableName(TestUtils.TABLE_NAME_SHAPE).withSourceTableKeyFieldName("id"))
)));
}
/*******************************************************************************
**
*******************************************************************************/
protected QTableMetaData newTable()
{
QTableMetaData tableMetaData = new QTableMetaData()
.withName("A")
.withBackendName(TestUtils.DEFAULT_BACKEND_NAME)
.withPrimaryKeyField("id");
tableMetaData.addField(new QFieldMetaData("id", QFieldType.INTEGER));
return (tableMetaData);
}
}