This commit is contained in:
Lakee Sivaraya
2026-01-14 10:24:19 -08:00
parent c1eef30578
commit a537ca7ebe
18 changed files with 116 additions and 117 deletions

View File

@@ -64,7 +64,14 @@ export async function GET(
id: table.id,
name: table.name,
description: table.description,
schema: table.schema,
schema: {
columns: (table.schema as any).columns.map((col: any) => ({
name: col.name,
type: col.type,
required: col.required ?? false,
unique: col.unique ?? false,
})),
},
rowCount: table.rowCount,
maxRows: table.maxRows,
createdAt: table.createdAt.toISOString(),

View File

@@ -172,6 +172,16 @@ export async function POST(request: NextRequest) {
)
}
// Normalize schema to ensure all fields have explicit defaults
const normalizedSchema = {
columns: params.schema.columns.map((col) => ({
name: col.name,
type: col.type,
required: col.required ?? false,
unique: col.unique ?? false,
})),
}
// Create table
const tableId = `tbl_${crypto.randomUUID().replace(/-/g, '')}`
const now = new Date()
@@ -183,7 +193,7 @@ export async function POST(request: NextRequest) {
workspaceId: params.workspaceId,
name: params.name,
description: params.description,
schema: params.schema,
schema: normalizedSchema,
maxRows: TABLE_LIMITS.MAX_ROWS_PER_TABLE,
rowCount: 0,
createdBy: authResult.userId,
@@ -279,6 +289,14 @@ export async function GET(request: NextRequest) {
return NextResponse.json({
tables: tables.map((t) => ({
...t,
schema: {
columns: (t.schema as any).columns.map((col: any) => ({
name: col.name,
type: col.type,
required: col.required ?? false,
unique: col.unique ?? false,
})),
},
createdAt: t.createdAt.toISOString(),
updatedAt: t.updatedAt.toISOString(),
})),

View File

@@ -28,6 +28,7 @@ export const TableBlock: BlockConfig<TableQueryResponse> = {
{ label: 'Update Row by ID', id: 'updateRow' },
{ label: 'Delete Row by ID', id: 'deleteRow' },
{ label: 'Get Row by ID', id: 'getRow' },
{ label: 'Get Schema', id: 'getSchema' },
],
value: () => 'queryRows',
},
@@ -449,6 +450,7 @@ Return ONLY the sort JSON:`,
'table_delete_rows_by_filter',
'table_query_rows',
'table_get_row',
'table_get_schema',
],
config: {
tool: (params) => {
@@ -462,6 +464,7 @@ Return ONLY the sort JSON:`,
deleteRowsByFilter: 'table_delete_rows_by_filter',
queryRows: 'table_query_rows',
getRow: 'table_get_row',
getSchema: 'table_get_schema',
}
return toolMap[params.operation] || 'table_query_rows'
},
@@ -583,6 +586,13 @@ Return ONLY the sort JSON:`,
}
}
// Get Schema
if (operation === 'getSchema') {
return {
tableId: rest.tableId,
}
}
// Query Rows
if (operation === 'queryRows') {
let filter: any
@@ -695,6 +705,16 @@ Return ONLY the sort JSON:`,
description: 'IDs of deleted rows',
condition: { field: 'operation', value: 'deleteRowsByFilter' },
},
name: {
type: 'string',
description: 'Table name',
condition: { field: 'operation', value: 'getSchema' },
},
columns: {
type: 'array',
description: 'Column definitions',
condition: { field: 'operation', value: 'getSchema' },
},
message: { type: 'string', description: 'Operation status message' },
},
}

View File

@@ -1376,6 +1376,7 @@ import {
tableDeleteRowsByFilterTool,
tableDeleteRowTool,
tableGetRowTool,
tableGetSchemaTool,
tableInsertRowTool,
tableListTool,
tableQueryRowsTool,
@@ -2726,6 +2727,7 @@ export const tools: Record<string, ToolConfig> = {
table_delete_rows_by_filter: tableDeleteRowsByFilterTool,
table_query_rows: tableQueryRowsTool,
table_get_row: tableGetRowTool,
table_get_schema: tableGetSchemaTool,
mailchimp_get_audiences: mailchimpGetAudiencesTool,
mailchimp_get_audience: mailchimpGetAudienceTool,
mailchimp_create_audience: mailchimpCreateAudienceTool,

View File

@@ -47,33 +47,6 @@ export const tableBatchInsertRowsTool: ToolConfig<
transformResponse: async (response): Promise<TableBatchInsertResponse> => {
const data = await response.json()
if (!response.ok) {
let errorMessage = data.error || 'Failed to batch insert rows'
// Include details if present
if (data.details) {
if (Array.isArray(data.details) && data.details.length > 0) {
// Check if details is array of error objects with row numbers
if (typeof data.details[0] === 'object' && 'row' in data.details[0]) {
const errorSummary = data.details
.map((detail: { row: number; errors: string[] }) => {
const rowErrors = detail.errors.join(', ')
return `Row ${detail.row}: ${rowErrors}`
})
.join('; ')
errorMessage = `${errorMessage}: ${errorSummary}`
} else {
// Simple array of strings
errorMessage = `${errorMessage}: ${data.details.join('; ')}`
}
} else if (typeof data.details === 'string') {
errorMessage = `${errorMessage}: ${data.details}`
}
}
throw new Error(errorMessage)
}
return {
success: true,
output: {

View File

@@ -52,10 +52,6 @@ export const tableCreateTool: ToolConfig<TableCreateParams, TableCreateResponse>
transformResponse: async (response): Promise<TableCreateResponse> => {
const data = await response.json()
if (!response.ok) {
throw new Error(data.error || 'Failed to create table')
}
return {
success: true,
output: {

View File

@@ -43,10 +43,6 @@ export const tableDeleteRowTool: ToolConfig<TableRowDeleteParams, TableDeleteRes
transformResponse: async (response): Promise<TableDeleteResponse> => {
const data = await response.json()
if (!response.ok) {
throw new Error(data.error || 'Failed to delete row')
}
return {
success: true,
output: {

View File

@@ -55,10 +55,6 @@ export const tableDeleteRowsByFilterTool: ToolConfig<
transformResponse: async (response): Promise<TableBulkOperationResponse> => {
const data = await response.json()
if (!response.ok) {
throw new Error(data.error || 'Failed to delete rows')
}
return {
success: true,
output: {

View File

@@ -40,10 +40,6 @@ export const tableGetRowTool: ToolConfig<TableRowGetParams, TableRowResponse> =
transformResponse: async (response): Promise<TableRowResponse> => {
const data = await response.json()
if (!response.ok) {
throw new Error(data.error || 'Failed to get row')
}
return {
success: true,
output: {

View File

@@ -0,0 +1,53 @@
import type { ToolConfig } from '@/tools/types'
import type { TableGetSchemaParams, TableGetSchemaResponse } from './types'
export const tableGetSchemaTool: ToolConfig<TableGetSchemaParams, TableGetSchemaResponse> = {
id: 'table_get_schema',
name: 'Get Schema',
description: 'Get the schema configuration of a table',
version: '1.0.0',
params: {
tableId: {
type: 'string',
required: true,
description: 'Table ID',
visibility: 'user-or-llm',
},
},
request: {
url: (params: any) => {
const workspaceId = params._context?.workspaceId
if (!workspaceId) {
throw new Error('workspaceId is required in execution context')
}
return `/api/table/${params.tableId}?workspaceId=${encodeURIComponent(workspaceId)}`
},
method: 'GET',
headers: () => ({
'Content-Type': 'application/json',
}),
},
transformResponse: async (response): Promise<TableGetSchemaResponse> => {
const data = await response.json()
return {
success: true,
output: {
name: data.table.name,
columns: data.table.schema.columns,
message: 'Schema retrieved successfully',
},
}
},
outputs: {
success: { type: 'boolean', description: 'Whether schema was retrieved' },
name: { type: 'string', description: 'Table name' },
columns: { type: 'array', description: 'Column definitions' },
message: { type: 'string', description: 'Status message' },
},
}

View File

@@ -3,6 +3,7 @@ export * from './create'
export * from './delete-row'
export * from './delete-rows-by-filter'
export * from './get-row'
export * from './get-schema'
export * from './insert-row'
export * from './list'
export * from './query-rows'

View File

@@ -44,22 +44,6 @@ export const tableInsertRowTool: ToolConfig<TableRowInsertParams, TableRowRespon
transformResponse: async (response): Promise<TableRowResponse> => {
const data = await response.json()
if (!response.ok) {
let errorMessage = data.error || 'Failed to insert row'
// Include details array if present
if (data.details) {
if (Array.isArray(data.details) && data.details.length > 0) {
const detailsStr = data.details.join('; ')
errorMessage = `${errorMessage}: ${detailsStr}`
} else if (typeof data.details === 'string') {
errorMessage = `${errorMessage}: ${data.details}`
}
}
throw new Error(errorMessage)
}
return {
success: true,
output: {

View File

@@ -26,10 +26,6 @@ export const tableListTool: ToolConfig<TableListParams, TableListResponse> = {
transformResponse: async (response): Promise<TableListResponse> => {
const data = await response.json()
if (!response.ok) {
throw new Error(data.error || 'Failed to list tables')
}
return {
success: true,
output: {

View File

@@ -76,10 +76,6 @@ export const tableQueryRowsTool: ToolConfig<TableRowQueryParams, TableQueryRespo
transformResponse: async (response): Promise<TableQueryResponse> => {
const data = await response.json()
if (!response.ok) {
throw new Error(data.error || 'Failed to query rows')
}
return {
success: true,
output: {

View File

@@ -185,3 +185,16 @@ export interface TableBulkOperationResponse extends ToolResponse {
message: string
}
}
export interface TableGetSchemaParams extends ToolParamsWithContext {
tableId: string
workspaceId?: string
}
export interface TableGetSchemaResponse extends ToolResponse {
output: {
name: string
columns: ColumnDefinition[]
message: string
}
}

View File

@@ -50,22 +50,6 @@ export const tableUpdateRowTool: ToolConfig<TableRowUpdateParams, TableRowRespon
transformResponse: async (response): Promise<TableRowResponse> => {
const data = await response.json()
if (!response.ok) {
let errorMessage = data.error || 'Failed to update row'
// Include details array if present
if (data.details) {
if (Array.isArray(data.details) && data.details.length > 0) {
const detailsStr = data.details.join('; ')
errorMessage = `${errorMessage}: ${detailsStr}`
} else if (typeof data.details === 'string') {
errorMessage = `${errorMessage}: ${data.details}`
}
}
throw new Error(errorMessage)
}
return {
success: true,
output: {

View File

@@ -62,22 +62,6 @@ export const tableUpdateRowsByFilterTool: ToolConfig<
transformResponse: async (response): Promise<TableBulkOperationResponse> => {
const data = await response.json()
if (!response.ok) {
let errorMessage = data.error || 'Failed to update rows'
// Include details array if present
if (data.details) {
if (Array.isArray(data.details) && data.details.length > 0) {
const detailsStr = data.details.join('; ')
errorMessage = `${errorMessage}: ${detailsStr}`
} else if (typeof data.details === 'string') {
errorMessage = `${errorMessage}: ${data.details}`
}
}
throw new Error(errorMessage)
}
return {
success: true,
output: {

View File

@@ -49,22 +49,6 @@ export const tableUpsertRowTool: ToolConfig<TableRowInsertParams, TableUpsertRes
transformResponse: async (response): Promise<TableUpsertResponse> => {
const data = await response.json()
if (!response.ok) {
let errorMessage = data.error || 'Failed to upsert row'
// Include details array if present
if (data.details) {
if (Array.isArray(data.details) && data.details.length > 0) {
const detailsStr = data.details.join('; ')
errorMessage = `${errorMessage}: ${detailsStr}`
} else if (typeof data.details === 'string') {
errorMessage = `${errorMessage}: ${data.details}`
}
}
throw new Error(errorMessage)
}
return {
success: true,
output: {