I have the following query params coming to my API
{
"PERSON_ID": "123456",
"LAST_MODIFIED_DATE": "2011-12-15T00:00:00",
"START_DATE": "2011-12-15T00:00:00",
"END_DATE": "2012-12-15T00:00:00"
}
I need to build a different dynamic SQL query based on the input parameters which can be any of the these given below - (either LAST_MODIFIED_DATE or (START_DATE and END_DATE) will be based. But PERSON_ID can be passed any of the other params
select * from Person where PERSON_ID = 123456
select * from Person where LAST_MODIFIED_DATE = 2011-12-15T00:00:00
select * from Person where PERSON_ID = 123456 and LAST_MODIFIED_DATE = 2011-12-15T00:00:00
select * from Person where PERSON_ID = 123456 and LAST_MODIFIED_DATE between 2011-12-15T00:00:00 and 2012-12-15T00:00:00
select * from Person where LAST_MODIFIED_DATE between 2011-12-15T00:00:00 and 2012-12-15T00:00:00
or if no query params are passed it will be
select * from Person
my DW logic is not able to cater to this requirement.
Tried below but not able to get the required results. Could you please suggest a recommended approach or best solution
%dw 2.0
output application/json
var data = {
"PERSON_ID": "123456",
"LAST_MODIFIED_DATE": "2011-12-15T00:00:00",
"START_DATE": "2011-12-15T00:00:00",
"END_DATE": "2012-12-15T00:00:00"
}
"Select * from Person Where " ++
((data filterObject ((value, key, index) -> (value != null and value != "")) mapObject ((value, key, index) -> {
(myData : "LAST_MODIFIED_DATE between " ++ (key as String)) if ((key as String) == "START_DATE"),
(myData : "AND " ++ (key as String)) if ((key as String) == "END_DATE"),
(myData : (key as String) ++ " = :" ++ (key as String)) if ((key as String) == "PERSON_ID"),
myData : (key as String) ++ " = :" ++ (key as String)
})).*myData joinBy " AND ")
Later in the DB connector I am setting the above output variable as query in SQL String
It is a very common use case with a lot of possible solutions.
What I like to do is I create an Array with all the conditions as items. Then join them using joinBy
function with a ' AND '
string to join those condition.
If you follow this the use of Conditional Elements makes the complex and dynamic SQL generation very readable and clear IMO
Updated the following based on Aled's suggestion to avoid SQL Injection For Example
%dw 2.0
output text/plain
fun generateWhereClause(queryParams) =
[
("PERSON_ID = :PERSON_ID") if(queryParams.PERSON_ID?),
("LAST_MODIFIED_DATE = :LAST_MODIFIED_DATE") if(queryParams.LAST_MODIFIED_DATE?),
("LAST_MODIFIED_DATE >= :START_DATE") if(queryParams.START_DATE?),
("LAST_MODIFIED_DATE <= :END_DATE") if(queryParams.END_DATE?),
] joinBy " AND "
---
'SELECT * FROM person WHERE $(generateWhereClause(vars.queryParams))'
This will generate a parameterized SQL Statement, and you can pass your query parameters as the input parameter in the select
operation.
<db:select config-ref="dbConfig">
<db:sql>#[payload]</db:sql>
<db:input-parameters>
#[vars.queryParams // whereever you have your params]
</db:input-parameters>
</db:select>
I have dropped between
operator and used >= and <=
operators because between
does not fit the pattern easily and makes the conditions in the array complex. If you want to use it though, you can.