mirror of
https://github.com/simstudioai/sim.git
synced 2026-09-24 15:45:35 +08:00
fix(snowflake): scope block params by operation
This commit is contained in:
@@ -599,30 +599,104 @@ export const SnowflakeBlock: BlockConfig<SnowflakeStatementResponse> = {
|
||||
tool: (params) => `snowflake_${params.operation}`,
|
||||
params: (params) => {
|
||||
const jsonBudget = { bytes: 0 }
|
||||
return {
|
||||
async: optionalBoolean(params.async),
|
||||
bindings: parseJson(params.bindings, 'Bindings', jsonBudget),
|
||||
database: params.database || params.contextDatabase || undefined,
|
||||
schema: params.schema || params.contextSchema || undefined,
|
||||
taskName: params.taskName || params.taskNameFilter || undefined,
|
||||
rows: parseJson(params.rows, 'Rows', jsonBudget),
|
||||
matchColumns: parseJson(params.matchColumns, 'Match columns', jsonBudget),
|
||||
filters: parseJson(params.filters, 'Filters', jsonBudget),
|
||||
procedureArguments: parseJson(
|
||||
params.procedureArguments,
|
||||
'Procedure arguments',
|
||||
jsonBudget
|
||||
),
|
||||
partition: optionalNumber(params.partition),
|
||||
const statementParams = () => ({
|
||||
timeout: optionalNumber(params.timeout),
|
||||
maxRows: optionalNumber(params.maxRows),
|
||||
limit: optionalNumber(params.limit),
|
||||
purge: optionalBoolean(params.purge),
|
||||
force: optionalBoolean(params.force),
|
||||
retryLast: optionalBoolean(params.retryLast),
|
||||
errorOnly: optionalBoolean(params.errorOnly),
|
||||
includeViews: optionalBoolean(params.includeViews),
|
||||
onError: copyOnError(params.onError, params.onErrorThreshold),
|
||||
})
|
||||
const contextParams = () => ({
|
||||
...statementParams(),
|
||||
database: params.contextDatabase || undefined,
|
||||
schema: params.contextSchema || undefined,
|
||||
})
|
||||
const objectParams = () => ({
|
||||
...statementParams(),
|
||||
database: params.database || undefined,
|
||||
schema: params.schema || undefined,
|
||||
})
|
||||
|
||||
switch (params.operation) {
|
||||
case 'execute_sql':
|
||||
return {
|
||||
...contextParams(),
|
||||
async: optionalBoolean(params.async),
|
||||
bindings: parseJson(params.bindings, 'Bindings', jsonBudget),
|
||||
}
|
||||
case 'get_statement':
|
||||
return {
|
||||
partition: optionalNumber(params.partition),
|
||||
maxRows: optionalNumber(params.maxRows),
|
||||
}
|
||||
case 'insert_rows':
|
||||
return {
|
||||
...objectParams(),
|
||||
rows: parseJson(params.rows, 'Rows', jsonBudget),
|
||||
}
|
||||
case 'update_rows':
|
||||
case 'upsert_rows':
|
||||
return {
|
||||
...objectParams(),
|
||||
rows: parseJson(params.rows, 'Rows', jsonBudget),
|
||||
matchColumns: parseJson(params.matchColumns, 'Match columns', jsonBudget),
|
||||
}
|
||||
case 'delete_rows':
|
||||
return {
|
||||
...objectParams(),
|
||||
filters: parseJson(params.filters, 'Filters', jsonBudget),
|
||||
}
|
||||
case 'load_data':
|
||||
return {
|
||||
...objectParams(),
|
||||
purge: optionalBoolean(params.purge),
|
||||
force: optionalBoolean(params.force),
|
||||
onError: copyOnError(params.onError, params.onErrorThreshold),
|
||||
}
|
||||
case 'list_warehouses':
|
||||
case 'get_warehouse':
|
||||
case 'resume_warehouse':
|
||||
case 'suspend_warehouse':
|
||||
case 'cancel_task_run':
|
||||
case 'get_task_run_output':
|
||||
return contextParams()
|
||||
case 'list_tasks':
|
||||
return {
|
||||
...objectParams(),
|
||||
limit: optionalNumber(params.limit),
|
||||
}
|
||||
case 'get_task':
|
||||
return objectParams()
|
||||
case 'run_task':
|
||||
return {
|
||||
...objectParams(),
|
||||
retryLast: optionalBoolean(params.retryLast),
|
||||
}
|
||||
case 'list_task_runs':
|
||||
return {
|
||||
...contextParams(),
|
||||
taskName: params.taskNameFilter || undefined,
|
||||
limit: optionalNumber(params.limit),
|
||||
errorOnly: optionalBoolean(params.errorOnly),
|
||||
}
|
||||
case 'get_task_run':
|
||||
return {
|
||||
...contextParams(),
|
||||
taskName: params.taskNameFilter || undefined,
|
||||
}
|
||||
case 'introspect_schema':
|
||||
return {
|
||||
...objectParams(),
|
||||
includeViews: optionalBoolean(params.includeViews),
|
||||
}
|
||||
case 'call_procedure':
|
||||
return {
|
||||
...objectParams(),
|
||||
procedureArguments: parseJson(
|
||||
params.procedureArguments,
|
||||
'Procedure arguments',
|
||||
jsonBudget
|
||||
),
|
||||
}
|
||||
default:
|
||||
return {}
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
@@ -72,6 +72,70 @@ describe('Snowflake SQL builders', () => {
|
||||
).toThrow('exceeds')
|
||||
})
|
||||
|
||||
it('only coerces fields used by the selected block operation', () => {
|
||||
const mapParams = SnowflakeBlock.tools.config.params
|
||||
if (!mapParams) throw new Error('Snowflake block must map tool parameters')
|
||||
|
||||
expect(() =>
|
||||
mapParams({
|
||||
operation: 'execute_sql',
|
||||
rows: '{invalid',
|
||||
filters: '{invalid',
|
||||
procedureArguments: '{invalid',
|
||||
onError: 'SKIP_FILE_NUMBER',
|
||||
})
|
||||
).not.toThrow()
|
||||
expect(() =>
|
||||
mapParams({
|
||||
operation: 'delete_rows',
|
||||
rows: '{invalid',
|
||||
filters: '{"id":1}',
|
||||
})
|
||||
).not.toThrow()
|
||||
expect(() =>
|
||||
mapParams({
|
||||
operation: 'load_data',
|
||||
onError: 'SKIP_FILE_NUMBER',
|
||||
})
|
||||
).toThrow('threshold')
|
||||
})
|
||||
|
||||
it('maps overlapping block fields according to the selected operation', () => {
|
||||
const mapParams = SnowflakeBlock.tools.config.params
|
||||
if (!mapParams) throw new Error('Snowflake block must map tool parameters')
|
||||
const finalParams = (params: Record<string, unknown>) => ({
|
||||
...params,
|
||||
...mapParams(params),
|
||||
})
|
||||
const staleFields = {
|
||||
database: 'OBJECT_DB',
|
||||
schema: 'OBJECT_SCHEMA',
|
||||
contextDatabase: 'CONTEXT_DB',
|
||||
contextSchema: 'CONTEXT_SCHEMA',
|
||||
taskName: 'TASK_DEFINITION',
|
||||
taskNameFilter: 'TASK_HISTORY_FILTER',
|
||||
}
|
||||
|
||||
expect(finalParams({ operation: 'execute_sql', ...staleFields })).toMatchObject({
|
||||
database: 'CONTEXT_DB',
|
||||
schema: 'CONTEXT_SCHEMA',
|
||||
})
|
||||
expect(finalParams({ operation: 'insert_rows', ...staleFields, rows: '[]' })).toMatchObject({
|
||||
database: 'OBJECT_DB',
|
||||
schema: 'OBJECT_SCHEMA',
|
||||
})
|
||||
expect(finalParams({ operation: 'list_task_runs', ...staleFields })).toMatchObject({
|
||||
database: 'CONTEXT_DB',
|
||||
schema: 'CONTEXT_SCHEMA',
|
||||
taskName: 'TASK_HISTORY_FILTER',
|
||||
})
|
||||
expect(finalParams({ operation: 'get_task', ...staleFields })).toMatchObject({
|
||||
database: 'OBJECT_DB',
|
||||
schema: 'OBJECT_SCHEMA',
|
||||
taskName: 'TASK_DEFINITION',
|
||||
})
|
||||
})
|
||||
|
||||
it('builds a bound multi-row INSERT in stable column order', () => {
|
||||
const result = buildInsertRows({
|
||||
...table,
|
||||
|
||||
Reference in New Issue
Block a user