Skip to content

Commit b6405b0

Browse files
Bill LeoutsakosBill Leoutsakos
authored andcommitted
fix(snowflake): scope block params by operation
1 parent 2deca33 commit b6405b0

2 files changed

Lines changed: 160 additions & 22 deletions

File tree

apps/sim/blocks/blocks/snowflake.ts

Lines changed: 96 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -599,30 +599,104 @@ export const SnowflakeBlock: BlockConfig<SnowflakeStatementResponse> = {
599599
tool: (params) => `snowflake_${params.operation}`,
600600
params: (params) => {
601601
const jsonBudget = { bytes: 0 }
602-
return {
603-
async: optionalBoolean(params.async),
604-
bindings: parseJson(params.bindings, 'Bindings', jsonBudget),
605-
database: params.database || params.contextDatabase || undefined,
606-
schema: params.schema || params.contextSchema || undefined,
607-
taskName: params.taskName || params.taskNameFilter || undefined,
608-
rows: parseJson(params.rows, 'Rows', jsonBudget),
609-
matchColumns: parseJson(params.matchColumns, 'Match columns', jsonBudget),
610-
filters: parseJson(params.filters, 'Filters', jsonBudget),
611-
procedureArguments: parseJson(
612-
params.procedureArguments,
613-
'Procedure arguments',
614-
jsonBudget
615-
),
616-
partition: optionalNumber(params.partition),
602+
const statementParams = () => ({
617603
timeout: optionalNumber(params.timeout),
618604
maxRows: optionalNumber(params.maxRows),
619-
limit: optionalNumber(params.limit),
620-
purge: optionalBoolean(params.purge),
621-
force: optionalBoolean(params.force),
622-
retryLast: optionalBoolean(params.retryLast),
623-
errorOnly: optionalBoolean(params.errorOnly),
624-
includeViews: optionalBoolean(params.includeViews),
625-
onError: copyOnError(params.onError, params.onErrorThreshold),
605+
})
606+
const contextParams = () => ({
607+
...statementParams(),
608+
database: params.contextDatabase || undefined,
609+
schema: params.contextSchema || undefined,
610+
})
611+
const objectParams = () => ({
612+
...statementParams(),
613+
database: params.database || undefined,
614+
schema: params.schema || undefined,
615+
})
616+
617+
switch (params.operation) {
618+
case 'execute_sql':
619+
return {
620+
...contextParams(),
621+
async: optionalBoolean(params.async),
622+
bindings: parseJson(params.bindings, 'Bindings', jsonBudget),
623+
}
624+
case 'get_statement':
625+
return {
626+
partition: optionalNumber(params.partition),
627+
maxRows: optionalNumber(params.maxRows),
628+
}
629+
case 'insert_rows':
630+
return {
631+
...objectParams(),
632+
rows: parseJson(params.rows, 'Rows', jsonBudget),
633+
}
634+
case 'update_rows':
635+
case 'upsert_rows':
636+
return {
637+
...objectParams(),
638+
rows: parseJson(params.rows, 'Rows', jsonBudget),
639+
matchColumns: parseJson(params.matchColumns, 'Match columns', jsonBudget),
640+
}
641+
case 'delete_rows':
642+
return {
643+
...objectParams(),
644+
filters: parseJson(params.filters, 'Filters', jsonBudget),
645+
}
646+
case 'load_data':
647+
return {
648+
...objectParams(),
649+
purge: optionalBoolean(params.purge),
650+
force: optionalBoolean(params.force),
651+
onError: copyOnError(params.onError, params.onErrorThreshold),
652+
}
653+
case 'list_warehouses':
654+
case 'get_warehouse':
655+
case 'resume_warehouse':
656+
case 'suspend_warehouse':
657+
case 'cancel_task_run':
658+
case 'get_task_run_output':
659+
return contextParams()
660+
case 'list_tasks':
661+
return {
662+
...objectParams(),
663+
limit: optionalNumber(params.limit),
664+
}
665+
case 'get_task':
666+
return objectParams()
667+
case 'run_task':
668+
return {
669+
...objectParams(),
670+
retryLast: optionalBoolean(params.retryLast),
671+
}
672+
case 'list_task_runs':
673+
return {
674+
...contextParams(),
675+
taskName: params.taskNameFilter || undefined,
676+
limit: optionalNumber(params.limit),
677+
errorOnly: optionalBoolean(params.errorOnly),
678+
}
679+
case 'get_task_run':
680+
return {
681+
...contextParams(),
682+
taskName: params.taskNameFilter || undefined,
683+
}
684+
case 'introspect_schema':
685+
return {
686+
...objectParams(),
687+
includeViews: optionalBoolean(params.includeViews),
688+
}
689+
case 'call_procedure':
690+
return {
691+
...objectParams(),
692+
procedureArguments: parseJson(
693+
params.procedureArguments,
694+
'Procedure arguments',
695+
jsonBudget
696+
),
697+
}
698+
default:
699+
return {}
626700
}
627701
},
628702
},

apps/sim/tools/snowflake/sql.test.ts

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,70 @@ describe('Snowflake SQL builders', () => {
7272
).toThrow('exceeds')
7373
})
7474

75+
it('only coerces fields used by the selected block operation', () => {
76+
const mapParams = SnowflakeBlock.tools.config.params
77+
if (!mapParams) throw new Error('Snowflake block must map tool parameters')
78+
79+
expect(() =>
80+
mapParams({
81+
operation: 'execute_sql',
82+
rows: '{invalid',
83+
filters: '{invalid',
84+
procedureArguments: '{invalid',
85+
onError: 'SKIP_FILE_NUMBER',
86+
})
87+
).not.toThrow()
88+
expect(() =>
89+
mapParams({
90+
operation: 'delete_rows',
91+
rows: '{invalid',
92+
filters: '{"id":1}',
93+
})
94+
).not.toThrow()
95+
expect(() =>
96+
mapParams({
97+
operation: 'load_data',
98+
onError: 'SKIP_FILE_NUMBER',
99+
})
100+
).toThrow('threshold')
101+
})
102+
103+
it('maps overlapping block fields according to the selected operation', () => {
104+
const mapParams = SnowflakeBlock.tools.config.params
105+
if (!mapParams) throw new Error('Snowflake block must map tool parameters')
106+
const finalParams = (params: Record<string, unknown>) => ({
107+
...params,
108+
...mapParams(params),
109+
})
110+
const staleFields = {
111+
database: 'OBJECT_DB',
112+
schema: 'OBJECT_SCHEMA',
113+
contextDatabase: 'CONTEXT_DB',
114+
contextSchema: 'CONTEXT_SCHEMA',
115+
taskName: 'TASK_DEFINITION',
116+
taskNameFilter: 'TASK_HISTORY_FILTER',
117+
}
118+
119+
expect(finalParams({ operation: 'execute_sql', ...staleFields })).toMatchObject({
120+
database: 'CONTEXT_DB',
121+
schema: 'CONTEXT_SCHEMA',
122+
})
123+
expect(finalParams({ operation: 'insert_rows', ...staleFields, rows: '[]' })).toMatchObject({
124+
database: 'OBJECT_DB',
125+
schema: 'OBJECT_SCHEMA',
126+
})
127+
expect(finalParams({ operation: 'list_task_runs', ...staleFields })).toMatchObject({
128+
database: 'CONTEXT_DB',
129+
schema: 'CONTEXT_SCHEMA',
130+
taskName: 'TASK_HISTORY_FILTER',
131+
})
132+
expect(finalParams({ operation: 'get_task', ...staleFields })).toMatchObject({
133+
database: 'OBJECT_DB',
134+
schema: 'OBJECT_SCHEMA',
135+
taskName: 'TASK_DEFINITION',
136+
})
137+
})
138+
75139
it('builds a bound multi-row INSERT in stable column order', () => {
76140
const result = buildInsertRows({
77141
...table,

0 commit comments

Comments
 (0)