172 instance_operation_ls paging bug fix

This commit is contained in:
2025-11-20 14:58:43 +03:00
parent 210560d973
commit 503df018aa
4 changed files with 68 additions and 30 deletions
+1 -1
View File
@@ -51,7 +51,7 @@
//variables.framework.docs={}; //variables.framework.docs={};
variables.framework.docs.APIName="svc-api"; variables.framework.docs.APIName="svc-api";
variables.framework.docs.APIVersion="0.171"; /*$ git config --global --unset user.password*/ variables.framework.docs.APIVersion="0.172"; /*$ git config --global --unset user.password*/
variables.framework.globalHeaders = structNew(); variables.framework.globalHeaders = structNew();
variables.framework.globalHeaders["Access-Control-Expose-Headers"] = "Location"; variables.framework.globalHeaders["Access-Control-Expose-Headers"] = "Location";
+16 -2
View File
@@ -1,6 +1,7 @@
<!--- version 2.01---><!---15:25 31.01.2019---> <!--- version 2.01---><!---15:25 31.01.2019--->
<!--- version 3---><!---16:42 16.11.2020---> <!--- version 3---><!---16:42 16.11.2020--->
<!--- version 4---><!---2025-09-06 19:15:50 больше не нужно объявлять параметр как list, достаточно оператора IN---> <!--- version 4---><!---2025-09-06 19:15:50 больше не нужно объявлять параметр как list, достаточно оператора IN--->
<!--- version 5---><!---2025-11-20 ILIKE - потеря совместимости со стандартным SQL (можно вернуться к совместимости через lower, но будут проблемы с индексами)--->
<!--- build query filter string ---> <!--- build query filter string --->
<cfparam name="ATTRIBUTES.filter" type="struct"/> <cfparam name="ATTRIBUTES.filter" type="struct"/>
@@ -23,8 +24,21 @@
---><cfif i LT #len#><cfqueryparam cfsqltype="#getCfSqLType(fltr.ftype)#" list="#fltr.list#" value="#fltr.prefix##fltr.val##fltr.suffix#"/></cfif><!--- ---><cfif i LT #len#><cfqueryparam cfsqltype="#getCfSqLType(fltr.ftype)#" list="#fltr.list#" value="#fltr.prefix##fltr.val##fltr.suffix#"/></cfif><!---
---></cfloop><!--- ---></cfloop><!---
---><cfelse><!--- ---><cfelse><!---
---><cfoutput>#fltr.field#</cfoutput><cfswitch expression=#uCase(fltr.compare)#><cfcase value="EQ"> = </cfcase><cfcase value="NE,NEQ"> <> </cfcase><cfcase value="LE,LTE"> <= </cfcase><cfcase value="LT"> < </cfcase><cfcase value="GE,GTE"> >= </cfcase><cfcase value="GT"> > </cfcase><cfcase value="LIKE"> LIKE </cfcase><cfcase value="LIKE%,LIKEP"> LIKE <cfqueryparam cfsqltype=#getCfSqLType(fltr.ftype)# value="%#fltr.val#%"/><cfcontinue/></cfcase><cfcase value="IN"> IN (<cfqueryparam cfsqltype=#getCfSqLType(fltr.ftype)# list=true value="#fltr.val#"/>)<cfcontinue/></cfcase><cfdefaultcase> = <cfoutput> #fltr.field#</cfoutput><cfcontinue/><!---***криво---></cfdefaultcase></cfswitch><cfqueryparam cfsqltype=#getCfSqLType(fltr.ftype)# value="#fltr.val#"/><cfcontinue/> ---><cfoutput>#fltr.field#</cfoutput><cfswitch expression=#uCase(fltr.compare)#>
</cfif> <cfcase value="EQ"> = </cfcase><!---
---><cfcase value="NE,NEQ"> <> </cfcase><!---
---><cfcase value="LE,LTE"> <= </cfcase><!---
---><cfcase value="LT"> < </cfcase><!---
---><cfcase value="GE,GTE"> >= </cfcase><!---
---><cfcase value="GT"> > </cfcase><!---
---><cfcase value="LIKE"> LIKE </cfcase><!---
---><cfcase value="ILIKE"> ILIKE </cfcase><!---
---><cfcase value="LIKE%,LIKEP"> LIKE <cfqueryparam cfsqltype=#getCfSqLType(fltr.ftype)# value="%#fltr.val#%"/><cfcontinue/></cfcase><!---
---><cfcase value="ILIKE%,ILIKEP"> ILIKE <cfqueryparam cfsqltype=#getCfSqLType(fltr.ftype)# value="%#fltr.val#%"/><cfcontinue/></cfcase><!---
---><cfcase value="IN"> IN (<cfqueryparam cfsqltype=#getCfSqLType(fltr.ftype)# list=true value="#fltr.val#"/>)<cfcontinue/></cfcase><!---
---><cfdefaultcase> = <cfoutput> #fltr.field#</cfoutput><cfcontinue/><!---***криво---></cfdefaultcase><!---
---></cfswitch><cfqueryparam cfsqltype=#getCfSqLType(fltr.ftype)# value="#fltr.val#"/><cfcontinue/>
</cfif><!--- *** ILIKE POSTGRESQL SPECIFIC --->
</cfloop> </cfloop>
<cfexit method="exittag"/> <cfexit method="exittag"/>
+12 -3
View File
@@ -4,6 +4,7 @@
hint="Static helper methods for ReST API"> hint="Static helper methods for ReST API">
<!--- v0.02 2024-10-15 ---> <!--- v0.02 2024-10-15 --->
<!--- v0.03 2024-11-27 ---> <!--- v0.03 2024-11-27 --->
<!--- v0.04 2025-11-20 columns--->
<cffunction name="empty2null" <cffunction name="empty2null"
@@ -81,9 +82,11 @@
hint="parse and collect filter params, for operators see filter_build"> hint="parse and collect filter params, for operators see filter_build">
<!---e.g. duration=NEQ:2---> <!---e.g. duration=NEQ:2--->
<!---*** add test for multiple values---> <!---*** add test for multiple values--->
<cfargument name="params" type="struct" required="true" /> <cfargument name="params" type="struct" required="true" /><!--- имена полей и колонок в snake_case --->
<cfset var local={}/><!--- *** --->
<cfset var out=structNew()/> <cfset var out=structNew()/>
<cfloop collection=#params# index="local.item"> <cfloop collection=#params# index="local.item">
<cfset var urlParamName=snake2camel(lCase(local.item))/> <cfset var urlParamName=snake2camel(lCase(local.item))/>
@@ -98,11 +101,17 @@
<cfif !isValid(ARGUMENTS.params[local.item].type,value)> <cfif !isValid(ARGUMENTS.params[local.item].type,value)>
<cfthrow type="invalidParamValue" message="Filter parameter #urlParamName# value is not a valid #ARGUMENTS.params[local.item].type#"/><!---не выводим значение, чтобы исключить XSS---> <cfthrow type="invalidParamValue" message="Filter parameter #urlParamName# value is not a valid #ARGUMENTS.params[local.item].type#"/><!---не выводим значение, чтобы исключить XSS--->
</cfif> </cfif>
<cfif structKeyExists(ARGUMENTS.params[local.item], "column") AND len(ARGUMENTS.params[local.item].column)>
<cfset var column="#ARGUMENTS.params[local.item].column#"/>
<cfelse>
<cfset var column=local.item/>
</cfif>
<cfif structKeyExists(ARGUMENTS.params[local.item], "prefix") AND len(ARGUMENTS.params[local.item].prefix)> <cfif structKeyExists(ARGUMENTS.params[local.item], "prefix") AND len(ARGUMENTS.params[local.item].prefix)>
<cfset var fieldName="#ARGUMENTS.params[local.item].prefix#.#local.item#"/> <cfset var fieldName="#ARGUMENTS.params[local.item].prefix#.#column#"/>
<cfelse> <cfelse>
<cfset var fieldName=#local.item#/> <cfset var fieldName=#column#/>
</cfif> </cfif>
<cfif structKeyExists(ARGUMENTS.params[local.item], "list") AND ARGUMENTS.params[local.item].list GT 0> <cfif structKeyExists(ARGUMENTS.params[local.item], "list") AND ARGUMENTS.params[local.item].list GT 0>
+39 -24
View File
@@ -12,7 +12,11 @@
"dt_created"={prefix="o", type="date"}, "dt_created"={prefix="o", type="date"},
"dt_updated"={prefix="o", type="date"}, "dt_updated"={prefix="o", type="date"},
"creator_id"={prefix="o", type="integer"}, "creator_id"={prefix="o", type="integer"},
"creator_email"={prefix="c", column="email", type="string"},
"creator_shortname"={prefix="c", column="shortname", type="string"},
"updater_id"={prefix="o", type="integer"}, "updater_id"={prefix="o", type="integer"},
"updater_email"={prefix="u", column="email", type="string"},
"updater_shortname"={prefix="u", column="shortname", type="string"},
"dt_submit"={prefix="o", type="date"}, "dt_submit"={prefix="o", type="date"},
"submit_result"={prefix="o", type="string"}, "submit_result"={prefix="o", type="string"},
"dt_start"={prefix="o", type="date"}, "dt_start"={prefix="o", type="date"},
@@ -34,8 +38,9 @@
<cfargument name="page" type="string" hint="type:integer" default="1"/> <cfargument name="page" type="string" hint="type:integer" default="1"/>
<cfargument name="orderBy" type="string" hint="type:string, description:comma-separated list of fields to sort by, example:fld1.ASC,fld2.DESC,fld3.ASC" default=""/> <cfargument name="orderBy" type="string" hint="type:string, description:comma-separated list of fields to sort by, example:fld1.ASC,fld2.DESC,fld3.ASC" default=""/>
<cfset var local={}/>
<cftry> <!--- отладка на время проблемы 404 ---> <cftry> <!--- отладка на время проблемы 404 --->
<cfset local={}/>
<!---parse and validate request parameters---> <!---parse and validate request parameters--->
<cftry> <cftry>
@@ -53,12 +58,7 @@
<cfreturn representationOf(cfcatch)/> <cfreturn representationOf(cfcatch)/>
</cfcatch> </cfcatch>
</cftry> </cftry>
<cfset var out={}/>
<cfset var maxrows=arguments.pageSize*arguments.page/>
<cfset var startrow=arguments.pageSize*(arguments.page-1)+1/>
<!--- <cfset request.locateIamService()/> --->
<cfquery name="local.qRead" result="local.result"> <cfquery name="local.qRead" result="local.result">
select select
@@ -89,50 +89,65 @@
<m:field>u.email as updater_email</m:field> <m:field>u.email as updater_email</m:field>
<m:field>u.shortname as updater_shortname</m:field> <m:field>u.shortname as updater_shortname</m:field>
</m:field_set> </m:field_set>
from instance_operation o <cfsavecontent variable="local.fromClause">
join instance e on (o.instance_uid=e.instance_uid) from instance_operation o
left outer join specification_item i on (e.specification_item_id=i.specification_item_id) join instance e on (o.instance_uid=e.instance_uid)
left outer join specification s on (i.specification_id=s.specification_id) left outer join specification_item i on (e.specification_item_id=i.specification_item_id)
left outer join contract d on (s.contract_id=d.contract_id) left outer join specification s on (i.specification_id=s.specification_id)
left outer join svc v on (e.service_id=v.svc_id) left outer join contract d on (s.contract_id=d.contract_id)
left outer join usr c on (e.creator_id=c.usr_id) left outer join svc v on (e.service_id=v.svc_id)
left outer join usr u on (e.updater_id=u.usr_id) left outer join usr c on (e.creator_id=c.usr_id)
left outer join usr u on (e.updater_id=u.usr_id)
</cfsavecontent>#local.fromClause#
where where
s.specification_id=<cfqueryparam cfsqltype="cf_sql_integer" value=#arguments.specificationId#/> s.specification_id=<cfqueryparam cfsqltype="cf_sql_integer" value=#arguments.specificationId#/>
<m:filter_build filter=#filter#/> <m:filter_build filter=#filter#/>
order by order by
<m:order_build sortCollection=#this.helper.parseNumericOrder(local.titleMap, arguments.orderBy)# fieldCount=0/><!---no sort length limit---> <m:order_build sortCollection=#this.helper.parseNumericOrder(local.titleMap, arguments.orderBy)# fieldCount=0/><!---no sort length limit--->
limit #maxrows# <cfif arguments.pageSize GT 0>
limit #arguments.pageSize#
offset #arguments.pageSize*(arguments.page-1)#
</cfif>
</cfquery> </cfquery>
<!--- <cfdump var=#local.qRead#/><cfabort/> ---> <!--- <cfdump var=#local.qRead#/><cfabort/> --->
<cfquery name="local.qCnt">
select count(*) as cnt
#local.fromClause#
where
s.specification_id=<cfqueryparam cfsqltype="cf_sql_integer" value=#arguments.specificationId#/>
<m:filter_build filter=#filter#/>
</cfquery>
<cfquery name="local.qTotal"> <cfquery name="local.qTotal">
select count(*) as cnt select count(*) as cnt
from instance_operation o #local.fromClause#
<!--- from instance_operation o
join instance e on (o.instance_uid=e.instance_uid) join instance e on (o.instance_uid=e.instance_uid)
left outer join specification_item i on (e.specification_item_id=i.specification_item_id) left outer join specification_item i on (e.specification_item_id=i.specification_item_id)
left outer join specification s on (i.specification_id=s.specification_id) left outer join specification s on (i.specification_id=s.specification_id) --->
where where
s.specification_id=<cfqueryparam cfsqltype="cf_sql_integer" value=#arguments.specificationId#/> s.specification_id=<cfqueryparam cfsqltype="cf_sql_integer" value=#arguments.specificationId#/>
</cfquery> </cfquery>
<cfset var out=structNew("linked")/>
<cfset "out.queryDurationMs"=getTickCount() - request.startTickCount/> <cfset "out.queryDurationMs"=getTickCount() - request.startTickCount/>
<cfset "out.total"=#local.qTotal.cnt#/> <cfset "out.total"=#local.qTotal.cnt#/>
<cfset "out.resultSetSize"=#local.qRead.recordCount#/> <cfset "out.resultSetSize"=#local.qCnt.cnt#/>
<cfset "out.pageSize"=#arguments.pageSize*1#/> <cfset "out.pageSize"=#arguments.pageSize*1#/>
<cfset "out.page"=#arguments.page*1#/> <cfset "out.page"=#arguments.page*1#/>
<cfset "out.orderBy"=#arguments.orderBy#/> <cfset "out.orderBy"=#arguments.orderBy#/>
<cfset var resultCollection=[]/> <cfset var resultCollection=[]/>
<cfloop query=#local.qRead# startRow=#startrow# endRow=#(startrow+maxrows-1)#> <cfloop query=#local.qRead#>
<cfset var rec=structNew("linked")/> <cfset var rec=structNew("linked")/>
<cfset this.helper.appendRecord(rec, "", local.titleMap, local.qRead, this.helper.snake2camel)/> <cfset this.helper.appendRecord(rec, "", local.titleMap, local.qRead, this.helper.snake2camel)/>
<cfset arrayAppend(resultCollection, rec)/> <cfset arrayAppend(resultCollection, rec)/>
</cfloop> </cfloop>
<cfset "out.size"=#arrayLen(resultCollection)#/> <cfset "out.size"=#arrayLen(resultCollection)#/>
<cfset "out.results"=#resultCollection#/> <cfset "out.results"=#resultCollection#/>
<cfset "out.runDurationMs"=getTickCount()-request.startTickCount/> <cfset "out.runDurationMs"=getTickCount()-request.startTickCount/>
<!---<cfset "out.sql"=#local.result.sql#/>---> <!---<cfset "out.sql"=#local.result.sql#/>--->
<cfreturn representationOf(out)/> <cfreturn representationOf(out)/>