From c748977a1b0450754dc5c0f35b67e3953e491816 Mon Sep 17 00:00:00 2001 From: Darin Kelkhoff Date: Wed, 19 Jun 2024 16:50:00 -0500 Subject: [PATCH] Validate that an api table doesn't have more than 1 field with the same name (which can happen if it's in the removed set along with main set) --- .../api/actions/GetTableApiFieldsAction.java | 26 ++++++++- .../tables/ApiTableMetaDataContainer.java | 57 +++++++++++++++++++ 2 files changed, 81 insertions(+), 2 deletions(-) diff --git a/qqq-middleware-api/src/main/java/com/kingsrook/qqq/api/actions/GetTableApiFieldsAction.java b/qqq-middleware-api/src/main/java/com/kingsrook/qqq/api/actions/GetTableApiFieldsAction.java index 23cfdf48..0319b64f 100644 --- a/qqq-middleware-api/src/main/java/com/kingsrook/qqq/api/actions/GetTableApiFieldsAction.java +++ b/qqq-middleware-api/src/main/java/com/kingsrook/qqq/api/actions/GetTableApiFieldsAction.java @@ -25,9 +25,11 @@ package com.kingsrook.qqq.api.actions; import java.util.ArrayList; import java.util.Comparator; import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; +import java.util.Set; import com.kingsrook.qqq.api.model.APIVersion; import com.kingsrook.qqq.api.model.APIVersionRange; import com.kingsrook.qqq.api.model.actions.GetTableApiFieldsInput; @@ -76,7 +78,27 @@ public class GetTableApiFieldsAction extends AbstractQActionFunction map = getTableApiFieldList(apiNameVersionAndTableName).stream().collect(Collectors.toMap(f -> (ApiFieldMetaData.getEffectiveApiFieldName(apiNameVersionAndTableName.apiName(), f)), f -> f)); + List tableApiFieldList = getTableApiFieldList(apiNameVersionAndTableName); + Map map = new LinkedHashMap<>(); + Set duplicateFieldNames = new HashSet<>(); + for(QFieldMetaData qFieldMetaData : tableApiFieldList) + { + String effectiveApiFieldName = ApiFieldMetaData.getEffectiveApiFieldName(apiNameVersionAndTableName.apiName(), qFieldMetaData); + if(map.containsKey(effectiveApiFieldName)) + { + duplicateFieldNames.add(effectiveApiFieldName); + } + else + { + map.put(effectiveApiFieldName, qFieldMetaData); + } + } + + if(!duplicateFieldNames.isEmpty()) + { + throw (new QException("The field names [" + duplicateFieldNames + "] appear in this api table more than once. (Do you need to exclude a field that is still in the table, but is also marked as removed?)")); + } + fieldMapCache.put(apiNameVersionAndTableName, map); } diff --git a/qqq-middleware-api/src/main/java/com/kingsrook/qqq/api/model/metadata/tables/ApiTableMetaDataContainer.java b/qqq-middleware-api/src/main/java/com/kingsrook/qqq/api/model/metadata/tables/ApiTableMetaDataContainer.java index daf44695..5a62d1ab 100644 --- a/qqq-middleware-api/src/main/java/com/kingsrook/qqq/api/model/metadata/tables/ApiTableMetaDataContainer.java +++ b/qqq-middleware-api/src/main/java/com/kingsrook/qqq/api/model/metadata/tables/ApiTableMetaDataContainer.java @@ -25,6 +25,14 @@ package com.kingsrook.qqq.api.model.metadata.tables; import java.util.LinkedHashMap; import java.util.Map; import com.kingsrook.qqq.api.ApiSupplementType; +import com.kingsrook.qqq.api.actions.GetTableApiFieldsAction; +import com.kingsrook.qqq.api.model.APIVersion; +import com.kingsrook.qqq.api.model.metadata.ApiInstanceMetaData; +import com.kingsrook.qqq.api.model.metadata.ApiInstanceMetaDataContainer; +import com.kingsrook.qqq.backend.core.context.CapturedContext; +import com.kingsrook.qqq.backend.core.context.QContext; +import com.kingsrook.qqq.backend.core.instances.QInstanceValidator; +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.tables.QSupplementalTableMetaData; import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData; @@ -36,6 +44,8 @@ import com.kingsrook.qqq.backend.core.utils.CollectionUtils; *******************************************************************************/ public class ApiTableMetaDataContainer extends QSupplementalTableMetaData { + private static final QLogger LOG = QLogger.getLogger(ApiTableMetaDataContainer.class); + private Map apis; @@ -172,4 +182,51 @@ public class ApiTableMetaDataContainer extends QSupplementalTableMetaData return (this); } + + + /******************************************************************************* + ** + *******************************************************************************/ + @Override + public void validate(QInstance qInstance, QTableMetaData tableMetaData, QInstanceValidator qInstanceValidator) + { + super.validate(qInstance, tableMetaData, qInstanceValidator); + + //////////////////////////////////////// + // iterate over apis this table is in // + //////////////////////////////////////// + for(String apiName : CollectionUtils.nonNullMap(apis).keySet()) + { + ApiInstanceMetaData apiInstanceMetaData = ApiInstanceMetaDataContainer.of(qInstance).getApis().get(apiName); + + ////////////////////////////////////////////////// + // iterate over supported versions for this api // + ////////////////////////////////////////////////// + for(APIVersion version : apiInstanceMetaData.getSupportedVersions()) + { + CapturedContext capturedContext = QContext.capture(); + try + { + QContext.setQInstance(qInstance); + + /////////////////////////////////////////////////////////////////////////////////////////////////// + // try to get the field-map for this table. note that this will (implicitly) throw an exception // + // if we have the same field name more than once, which can happen if a field is both in the // + // removed-list and the table's normal field list. // + /////////////////////////////////////////////////////////////////////////////////////////////////// + GetTableApiFieldsAction.getTableApiFieldMap(new GetTableApiFieldsAction.ApiNameVersionAndTableName(apiName, version.toString(), tableMetaData.getName())); + } + catch(Exception e) + { + String message = "Error validating ApiTableMetaData for table: " + tableMetaData.getName() + ", api: " + apiName + ", version: " + version; + LOG.warn(message, e); + qInstanceValidator.getErrors().add(message + ": " + e.getMessage()); + } + finally + { + QContext.init(capturedContext); + } + } + } + } }