forked from tsai/budibase
3 changed files with 133 additions and 119 deletions
@ -0,0 +1,125 @@ |
|||||
|
import { findHBSBlocks, processStringSync } from "@budibase/string-templates" |
||||
|
import { Integration } from "../../definitions/datasource" |
||||
|
import { DatasourcePlus } from "../base/datasourcePlus" |
||||
|
|
||||
|
const CONST_CHAR_REGEX = new RegExp("'[^']*'", "g") |
||||
|
|
||||
|
export function enrichQueryFields( |
||||
|
fields: { [key: string]: any }, |
||||
|
parameters = {} |
||||
|
) { |
||||
|
const enrichedQuery: { [key: string]: any } = Array.isArray(fields) ? [] : {} |
||||
|
|
||||
|
// enrich the fields with dynamic parameters
|
||||
|
for (let key of Object.keys(fields)) { |
||||
|
if (fields[key] == null) { |
||||
|
continue |
||||
|
} |
||||
|
if (typeof fields[key] === "object") { |
||||
|
// enrich nested fields object
|
||||
|
enrichedQuery[key] = enrichQueryFields(fields[key], parameters) |
||||
|
} else if (typeof fields[key] === "string") { |
||||
|
// enrich string value as normal
|
||||
|
enrichedQuery[key] = processStringSync(fields[key], parameters, { |
||||
|
noEscaping: true, |
||||
|
noHelpers: true, |
||||
|
escapeNewlines: true, |
||||
|
}) |
||||
|
} else { |
||||
|
enrichedQuery[key] = fields[key] |
||||
|
} |
||||
|
} |
||||
|
if ( |
||||
|
enrichedQuery.json || |
||||
|
enrichedQuery.customData || |
||||
|
enrichedQuery.requestBody |
||||
|
) { |
||||
|
try { |
||||
|
enrichedQuery.json = JSON.parse( |
||||
|
enrichedQuery.json || |
||||
|
enrichedQuery.customData || |
||||
|
enrichedQuery.requestBody |
||||
|
) |
||||
|
} catch (err) { |
||||
|
// no json found, ignore
|
||||
|
} |
||||
|
delete enrichedQuery.customData |
||||
|
} |
||||
|
return enrichedQuery |
||||
|
} |
||||
|
|
||||
|
export function interpolateSQL( |
||||
|
fields: { [key: string]: any }, |
||||
|
parameters: { [key: string]: any }, |
||||
|
integration: DatasourcePlus |
||||
|
) { |
||||
|
let sql = fields.sql |
||||
|
if (!sql || typeof sql !== "string") { |
||||
|
return fields |
||||
|
} |
||||
|
const bindings = findHBSBlocks(sql) |
||||
|
let variables = [], |
||||
|
arrays = [] |
||||
|
for (let binding of bindings) { |
||||
|
// look for array/list operations in the SQL statement, which will need handled later
|
||||
|
const listRegexMatch = sql.match( |
||||
|
new RegExp(`(in|IN|In|iN)( )+[(]?${binding}[)]?`) |
||||
|
) |
||||
|
// check if the variable was used as part of a string concat e.g. 'Hello {{binding}}'
|
||||
|
// start by finding all the instances of const character strings
|
||||
|
const charConstMatch = sql.match(CONST_CHAR_REGEX) || [] |
||||
|
// now look within them to see if a binding is used
|
||||
|
const charConstBindingMatch = charConstMatch.find((string: any) => |
||||
|
string.match(new RegExp(`'[^']*${binding}[^']*'`)) |
||||
|
) |
||||
|
if (charConstBindingMatch) { |
||||
|
let [part1, part2] = charConstBindingMatch.split(binding) |
||||
|
part1 = `'${part1.substring(1)}'` |
||||
|
part2 = `'${part2.substring(0, part2.length - 1)}'` |
||||
|
sql = sql.replace( |
||||
|
charConstBindingMatch, |
||||
|
integration.getStringConcat([ |
||||
|
part1, |
||||
|
integration.getBindingIdentifier(), |
||||
|
part2, |
||||
|
]) |
||||
|
) |
||||
|
} |
||||
|
// generate SQL parameterised array
|
||||
|
else if (listRegexMatch) { |
||||
|
arrays.push(binding) |
||||
|
// determine the length of the array
|
||||
|
const value = enrichQueryFields([binding], parameters)[0] |
||||
|
.split(",") |
||||
|
.map((val: string) => val.trim()) |
||||
|
// build a string like ($1, $2, $3)
|
||||
|
let replacement = `${Array.apply(null, Array(value.length)) |
||||
|
.map(() => integration.getBindingIdentifier()) |
||||
|
.join(",")}` |
||||
|
// check if parentheses are needed
|
||||
|
if (!listRegexMatch[0].includes(`(${binding})`)) { |
||||
|
replacement = `(${replacement})` |
||||
|
} |
||||
|
sql = sql.replace(binding, replacement) |
||||
|
} else { |
||||
|
sql = sql.replace(binding, integration.getBindingIdentifier()) |
||||
|
} |
||||
|
variables.push(binding) |
||||
|
} |
||||
|
// replicate the knex structure
|
||||
|
fields.sql = sql |
||||
|
fields.bindings = enrichQueryFields(variables, parameters) |
||||
|
// check for arrays in the data
|
||||
|
let updated: string[] = [] |
||||
|
for (let i = 0; i < variables.length; i++) { |
||||
|
if (arrays.includes(variables[i])) { |
||||
|
updated = updated.concat( |
||||
|
fields.bindings[i].split(",").map((val: string) => val.trim()) |
||||
|
) |
||||
|
} else { |
||||
|
updated.push(fields.bindings[i]) |
||||
|
} |
||||
|
} |
||||
|
fields.bindings = updated |
||||
|
return fields |
||||
|
} |
||||
Loading…
Reference in new issue