@@ -12,6 +12,11 @@ import type {
1212 TablePredicateInput ,
1313} from '@/lib/table/types'
1414import type { BlockConfig } from '@/blocks/types'
15+ import {
16+ resolveTableColumnSelection ,
17+ TABLE_OUTPUT_COLUMNS_INPUT ,
18+ TABLE_OUTPUT_COLUMNS_SUBBLOCK ,
19+ } from '@/blocks/utils'
1520import { TABLE_ID_PARAM } from '@/tools/table/params'
1621import { getTrigger } from '@/triggers'
1722
@@ -90,28 +95,6 @@ function resolveOrder(params: TableBlockParams): SortSpec | undefined {
9095 return ( parsed as SortSpec | undefined ) || undefined
9196}
9297
93- /**
94- * Resolves the "Columns to Return" selection. Only an absent value (`undefined`,
95- * `null`, the dependsOn-cleared `''`, or `[]`) means "all columns"; anything
96- * else must be a list of column ids/names. A malformed value fails fast rather
97- * than silently widening a deliberately narrowed query to every column — the
98- * same stance `parseOptionalLimit` takes for a malformed limit. A JSON string is
99- * accepted because an agent-authored block config serializes arrays that way.
100- */
101- function resolveOutputColumns ( raw : unknown ) : string [ ] | undefined {
102- if ( raw === undefined || raw === null || raw === '' ) return undefined
103- const parsed = typeof raw === 'string' ? parseJSON ( raw , 'Columns to Return' ) : raw
104- if ( ! Array . isArray ( parsed ) ) {
105- throw new Error ( 'Invalid Columns to Return: expected a list of column ids or names' )
106- }
107- if ( parsed . length === 0 ) return undefined
108- const columns = parsed . map ( ( column ) => ( typeof column === 'string' ? column . trim ( ) : '' ) )
109- if ( columns . some ( ( column ) => column . length === 0 ) ) {
110- throw new Error ( 'Invalid Columns to Return: every entry must be a non-empty column id or name' )
111- }
112- return columns
113- }
114-
11598interface ParsedParams {
11699 tableId ?: string
117100 rowId ?: string
@@ -200,9 +183,7 @@ const paramTransformers: Record<string, (params: TableBlockParams) => ParsedPara
200183
201184 query_rows : ( params ) => ( {
202185 tableId : params . tableId ,
203- // The canvas selection wins; a model-supplied `columns` (Agent tool use) is the
204- // fallback so it is not clobbered by an empty canvas value when merged.
205- columns : resolveOutputColumns ( params . outputColumns ) ?? resolveOutputColumns ( params . columns ) ,
186+ columns : resolveTableColumnSelection ( params ) ,
206187 filter : resolveFilter ( params ) ,
207188 order : resolveOrder ( params ) ,
208189 // Omitted limit returns the entire result (server fails fast over 5MB);
@@ -342,19 +323,7 @@ export const TableV2Block: BlockConfig = {
342323 required : true ,
343324 } ,
344325
345- {
346- id : 'outputColumns' ,
347- title : 'Columns to Return' ,
348- type : 'dropdown' ,
349- selectorKey : 'table.outputColumns' ,
350- multiSelect : true ,
351- searchable : true ,
352- preserveLabelCase : true ,
353- placeholder : 'All columns' ,
354- description : 'Only include these columns in each returned row. Leave empty for all columns.' ,
355- dependsOn : { any : [ 'tableSelector' , 'manualTableId' ] } ,
356- condition : { field : 'operation' , value : 'query_rows' } ,
357- } ,
326+ TABLE_OUTPUT_COLUMNS_SUBBLOCK ,
358327
359328 {
360329 id : 'rowId' ,
@@ -590,10 +559,7 @@ Return ONLY the JSON object:`,
590559 data : { type : 'json' , description : 'Row data for insert/update' } ,
591560 rows : { type : 'array' , description : 'Array of row data for batch insert' } ,
592561 rowId : { type : 'string' , description : 'Row identifier for ID-based operations' } ,
593- outputColumns : {
594- type : 'array' ,
595- description : 'Table columns to include in each queried row; omit for all columns' ,
596- } ,
562+ outputColumns : TABLE_OUTPUT_COLUMNS_INPUT ,
597563 filterInput : {
598564 type : 'json' ,
599565 description :
0 commit comments