From 79bc7dfecdc1b75912522c0c8bb15aad9defdd30 Mon Sep 17 00:00:00 2001 From: Darin Kelkhoff Date: Mon, 14 Jul 2025 16:27:26 -0500 Subject: [PATCH] Refactor new method setValueFromApiFieldInQRecord out of apiJsonObjectToQRecord for smaller use-case of similar nature --- .../qqq/api/actions/QRecordApiAdapter.java | 101 +++++++++++------- .../api/actions/QRecordApiAdapterTest.java | 19 +++- 2 files changed, 81 insertions(+), 39 deletions(-) diff --git a/qqq-middleware-api/src/main/java/com/kingsrook/qqq/api/actions/QRecordApiAdapter.java b/qqq-middleware-api/src/main/java/com/kingsrook/qqq/api/actions/QRecordApiAdapter.java index 3148aea4..f2a28d32 100644 --- a/qqq-middleware-api/src/main/java/com/kingsrook/qqq/api/actions/QRecordApiAdapter.java +++ b/qqq-middleware-api/src/main/java/com/kingsrook/qqq/api/actions/QRecordApiAdapter.java @@ -294,44 +294,7 @@ public class QRecordApiAdapter //////////////////////////////////////////////// if(apiFieldsMap.containsKey(jsonKey)) { - QFieldMetaData field = apiFieldsMap.get(jsonKey); - Object value = jsonObject.isNull(jsonKey) ? null : jsonObject.get(jsonKey); - - if(field.getType().equals(QFieldType.BLOB) && value instanceof String s) - { - value = Base64.getDecoder().decode(s); - } - - //////////////////////////////////////////////////////////////////////////////////////////////////////// - // generally, omit non-editable fields - // - // however - if we're asked to include the primary key (and this is the primary key), then include it // - //////////////////////////////////////////////////////////////////////////////////////////////////////// - if(!field.getIsEditable()) - { - if(includeNonEditableFields) - { - LOG.trace("Even though field [" + field.getName() + "] is not editable, we'll use it, because we've been asked to include non-editable fields"); - } - else - { - continue; - } - } - - ApiFieldMetaData apiFieldMetaData = ObjectUtils.tryAndRequireNonNullElse(() -> ApiFieldMetaDataContainer.of(field).getApiFieldMetaData(apiName), new ApiFieldMetaData()); - if(StringUtils.hasContent(apiFieldMetaData.getReplacedByFieldName())) - { - qRecord.setValue(apiFieldMetaData.getReplacedByFieldName(), value); - } - else if(apiFieldMetaData.getCustomValueMapper() != null) - { - ApiFieldCustomValueMapper customValueMapper = QCodeLoader.getAdHoc(ApiFieldCustomValueMapper.class, apiFieldMetaData.getCustomValueMapper()); - customValueMapper.consumeApiValue(qRecord, value, jsonObject, jsonKey); - } - else - { - qRecord.setValue(field.getName(), value); - } + setValueFromApiFieldInQRecord(jsonObject, jsonKey, apiName, apiFieldsMap, qRecord, includeNonEditableFields); } else if(associationMap.containsKey(jsonKey)) { @@ -404,6 +367,68 @@ public class QRecordApiAdapter + /*************************************************************************** + * + ***************************************************************************/ + public static void setValueFromApiFieldInQRecord(JSONObject apiObject, String apiFieldName, String apiName, Map apiFieldsMap, QRecord qRecord, boolean includeNonEditableFields) throws QException + { + QFieldMetaData field = apiFieldsMap.get(apiFieldName); + if(field == null) + { + throw (new QException("Unrecognized apiFieldName: " + apiFieldName)); + } + + ///////////////////////////////////////////////////////////////////////////////////// + // generally, omit non-editable fields, unless the param to include them is given. // + ///////////////////////////////////////////////////////////////////////////////////// + if(!field.getIsEditable()) + { + if(includeNonEditableFields) + { + LOG.trace("Even though field [" + field.getName() + "] is not editable, we'll use it, because we've been asked to include non-editable fields"); + } + else + { + return; + } + } + + /////////////////////////////////////// + // get the value from the api object // + /////////////////////////////////////// + Object value = apiObject.isNull(apiFieldName) ? null : apiObject.get(apiFieldName); + if(field.getType().equals(QFieldType.BLOB) && value instanceof String s) + { + value = Base64.getDecoder().decode(s); + } + + ApiFieldMetaData apiFieldMetaData = ObjectUtils.tryAndRequireNonNullElse(() -> ApiFieldMetaDataContainer.of(field).getApiFieldMetaData(apiName), new ApiFieldMetaData()); + if(StringUtils.hasContent(apiFieldMetaData.getReplacedByFieldName())) + { + /////////////////////////////////////////////////////////////// + // if field was replaced, then set OLD field name in QRecord // + /////////////////////////////////////////////////////////////// + qRecord.setValue(apiFieldMetaData.getReplacedByFieldName(), value); + } + else if(apiFieldMetaData.getCustomValueMapper() != null) + { + /////////////////////////////////////////////////////////// + // if a custom value mapper is to be used, then do so... // + /////////////////////////////////////////////////////////// + ApiFieldCustomValueMapper customValueMapper = QCodeLoader.getAdHoc(ApiFieldCustomValueMapper.class, apiFieldMetaData.getCustomValueMapper()); + customValueMapper.consumeApiValue(qRecord, value, apiObject, apiFieldName); + } + else + { + ////////////////////////////////////////////////////// + // else, default case, set the value in the qrecord // + ////////////////////////////////////////////////////// + qRecord.setValue(field.getName(), value); + } + } + + + /******************************************************************************* ** *******************************************************************************/ diff --git a/qqq-middleware-api/src/test/java/com/kingsrook/qqq/api/actions/QRecordApiAdapterTest.java b/qqq-middleware-api/src/test/java/com/kingsrook/qqq/api/actions/QRecordApiAdapterTest.java index 387806d2..efb819ce 100644 --- a/qqq-middleware-api/src/test/java/com/kingsrook/qqq/api/actions/QRecordApiAdapterTest.java +++ b/qqq-middleware-api/src/test/java/com/kingsrook/qqq/api/actions/QRecordApiAdapterTest.java @@ -32,6 +32,7 @@ import com.kingsrook.qqq.api.TestUtils; import com.kingsrook.qqq.api.javalin.QBadRequestException; import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.model.data.QRecord; +import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData; import com.kingsrook.qqq.backend.core.utils.ValueUtils; import org.json.JSONObject; import org.junit.jupiter.api.Test; @@ -206,7 +207,6 @@ class QRecordApiAdapterTest extends BaseTest """), TestUtils.TABLE_NAME_PERSON, TestUtils.API_NAME, TestUtils.V2023_Q1, true); assertTrue(recordWithoutNonEditablePrimaryKeyFields.getValues().containsKey("createDate")); assertEquals(256, recordWithoutNonEditablePrimaryKeyFields.getValues().get("id")); - } @@ -265,4 +265,21 @@ class QRecordApiAdapterTest extends BaseTest } } + + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void testSetValueFromApiFieldInQRecord() throws QException + { + QRecord record = new QRecord(); + Map apiFieldsMap = GetTableApiFieldsAction.getTableApiFieldMap(new GetTableApiFieldsAction.ApiNameVersionAndTableName(TestUtils.API_NAME, TestUtils.V2022_Q4, TestUtils.TABLE_NAME_PERSON)); + JSONObject apiObject = new JSONObject(Map.of("shoeCount", 2, "firstName", "Tim")); + QRecordApiAdapter.setValueFromApiFieldInQRecord(apiObject, "firstName", TestUtils.API_NAME, apiFieldsMap, record, false); + QRecordApiAdapter.setValueFromApiFieldInQRecord(apiObject, "shoeCount", TestUtils.API_NAME, apiFieldsMap, record, false); + assertEquals("Tim", record.getValueString("firstName")); + assertEquals(2, record.getValueInteger("noOfShoes")); + } + } \ No newline at end of file