forked from tsai/budibase
committed by
GitHub
5 changed files with 141 additions and 121 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