214 empty lists fixes

This commit is contained in:
2026-03-14 14:08:21 +03:00
parent aff2416baa
commit 4f624b06c4
8 changed files with 73 additions and 29 deletions
+1 -1
View File
@@ -57,7 +57,7 @@
//variables.framework.docs={};
variables.framework.docs.APIName="svc-api";
variables.framework.docs.APIVersion="0.213"; /*$ git config --global --unset user.password*/
variables.framework.docs.APIVersion="0.214"; /*$ git config --global --unset user.password*/
variables.framework.globalHeaders = structNew();
variables.framework.globalHeaders["Access-Control-Expose-Headers"] = "Location";
+8 -6
View File
@@ -18,7 +18,8 @@
<cfargument name="value" type="any" required="true" />
<cfif isEmpty(ARGUMENTS.value)><!---*** некорректно, но просто, пустые строки превращает в нулл--->
<cfif isSimpleValue(ARGUMENTS.value) AND isEmpty(ARGUMENTS.value)><!---*** некорректно, но просто, пустые строки превращает в нулл--->
<!--- нам не нужно, чтобы пустые массивы превращались в нулл. Наверное, и структуры тоже --->
<cfreturn javacast('null','')/>
<cfelse>
<cfreturn ARGUMENTS.value />
@@ -71,12 +72,13 @@
<cfif queryColumnExists(ARGUMENTS.query, local.col)>
<cfif type EQ "list">
<!--- *** workaround for empty lists - keep them empty instead of null - should designate field type as list --->
<cfset obj[ARGUMENTS.fieldNameDecorator(local.col)]=formatter(ARGUMENTS.query[local.col][ARGUMENTS.query.currentRow])/>
<cfelse>
<!--- <cfif type EQ "list"> --->
<!--- *** workaround for empty lists - keep them empty strings or arrays instead of null - should designate field type as list --->
<!--- *** правда, для CFS параметров это не работает - тип поля может меняться в зависимости от условий --->
<!--- <cfset obj[ARGUMENTS.fieldNameDecorator(local.col)]=formatter(ARGUMENTS.query[local.col][ARGUMENTS.query.currentRow])/>
<cfelse> --->
<cfset obj[ARGUMENTS.fieldNameDecorator(local.col)]=empty2null(formatter(ARGUMENTS.query[local.col][ARGUMENTS.query.currentRow]))/>
</cfif>
<!--- </cfif> --->
<!--- *** преобразование пустой строки в null преобразует в нулл также пустые списки, что искажает факт --->
</cfif>
<!---*** не уверен в надежности конструкции во всех реализациях CF, контекст query передастся ли--->
+1 -3
View File
@@ -76,15 +76,13 @@
<cfset "out.aruments"=#arguments#/>
<cfset "out.arпuments"=#arguments#/>
<cfset "out.args"=#args#/>
<cfset "out.results"=#local.value_list#/>
<cfset "out.spec"=[]/>
<cfloop query=#local.qSpec#>
<!--- <cfset local.qCfsParam.default_value = computeDefault(local.qCfsParam.default_compute, local.qCfsParam.default_value, qSvcOperation.svc_id, arguments.usrId)/> --->
<cfset var rec = this.helper.appendRecord(structNew("linked"), "", local.specTitleMap, local.qSpec, this.helper.snake2camel)/>
<cfset arrayAppend(out.spec, rec)/>
</cfloop>
+18 -7
View File
@@ -141,9 +141,15 @@
<m:field>sop.label</m:field>
<m:field>sop.data_type</m:field>
<m:field>null as data_descriptor</m:field>
<m:field formatter=#function(x){return listToArray(x);}# type="list">sop.value_list</m:field>
<m:field formatter=#(x)=>((isArray(x) OR isEmpty(x))? x : listToArray(x))#>sop.value_list</m:field>
<m:field>sop.ref_svc_id</m:field>
<m:field>sop.func</m:field>
<m:field>sop.nested_ref</m:field>
<m:field>sop.state_path</m:field>
<m:field>sop.expression</m:field>
<m:field>sop.depends_on_cfs_params</m:field>
<m:field formatter=#request.castToBool#>sop.is_required</m:field>
<m:field>sop.default_value</m:field>
<m:field>sop.regex</m:field>
@@ -155,13 +161,12 @@
<m:field>sop.descr</m:field>
<m:field>sop.man</m:field>
<m:field>sop.sort</m:field>
<m:field>iop.note</m:field>
<m:field>sop.nested_ref</m:field>
<m:field>iop.note</m:field>
<m:field>sop.config::text as config</m:field>
<m:field>null as nested_ref_data</m:field><!--- placeholder for future data --->
<m:field>sop.state_path</m:field>
<m:field>sop.depends_on_cfs_params</m:field>
<m:field>sop.expression</m:field>
<m:field formatter=#request.castToBool#>sop.is_sensitive</m:field>
</m:field_set>
from svc_operation_cfs_param sop
@@ -219,7 +224,13 @@
}
)
/>
</cfif>
</cfif>
<cfif (len(local.qCfsParam.func) OR len(local.qCfsParam.expression) OR len(local.qCfsParam.state_path) OR len(local.qCfsParam.nested_ref))
AND len(local.qCfsParam.value_list) EQ 0>
<cfset local.qCfsParam.value_list = []/>
</cfif>
<!--- *** боюсь, где-то тут нужно будет делать вычисления субпараметров --->
<cfif data_type EQ "map" OR data_type EQ "map-fixed" OR data_type EQ "array-map-fixed">
<cfinvoke component="instance_operation_cfs_param" method="processMap" qParam=#local.qCfsParam#/>
+13 -4
View File
@@ -467,15 +467,19 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
<m:field>sop.svc_operation_cfs_param</m:field>
<m:field>sop.data_type</m:field>
<m:field>null as data_descriptor</m:field>
<m:field formatter=#function(x){return listToArray(x);}# type="list">sop.value_list</m:field>
<m:field formatter=#(x)=>((isArray(x) OR isEmpty(x))? x : listToArray(x))#>sop.value_list</m:field>
<m:field>u.login as creator_login</m:field>
<m:field>u.shortname as creator_shortname</m:field>
<m:field formatter=#request.castToBool#>sop.is_sensitive</m:field>
<m:field>sop.man</m:field>
<m:field>sop.func</m:field>
<m:field>sop.nested_ref</m:field>
<m:field>sop.config::text as config</m:field>
<m:field>sop.expression</m:field>
<m:field>sop.nested_ref</m:field>
<m:field>sop.state_path</m:field>
<m:field>sop.depends_on_cfs_params</m:field>
<m:field>sop.config::text as config</m:field>
<m:field>e.service_id</m:field>
<m:field>e.instance_uid::text as instance_uid</m:field>
</m:field_set>
@@ -522,7 +526,12 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
<cfcatch type="ANY"></cfcatch>
</cftry>
<cfset local.qCfsParam.value_list = getListFromState(currentState, local.qCfsParam.state_path)/>
</cfif>
</cfif>
<cfif (len(local.qCfsParam.func) OR len(local.qCfsParam.expression) OR len(local.qCfsParam.state_path) OR len(local.qCfsParam.nested_ref))
AND len(local.qCfsParam.value_list) EQ 0>
<cfset local.qCfsParam.value_list = []/>
</cfif>
<cfif local.qCfsParam.data_type EQ "map" OR local.qCfsParam.data_type EQ "map-fixed" OR local.qCfsParam.data_type EQ "array-map-fixed">
<cfset processMap(local.qCfsParam)/><!--- query passed by reference --->
@@ -88,11 +88,16 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
<m:field>sop.sort</m:field>
<m:field formatter=#request.castToBool#>sop.is_sensitive</m:field>
<m:field>sop.data_type</m:field>
<m:field formatter=#function(x){return listToArray(x);}#>sop.value_list</m:field>
<m:field formatter=#(x)=>((isArray(x) OR isEmpty(x))? x : listToArray(x))#>sop.value_list</m:field>
<m:field>sop.default_value</m:field>
<m:field>sop.func</m:field>
<m:field>sop.man</m:field>
<m:field>sop.func</m:field>
<m:field>p.state_path</m:field>
<m:field>p.nested_ref</m:field>
<m:field>p.expression</m:field>
<m:field>sop.depends_on_cfs_params</m:field>
<m:field>sop.man</m:field>
<m:field>null as data_descriptor</m:field>
<m:field>e.service_id</m:field>
</m:field_set>
@@ -126,6 +131,10 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
<!--- <cfset local.qCfsParam.value_list=generateValueList(argumentCollection=#args#)/> --->
<cfinvoke component="instance_operation_cfs_param" method="generateValueList" argumentCollection=#args# returnVariable="local.qCfsParam.value_list"/><!--- *** тут засада с форматом списка: массив или лист --->
<!--- можно перечислить именованные аргументы обычным порядком, но с коллекцией потенциально более гибко --->
<cfif (len(local.qCfsParam.func) OR len(local.qCfsParam.expression) OR len(local.qCfsParam.state_path) OR len(local.qCfsParam.nested_ref))
AND len(local.qCfsParam.value_list) EQ 0>
<cfset local.qCfsParam.value_list = []/>
</cfif>
<cfif len(trim(local.qCfsParam.value_list)) AND listLen(local.qCfsParam.value_list) EQ 1>
<cfset local.qCfsParam.default_value=local.qCfsParam.value_list/>
</cfif>
+12 -4
View File
@@ -74,8 +74,9 @@
<m:field>p.svc_operation_cfs_param</m:field>
<m:field>p.label</m:field>
<m:field>p.data_type</m:field>
<m:field>null as data_descriptor</m:field>
<m:field formatter=#function(x){return listToArray(x);}# type="list">p.value_list</m:field>
<m:field>null as data_descriptor</m:field>
<!--- стоит помнить, что formatter выполняется при окончательном форматировании резалтсета в json --->
<m:field formatter=#(x)=>((isArray(x) OR isEmpty(x))? x : listToArray(x))#> p.value_list</m:field><!--- ниже мы обрабатываем резалтсет и в случае, когда подразумевается список, заменяем пустое значение пустым массивом, который интерпретируется как пустой список (по крайней мере не пользуемся специальным текстовым значением) --->
<m:field <!--- formatter=#function(x){return listToArray(generateValueList(x));}# --->>p.func</m:field><!--- *** отчаявшись сделать красиво --->
<m:field>p.ref_svc_id</m:field>
<m:field formatter=#request.castToBool#>p.is_required</m:field>
@@ -149,8 +150,12 @@
argumentCollection=#args#
returnVariable="local.qCfsParam.value_list"
/>
</cfif>
</cfif>
<cfif (len(local.qCfsParam.func) OR len(local.qCfsParam.expression) OR len(local.qCfsParam.state_path) OR len(local.qCfsParam.nested_ref))
AND len(local.qCfsParam.value_list) EQ 0>
<cfset local.qCfsParam.value_list = []/>
</cfif>
<cfif data_type EQ "map" OR data_type EQ "map-fixed" OR data_type EQ "array-map-fixed"><!--- *** частичное дублирование с instance_operation_cfs_param.processMap --->
<!--- без полей инстанса, только шаблон --->
@@ -209,7 +214,9 @@
</cfif><!---/map --->
</cfloop>
<cfset queryDeleteColumn(local.qCfsParam, "func")/>
<!--- <cfdump var=#local.qCfsParam# abort=true/> --->
<!--- <cfset queryDeleteColumn(local.qCfsParam, "func")/> --->
<cfset var out=structNew("linked")/>
<cfset "out.queryDurationMs"=getTickCount() - request.startTickCount/>
@@ -233,6 +240,7 @@
</cfif>
<cfset var rec = this.helper.appendRecord(structNew("linked"), "", local.cfsParamMap, local.qCfsParam, this.helper.snake2camel)/>
<!--- <cfdump var=#rec# abort=true/> --->
<cfset arrayAppend(out.svcOperation.cfsParams, rec)/>
</cfloop>
+8 -1
View File
@@ -36,12 +36,15 @@
<m:field>p.svc_operation_cfs_param</m:field>
<m:field>p.label</m:field>
<m:field>p.data_type</m:field>
<m:field formatter=#function(x){return listToArray(x);}# type="list">p.value_list</m:field>
<m:field formatter=#(x)=>((isArray(x) OR isEmpty(x))? x : listToArray(x))#>p.value_list</m:field>
<m:field>p.ref_svc_id</m:field>
<m:field formatter=#request.castToBool#>p.is_required</m:field>
<m:field>p.default_value</m:field><!--- can be overridden bu default_compute --->
<m:field>p.default_compute</m:field>
<m:field>p.func</m:field>
<m:field>p.expression</m:field>
<m:field>p.state_path</m:field>
<m:field>p.nested_ref</m:field>
<m:field>p.regex</m:field>
<m:field>p.unique_scope</m:field>
<m:field>p.maxlength</m:field>
@@ -82,6 +85,10 @@
<cfset "out.svcOperation.cfsParams"=[]/>
<cfloop query=#local.qCfsParam#>
<cfif (len(local.qCfsParam.func) OR len(local.qCfsParam.expression) OR len(local.qCfsParam.state_path) OR len(local.qCfsParam.nested_ref))
AND len(local.qCfsParam.value_list) EQ 0>
<cfset local.qCfsParam.value_list = []/>
</cfif>
<cfset arrayAppend(out.svcOperation.cfsParams, this.helper.appendRecord(structNew("linked"), "", local.cfsParamMap, local.qCfsParam, this.helper.snake2camel))/>
</cfloop>