Initial fix for defaulting parameters, switch to null rather than strings, this is important for prepared statements/SQL queries.
This commit is contained in:
parent
ed94459fd8
commit
c32163a9be
|
@ -6,7 +6,7 @@ import { invalidateDynamicVariables } from "../../../threads/utils"
|
||||||
import env from "../../../environment"
|
import env from "../../../environment"
|
||||||
import { events, context, utils, constants } from "@budibase/backend-core"
|
import { events, context, utils, constants } from "@budibase/backend-core"
|
||||||
import sdk from "../../../sdk"
|
import sdk from "../../../sdk"
|
||||||
import { QueryEvent } from "../../../threads/definitions"
|
import { QueryEvent, QueryEventParameters } from "../../../threads/definitions"
|
||||||
import {
|
import {
|
||||||
ConfigType,
|
ConfigType,
|
||||||
Query,
|
Query,
|
||||||
|
@ -18,7 +18,6 @@ import {
|
||||||
FieldType,
|
FieldType,
|
||||||
ExecuteQueryRequest,
|
ExecuteQueryRequest,
|
||||||
ExecuteQueryResponse,
|
ExecuteQueryResponse,
|
||||||
QueryParameter,
|
|
||||||
PreviewQueryRequest,
|
PreviewQueryRequest,
|
||||||
PreviewQueryResponse,
|
PreviewQueryResponse,
|
||||||
} from "@budibase/types"
|
} from "@budibase/types"
|
||||||
|
@ -29,7 +28,7 @@ const Runner = new Thread(ThreadType.QUERY, {
|
||||||
timeoutMs: env.QUERY_THREAD_TIMEOUT,
|
timeoutMs: env.QUERY_THREAD_TIMEOUT,
|
||||||
})
|
})
|
||||||
|
|
||||||
function validateQueryInputs(parameters: Record<string, string>) {
|
function validateQueryInputs(parameters: QueryEventParameters) {
|
||||||
for (let entry of Object.entries(parameters)) {
|
for (let entry of Object.entries(parameters)) {
|
||||||
const [key, value] = entry
|
const [key, value] = entry
|
||||||
if (typeof value !== "string") {
|
if (typeof value !== "string") {
|
||||||
|
@ -100,8 +99,10 @@ export async function save(ctx: UserCtx<Query, Query>) {
|
||||||
const datasource = await sdk.datasources.get(query.datasourceId)
|
const datasource = await sdk.datasources.get(query.datasourceId)
|
||||||
|
|
||||||
let eventFn
|
let eventFn
|
||||||
if (!query._id) {
|
if (!query._id && !query._rev) {
|
||||||
query._id = generateQueryID(query.datasourceId)
|
query._id = generateQueryID(query.datasourceId)
|
||||||
|
// flag to state whether the default bindings are empty strings (old behaviour) or null
|
||||||
|
query.nullDefaultSupport = true
|
||||||
eventFn = () => events.query.created(datasource, query)
|
eventFn = () => events.query.created(datasource, query)
|
||||||
} else {
|
} else {
|
||||||
eventFn = () => events.query.updated(datasource, query)
|
eventFn = () => events.query.updated(datasource, query)
|
||||||
|
@ -135,16 +136,22 @@ function getAuthConfig(ctx: UserCtx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function enrichParameters(
|
function enrichParameters(
|
||||||
queryParameters: QueryParameter[],
|
query: Query,
|
||||||
requestParameters: Record<string, string> = {}
|
requestParameters: QueryEventParameters = {}
|
||||||
): Record<string, string> {
|
): QueryEventParameters {
|
||||||
|
const paramNotSet = (val: unknown) => val === "" || val == undefined
|
||||||
// first check parameters are all valid
|
// first check parameters are all valid
|
||||||
validateQueryInputs(requestParameters)
|
validateQueryInputs(requestParameters)
|
||||||
// make sure parameters are fully enriched with defaults
|
// make sure parameters are fully enriched with defaults
|
||||||
for (let parameter of queryParameters) {
|
for (let parameter of query.parameters) {
|
||||||
if (!requestParameters[parameter.name]) {
|
let value: string | null = requestParameters[parameter.name]
|
||||||
requestParameters[parameter.name] = parameter.default
|
if (!value) {
|
||||||
|
value = parameter.default
|
||||||
}
|
}
|
||||||
|
if (query.nullDefaultSupport && paramNotSet(value)) {
|
||||||
|
value = null
|
||||||
|
}
|
||||||
|
requestParameters[parameter.name] = value
|
||||||
}
|
}
|
||||||
return requestParameters
|
return requestParameters
|
||||||
}
|
}
|
||||||
|
@ -157,10 +164,15 @@ export async function preview(
|
||||||
)
|
)
|
||||||
// preview may not have a queryId as it hasn't been saved, but if it does
|
// preview may not have a queryId as it hasn't been saved, but if it does
|
||||||
// this stops dynamic variables from calling the same query
|
// this stops dynamic variables from calling the same query
|
||||||
const { fields, parameters, queryVerb, transformer, queryId, schema } =
|
const queryId = ctx.request.body.queryId
|
||||||
ctx.request.body
|
// the body contains the makings of a query, which has not been saved yet
|
||||||
|
const query: Query = ctx.request.body
|
||||||
|
// hasn't been saved, new query
|
||||||
|
if (!queryId && !query._id) {
|
||||||
|
query.nullDefaultSupport = true
|
||||||
|
}
|
||||||
|
|
||||||
let existingSchema = schema
|
let existingSchema = query.schema
|
||||||
if (queryId && !existingSchema) {
|
if (queryId && !existingSchema) {
|
||||||
try {
|
try {
|
||||||
const db = context.getAppDB()
|
const db = context.getAppDB()
|
||||||
|
@ -268,13 +280,13 @@ export async function preview(
|
||||||
try {
|
try {
|
||||||
const inputs: QueryEvent = {
|
const inputs: QueryEvent = {
|
||||||
appId: ctx.appId,
|
appId: ctx.appId,
|
||||||
datasource,
|
queryVerb: query.queryVerb,
|
||||||
queryVerb,
|
fields: query.fields,
|
||||||
fields,
|
parameters: enrichParameters(query),
|
||||||
parameters: enrichParameters(parameters),
|
transformer: query.transformer,
|
||||||
transformer,
|
schema: query.schema,
|
||||||
queryId,
|
queryId,
|
||||||
schema,
|
datasource,
|
||||||
// have to pass down to the thread runner - can't put into context now
|
// have to pass down to the thread runner - can't put into context now
|
||||||
environmentVariables: envVars,
|
environmentVariables: envVars,
|
||||||
ctx: {
|
ctx: {
|
||||||
|
@ -336,10 +348,7 @@ async function execute(
|
||||||
queryVerb: query.queryVerb,
|
queryVerb: query.queryVerb,
|
||||||
fields: query.fields,
|
fields: query.fields,
|
||||||
pagination: ctx.request.body.pagination,
|
pagination: ctx.request.body.pagination,
|
||||||
parameters: enrichParameters(
|
parameters: enrichParameters(query, ctx.request.body.parameters),
|
||||||
query.parameters,
|
|
||||||
ctx.request.body.parameters
|
|
||||||
),
|
|
||||||
transformer: query.transformer,
|
transformer: query.transformer,
|
||||||
queryId: ctx.params.queryId,
|
queryId: ctx.params.queryId,
|
||||||
// have to pass down to the thread runner - can't put into context now
|
// have to pass down to the thread runner - can't put into context now
|
||||||
|
|
|
@ -1,21 +1,20 @@
|
||||||
import { Datasource, QuerySchema, Row } from "@budibase/types"
|
import { Datasource, Row, Query } from "@budibase/types"
|
||||||
|
|
||||||
export type WorkerCallback = (error: any, response?: any) => void
|
export type WorkerCallback = (error: any, response?: any) => void
|
||||||
|
|
||||||
export interface QueryEvent {
|
export interface QueryEvent
|
||||||
|
extends Omit<Query, "datasourceId" | "name" | "parameters" | "readable"> {
|
||||||
appId?: string
|
appId?: string
|
||||||
datasource: Datasource
|
datasource: Datasource
|
||||||
queryVerb: string
|
|
||||||
fields: { [key: string]: any }
|
|
||||||
parameters: { [key: string]: unknown }
|
|
||||||
pagination?: any
|
pagination?: any
|
||||||
transformer: any
|
|
||||||
queryId?: string
|
queryId?: string
|
||||||
environmentVariables?: Record<string, string>
|
environmentVariables?: Record<string, string>
|
||||||
|
parameters: QueryEventParameters
|
||||||
ctx?: any
|
ctx?: any
|
||||||
schema?: Record<string, QuerySchema | string>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type QueryEventParameters = Record<string, string | null>
|
||||||
|
|
||||||
export interface QueryResponse {
|
export interface QueryResponse {
|
||||||
rows: Row[]
|
rows: Row[]
|
||||||
keys: string[]
|
keys: string[]
|
||||||
|
|
|
@ -15,6 +15,8 @@ export interface Query extends Document {
|
||||||
schema: Record<string, QuerySchema | string>
|
schema: Record<string, QuerySchema | string>
|
||||||
readable: boolean
|
readable: boolean
|
||||||
queryVerb: string
|
queryVerb: string
|
||||||
|
// flag to state whether the default bindings are empty strings (old behaviour) or null
|
||||||
|
nullDefaultSupport?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface QueryPreview extends Omit<Query, "_id"> {
|
export interface QueryPreview extends Omit<Query, "_id"> {
|
||||||
|
|
Loading…
Reference in New Issue