From bc76a7f66fecc0603fd84c582d4a0711057409ce Mon Sep 17 00:00:00 2001 From: Tim Chamberlain Date: Mon, 12 May 2025 14:49:52 -0500 Subject: [PATCH 1/3] added whitespace behavior and test --- .../metadata/fields/WhiteSpaceBehavior.java | 171 ++++++++++++++ .../fields/WhiteSpaceBehaviorTest.java | 223 ++++++++++++++++++ 2 files changed, 394 insertions(+) create mode 100644 qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/fields/WhiteSpaceBehavior.java create mode 100644 qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/fields/WhiteSpaceBehaviorTest.java diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/fields/WhiteSpaceBehavior.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/fields/WhiteSpaceBehavior.java new file mode 100644 index 00000000..4029315e --- /dev/null +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/fields/WhiteSpaceBehavior.java @@ -0,0 +1,171 @@ +/* + * 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 . + */ + +package com.kingsrook.qqq.backend.core.model.metadata.fields; + + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.function.Function; +import com.kingsrook.qqq.backend.core.actions.values.ValueBehaviorApplier; +import com.kingsrook.qqq.backend.core.model.data.QRecord; +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; + + +/******************************************************************************* + ** Field behavior that changes the whitespace of string values. + *******************************************************************************/ +public enum WhiteSpaceBehavior implements FieldBehavior, FieldBehaviorForFrontend, FieldFilterBehavior +{ + NONE(null), + REMOVE_ALL_WHITESPACE((String s) -> s.chars().filter(c -> !Character.isWhitespace(c)).collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append).toString()); + + + private final Function function; + + + + /******************************************************************************* + ** + *******************************************************************************/ + WhiteSpaceBehavior(Function function) + { + this.function = function; + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Override + public WhiteSpaceBehavior getDefault() + { + return (NONE); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Override + public void apply(ValueBehaviorApplier.Action action, List recordList, QInstance instance, QTableMetaData table, QFieldMetaData field) + { + if(this.equals(NONE)) + { + return; + } + + switch(this) + { + case REMOVE_ALL_WHITESPACE -> applyFunction(recordList, table, field); + default -> throw new IllegalStateException("Unexpected enum value: " + this); + } + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + private void applyFunction(List recordList, QTableMetaData table, QFieldMetaData field) + { + String fieldName = field.getName(); + for(QRecord record : CollectionUtils.nonNullList(recordList)) + { + String value = record.getValueString(fieldName); + if(value != null && function != null) + { + record.setValue(fieldName, function.apply(value)); + } + } + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Override + public Serializable applyToFilterCriteriaValue(Serializable value, QInstance instance, QTableMetaData table, QFieldMetaData field) + { + if(this.equals(NONE) || function == null) + { + return (value); + } + + if(value instanceof String s) + { + String newValue = function.apply(s); + if(!Objects.equals(value, newValue)) + { + return (newValue); + } + } + + return (value); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Override + public boolean allowMultipleBehaviorsOfThisType() + { + return (false); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Override + public List validateBehaviorConfiguration(QTableMetaData tableMetaData, QFieldMetaData fieldMetaData) + { + if(this == NONE) + { + return Collections.emptyList(); + } + + List errors = new ArrayList<>(); + String errorSuffix = " field [" + fieldMetaData.getName() + "] in table [" + tableMetaData.getName() + "]"; + + if(fieldMetaData.getType() != null) + { + if(!fieldMetaData.getType().isStringLike()) + { + errors.add("A WhiteSpaceBehavior was a applied to a non-String-like field:" + errorSuffix); + } + } + + return (errors); + } + +} diff --git a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/fields/WhiteSpaceBehaviorTest.java b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/fields/WhiteSpaceBehaviorTest.java new file mode 100644 index 00000000..5ad4d1c2 --- /dev/null +++ b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/fields/WhiteSpaceBehaviorTest.java @@ -0,0 +1,223 @@ +/* + * 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 . + */ + +package com.kingsrook.qqq.backend.core.model.metadata.fields; + + +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import com.kingsrook.qqq.backend.core.BaseTest; +import com.kingsrook.qqq.backend.core.actions.tables.GetAction; +import com.kingsrook.qqq.backend.core.actions.tables.InsertAction; +import com.kingsrook.qqq.backend.core.actions.tables.QueryAction; +import com.kingsrook.qqq.backend.core.actions.tables.UpdateAction; +import com.kingsrook.qqq.backend.core.actions.values.ValueBehaviorApplier; +import com.kingsrook.qqq.backend.core.context.QContext; +import com.kingsrook.qqq.backend.core.exceptions.QException; +import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput; +import com.kingsrook.qqq.backend.core.model.actions.tables.update.UpdateInput; +import com.kingsrook.qqq.backend.core.model.data.QRecord; +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.TestUtils; +import com.kingsrook.qqq.backend.core.utils.collections.ListBuilder; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + + +/******************************************************************************* + ** Unit test for WhiteSpaceBehavior + *******************************************************************************/ +class WhiteSpaceBehaviorTest extends BaseTest +{ + public static final String FIELD = "firstName"; + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void testNone() + { + assertNull(applyToRecord(WhiteSpaceBehavior.NONE, new QRecord(), ValueBehaviorApplier.Action.INSERT).getValue(FIELD)); + assertNull(applyToRecord(WhiteSpaceBehavior.NONE, new QRecord().withValue(FIELD, null), ValueBehaviorApplier.Action.INSERT).getValue(FIELD)); + assertEquals("John", applyToRecord(WhiteSpaceBehavior.NONE, new QRecord().withValue(FIELD, "John"), ValueBehaviorApplier.Action.INSERT).getValue(FIELD)); + + assertEquals(ListBuilder.of("J. ohn", null, "Jane\n"), applyToRecords(WhiteSpaceBehavior.NONE, List.of( + new QRecord().withValue(FIELD, "J. ohn"), + new QRecord(), + new QRecord().withValue(FIELD, "Jane\n")), + ValueBehaviorApplier.Action.INSERT).stream().map(r -> r.getValueString(FIELD)).toList()); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void testRemoveWhiteSpace() + { + assertNull(applyToRecord(WhiteSpaceBehavior.REMOVE_ALL_WHITESPACE, new QRecord(), ValueBehaviorApplier.Action.INSERT).getValue(FIELD)); + assertNull(applyToRecord(WhiteSpaceBehavior.REMOVE_ALL_WHITESPACE, new QRecord().withValue(FIELD, null), ValueBehaviorApplier.Action.INSERT).getValue(FIELD)); + assertEquals("doobeedoobeedoo", applyToRecord(WhiteSpaceBehavior.REMOVE_ALL_WHITESPACE, new QRecord().withValue(FIELD, "doo bee doo\n bee doo"), ValueBehaviorApplier.Action.INSERT).getValue(FIELD)); + + assertEquals(ListBuilder.of("thisistheway", null, "thatwastheway"), applyToRecords(WhiteSpaceBehavior.REMOVE_ALL_WHITESPACE, List.of( + new QRecord().withValue(FIELD, "this is\rthe way \t"), + new QRecord(), + new QRecord().withValue(FIELD, "that was the way\n")), + ValueBehaviorApplier.Action.INSERT).stream().map(r -> r.getValueString(FIELD)).toList()); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + private QRecord applyToRecord(WhiteSpaceBehavior behavior, QRecord record, ValueBehaviorApplier.Action action) + { + return (applyToRecords(behavior, List.of(record), action).get(0)); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + private List applyToRecords(WhiteSpaceBehavior behavior, List records, ValueBehaviorApplier.Action action) + { + QTableMetaData table = QContext.getQInstance().getTable(TestUtils.TABLE_NAME_PERSON_MEMORY); + behavior.apply(action, records, QContext.getQInstance(), table, table.getField(FIELD)); + return (records); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void testReads() throws QException + { + TestUtils.insertDefaultShapes(QContext.getQInstance()); + + List records = QueryAction.execute(TestUtils.TABLE_NAME_SHAPE, null); + assertEquals(Set.of("Triangle", "Square", "Circle"), records.stream().map(r -> r.getValueString("name")).collect(Collectors.toSet())); + + QFieldMetaData field = QContext.getQInstance().getTable(TestUtils.TABLE_NAME_SHAPE).getField("name"); + field.setBehaviors(Set.of(CaseChangeBehavior.TO_UPPER_CASE)); + + records = QueryAction.execute(TestUtils.TABLE_NAME_SHAPE, null); + assertEquals(Set.of("TRIANGLE", "SQUARE", "CIRCLE"), records.stream().map(r -> r.getValueString("name")).collect(Collectors.toSet())); + + field.setBehaviors(Set.of(CaseChangeBehavior.TO_LOWER_CASE)); + assertEquals("triangle", GetAction.execute(TestUtils.TABLE_NAME_SHAPE, 1).getValueString("name")); + + field.setBehaviors(Set.of(CaseChangeBehavior.NONE)); + assertEquals("Triangle", GetAction.execute(TestUtils.TABLE_NAME_SHAPE, 1).getValueString("name")); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void testWrites() throws QException + { + Integer id = 100; + + QFieldMetaData field = QContext.getQInstance().getTable(TestUtils.TABLE_NAME_SHAPE).getField("name"); + field.setBehaviors(Set.of(CaseChangeBehavior.TO_UPPER_CASE)); + new InsertAction().execute(new InsertInput(TestUtils.TABLE_NAME_SHAPE).withRecord(new QRecord().withValue("id", id).withValue("name", "Octagon"))); + + ////////////////////////////////////////////////////////////////////////////////// + // turn off the to-upper-case behavior, so we'll see what was actually inserted // + ////////////////////////////////////////////////////////////////////////////////// + field.setBehaviors(Collections.emptySet()); + assertEquals("OCTAGON", GetAction.execute(TestUtils.TABLE_NAME_SHAPE, id).getValueString("name")); + + //////////////////////////////////////////// + // change to toLowerCase and do an update // + //////////////////////////////////////////// + field.setBehaviors(Set.of(CaseChangeBehavior.TO_LOWER_CASE)); + new UpdateAction().execute(new UpdateInput(TestUtils.TABLE_NAME_SHAPE).withRecord(new QRecord().withValue("id", id).withValue("name", "Octagon"))); + + //////////////////////////////////////////////////////////////////////////////////// + // turn off the to-lower-case behavior, so we'll see what was actually udpated to // + //////////////////////////////////////////////////////////////////////////////////// + field.setBehaviors(Collections.emptySet()); + assertEquals("octagon", GetAction.execute(TestUtils.TABLE_NAME_SHAPE, id).getValueString("name")); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void testFilter() + { + QInstance qInstance = QContext.getQInstance(); + QTableMetaData table = qInstance.getTable(TestUtils.TABLE_NAME_SHAPE); + QFieldMetaData field = table.getField("name"); + field.setBehaviors(Set.of(CaseChangeBehavior.TO_UPPER_CASE)); + assertEquals("SQUARE", CaseChangeBehavior.TO_UPPER_CASE.applyToFilterCriteriaValue("square", qInstance, table, field)); + + field.setBehaviors(Set.of(CaseChangeBehavior.TO_LOWER_CASE)); + assertEquals("triangle", CaseChangeBehavior.TO_LOWER_CASE.applyToFilterCriteriaValue("Triangle", qInstance, table, field)); + + field.setBehaviors(Set.of(CaseChangeBehavior.NONE)); + assertEquals("Circle", CaseChangeBehavior.NONE.applyToFilterCriteriaValue("Circle", qInstance, table, field)); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void testValidation() + { + QTableMetaData table = QContext.getQInstance().getTable(TestUtils.TABLE_NAME_SHAPE); + + /////////////////////////////////////////// + // should be no errors on a string field // + /////////////////////////////////////////// + assertTrue(CaseChangeBehavior.TO_UPPER_CASE.validateBehaviorConfiguration(table, table.getField("name")).isEmpty()); + + ////////////////////////////////////////// + // should be an error on a number field // + ////////////////////////////////////////// + assertEquals(1, CaseChangeBehavior.TO_LOWER_CASE.validateBehaviorConfiguration(table, table.getField("id")).size()); + + ///////////////////////////////////////// + // NONE should be allowed on any field // + ///////////////////////////////////////// + assertTrue(CaseChangeBehavior.NONE.validateBehaviorConfiguration(table, table.getField("id")).isEmpty()); + } + +} From 2491523a6be178baa5b72c5f6d7141fa500888ae Mon Sep 17 00:00:00 2001 From: Tim Chamberlain Date: Tue, 13 May 2025 10:15:41 -0500 Subject: [PATCH 2/3] added more whitespace behaviors (trims) --- .../metadata/fields/WhiteSpaceBehavior.java | 7 ++- .../fields/WhiteSpaceBehaviorTest.java | 59 ++++++++++++++++++- 2 files changed, 63 insertions(+), 3 deletions(-) diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/fields/WhiteSpaceBehavior.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/fields/WhiteSpaceBehavior.java index 4029315e..3beaf3d1 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/fields/WhiteSpaceBehavior.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/fields/WhiteSpaceBehavior.java @@ -41,7 +41,10 @@ import com.kingsrook.qqq.backend.core.utils.CollectionUtils; public enum WhiteSpaceBehavior implements FieldBehavior, FieldBehaviorForFrontend, FieldFilterBehavior { NONE(null), - REMOVE_ALL_WHITESPACE((String s) -> s.chars().filter(c -> !Character.isWhitespace(c)).collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append).toString()); + REMOVE_ALL_WHITESPACE((String s) -> s.chars().filter(c -> !Character.isWhitespace(c)).collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append).toString()), + TRIM((String s) -> s.trim()), + TRIM_LEFT((String s) -> s.stripLeading()), + TRIM_RIGHT((String s) -> s.stripTrailing()); private final Function function; @@ -82,7 +85,7 @@ public enum WhiteSpaceBehavior implements FieldBehavior, Fie switch(this) { - case REMOVE_ALL_WHITESPACE -> applyFunction(recordList, table, field); + case REMOVE_ALL_WHITESPACE, TRIM, TRIM_LEFT, TRIM_RIGHT -> applyFunction(recordList, table, field); default -> throw new IllegalStateException("Unexpected enum value: " + this); } } diff --git a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/fields/WhiteSpaceBehaviorTest.java b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/fields/WhiteSpaceBehaviorTest.java index 5ad4d1c2..60c2e30a 100644 --- a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/fields/WhiteSpaceBehaviorTest.java +++ b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/fields/WhiteSpaceBehaviorTest.java @@ -94,6 +94,63 @@ class WhiteSpaceBehaviorTest extends BaseTest + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void testTrimWhiteSpace() + { + assertNull(applyToRecord(WhiteSpaceBehavior.TRIM, new QRecord(), ValueBehaviorApplier.Action.INSERT).getValue(FIELD)); + assertNull(applyToRecord(WhiteSpaceBehavior.TRIM, new QRecord().withValue(FIELD, null), ValueBehaviorApplier.Action.INSERT).getValue(FIELD)); + assertEquals("doo bee doo\n bee doo", applyToRecord(WhiteSpaceBehavior.TRIM, new QRecord().withValue(FIELD, " doo bee doo\n bee doo\r \n\n"), ValueBehaviorApplier.Action.INSERT).getValue(FIELD)); + + assertEquals(ListBuilder.of("this is\rthe way", null, "that was the way"), applyToRecords(WhiteSpaceBehavior.TRIM, List.of( + new QRecord().withValue(FIELD, " this is\rthe way \t"), + new QRecord(), + new QRecord().withValue(FIELD, "that was the way\n")), + ValueBehaviorApplier.Action.INSERT).stream().map(r -> r.getValueString(FIELD)).toList()); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void testTrimLeftWhiteSpace() + { + assertNull(applyToRecord(WhiteSpaceBehavior.TRIM_LEFT, new QRecord(), ValueBehaviorApplier.Action.INSERT).getValue(FIELD)); + assertNull(applyToRecord(WhiteSpaceBehavior.TRIM_LEFT, new QRecord().withValue(FIELD, null), ValueBehaviorApplier.Action.INSERT).getValue(FIELD)); + assertEquals("doo bee doo\n bee doo\r \n\n", applyToRecord(WhiteSpaceBehavior.TRIM_LEFT, new QRecord().withValue(FIELD, " doo bee doo\n bee doo\r \n\n"), ValueBehaviorApplier.Action.INSERT).getValue(FIELD)); + + assertEquals(ListBuilder.of("this is\rthe way \t", null, "that was the way\n"), applyToRecords(WhiteSpaceBehavior.TRIM_LEFT, List.of( + new QRecord().withValue(FIELD, " this is\rthe way \t"), + new QRecord(), + new QRecord().withValue(FIELD, " \n that was the way\n")), + ValueBehaviorApplier.Action.INSERT).stream().map(r -> r.getValueString(FIELD)).toList()); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void testTrimRightWhiteSpace() + { + assertNull(applyToRecord(WhiteSpaceBehavior.TRIM_RIGHT, new QRecord(), ValueBehaviorApplier.Action.INSERT).getValue(FIELD)); + assertNull(applyToRecord(WhiteSpaceBehavior.TRIM_RIGHT, new QRecord().withValue(FIELD, null), ValueBehaviorApplier.Action.INSERT).getValue(FIELD)); + assertEquals(" doo bee doo\n bee doo", applyToRecord(WhiteSpaceBehavior.TRIM_RIGHT, new QRecord().withValue(FIELD, " doo bee doo\n bee doo\r \n\n"), ValueBehaviorApplier.Action.INSERT).getValue(FIELD)); + + assertEquals(ListBuilder.of(" this is\rthe way", null, " \n that was the way"), applyToRecords(WhiteSpaceBehavior.TRIM_RIGHT, List.of( + new QRecord().withValue(FIELD, " this is\rthe way \t"), + new QRecord(), + new QRecord().withValue(FIELD, " \n that was the way\n")), + ValueBehaviorApplier.Action.INSERT).stream().map(r -> r.getValueString(FIELD)).toList()); + } + + + /******************************************************************************* ** *******************************************************************************/ @@ -167,7 +224,7 @@ class WhiteSpaceBehaviorTest extends BaseTest new UpdateAction().execute(new UpdateInput(TestUtils.TABLE_NAME_SHAPE).withRecord(new QRecord().withValue("id", id).withValue("name", "Octagon"))); //////////////////////////////////////////////////////////////////////////////////// - // turn off the to-lower-case behavior, so we'll see what was actually udpated to // + // turn off the to-lower-case behavior, so we'll see what was actually updated to // //////////////////////////////////////////////////////////////////////////////////// field.setBehaviors(Collections.emptySet()); assertEquals("octagon", GetAction.execute(TestUtils.TABLE_NAME_SHAPE, id).getValueString("name")); From 32fde00b960d17ed8ca66567b478b21c2c3a5180 Mon Sep 17 00:00:00 2001 From: Tim Chamberlain Date: Thu, 15 May 2025 12:56:10 -0500 Subject: [PATCH 3/3] updates to check versions on process query params --- .../qqq/api/actions/ApiFieldUtils.java | 106 ++++++++++++++++++ .../actions/GenerateOpenApiSpecAction.java | 31 ++--- .../api/actions/GetTableApiFieldsAction.java | 75 +------------ 3 files changed, 125 insertions(+), 87 deletions(-) create mode 100644 qqq-middleware-api/src/main/java/com/kingsrook/qqq/api/actions/ApiFieldUtils.java diff --git a/qqq-middleware-api/src/main/java/com/kingsrook/qqq/api/actions/ApiFieldUtils.java b/qqq-middleware-api/src/main/java/com/kingsrook/qqq/api/actions/ApiFieldUtils.java new file mode 100644 index 00000000..79235273 --- /dev/null +++ b/qqq-middleware-api/src/main/java/com/kingsrook/qqq/api/actions/ApiFieldUtils.java @@ -0,0 +1,106 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2023. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.kingsrook.qqq.api.actions; + + +import com.kingsrook.qqq.api.model.APIVersionRange; +import com.kingsrook.qqq.api.model.metadata.fields.ApiFieldMetaData; +import com.kingsrook.qqq.api.model.metadata.fields.ApiFieldMetaDataContainer; +import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData; +import com.kingsrook.qqq.backend.core.utils.ObjectUtils; +import com.kingsrook.qqq.backend.core.utils.StringUtils; +import org.apache.commons.lang.BooleanUtils; + + +/******************************************************************************* + ** utility methods for working with fields + ** + *******************************************************************************/ +public class ApiFieldUtils +{ + + + /******************************************************************************* + ** + *******************************************************************************/ + public static boolean isIncluded(String apiName, QFieldMetaData field) + { + ApiFieldMetaData apiFieldMetaData = getApiFieldMetaData(apiName, field); + if(apiFieldMetaData != null && BooleanUtils.isTrue(apiFieldMetaData.getIsExcluded())) + { + return (false); + } + + return (true); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + public static APIVersionRange getApiVersionRangeForRemovedField(String apiName, QFieldMetaData field) + { + ApiFieldMetaData apiFieldMetaData = getApiFieldMetaData(apiName, field); + if(apiFieldMetaData != null && apiFieldMetaData.getInitialVersion() != null) + { + if(StringUtils.hasContent(apiFieldMetaData.getFinalVersion())) + { + return (APIVersionRange.betweenAndIncluding(apiFieldMetaData.getInitialVersion(), apiFieldMetaData.getFinalVersion())); + } + else + { + throw (new IllegalStateException("RemovedApiFieldMetaData for field [" + field.getName() + "] did not specify a finalVersion.")); + } + } + else + { + throw (new IllegalStateException("RemovedApiFieldMetaData for field [" + field.getName() + "] did not specify an initialVersion.")); + } + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + public static APIVersionRange getApiVersionRange(String apiName, QFieldMetaData field) + { + ApiFieldMetaData apiFieldMetaData = getApiFieldMetaData(apiName, field); + if(apiFieldMetaData != null && apiFieldMetaData.getInitialVersion() != null) + { + return (APIVersionRange.afterAndIncluding(apiFieldMetaData.getInitialVersion())); + } + + return (APIVersionRange.none()); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + public static ApiFieldMetaData getApiFieldMetaData(String apiName, QFieldMetaData field) + { + return ObjectUtils.tryAndRequireNonNullElse(() -> ApiFieldMetaDataContainer.of(field).getApiFieldMetaData(apiName), new ApiFieldMetaData()); + } +} diff --git a/qqq-middleware-api/src/main/java/com/kingsrook/qqq/api/actions/GenerateOpenApiSpecAction.java b/qqq-middleware-api/src/main/java/com/kingsrook/qqq/api/actions/GenerateOpenApiSpecAction.java index 247242b1..c6eda4c5 100644 --- a/qqq-middleware-api/src/main/java/com/kingsrook/qqq/api/actions/GenerateOpenApiSpecAction.java +++ b/qqq-middleware-api/src/main/java/com/kingsrook/qqq/api/actions/GenerateOpenApiSpecAction.java @@ -111,7 +111,7 @@ public class GenerateOpenApiSpecAction extends AbstractQActionFunction tags) + private Path generateProcessSpecPathObject(ApiInstanceMetaData apiInstanceMetaData, ApiProcessMetaData apiProcessMetaData, QProcessMetaData processMetaData, List tags, APIVersion apiVersion) { String description = apiProcessMetaData.getDescription(); if(!StringUtils.hasContent(description)) @@ -927,7 +927,10 @@ public class GenerateOpenApiSpecAction extends AbstractQActionFunction ApiFieldMetaDataContainer.of(field).getApiFieldMetaData(apiName), new ApiFieldMetaData()); - } - - - /******************************************************************************* ** *******************************************************************************/