@aigne/afs-sqlite 1.11.0-beta.6 → 1.11.0-beta.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/dist/actions/built-in.cjs +870 -16
  2. package/dist/actions/built-in.d.cts.map +1 -1
  3. package/dist/actions/built-in.d.mts.map +1 -1
  4. package/dist/actions/built-in.mjs +870 -16
  5. package/dist/actions/built-in.mjs.map +1 -1
  6. package/dist/actions/operators.cjs +156 -0
  7. package/dist/actions/operators.mjs +157 -0
  8. package/dist/actions/operators.mjs.map +1 -0
  9. package/dist/actions/types.cjs +33 -0
  10. package/dist/actions/types.d.cts +22 -0
  11. package/dist/actions/types.d.cts.map +1 -1
  12. package/dist/actions/types.d.mts +22 -0
  13. package/dist/actions/types.d.mts.map +1 -1
  14. package/dist/actions/types.mjs +32 -0
  15. package/dist/actions/types.mjs.map +1 -0
  16. package/dist/index.cjs +2 -0
  17. package/dist/index.d.cts +1 -1
  18. package/dist/index.d.mts +1 -1
  19. package/dist/index.mjs +1 -1
  20. package/dist/node/builder.cjs +11 -8
  21. package/dist/node/builder.d.cts.map +1 -1
  22. package/dist/node/builder.d.mts.map +1 -1
  23. package/dist/node/builder.mjs +11 -8
  24. package/dist/node/builder.mjs.map +1 -1
  25. package/dist/operations/query-builder.cjs +2 -2
  26. package/dist/operations/query-builder.d.cts.map +1 -1
  27. package/dist/operations/query-builder.d.mts.map +1 -1
  28. package/dist/operations/query-builder.mjs +2 -2
  29. package/dist/operations/query-builder.mjs.map +1 -1
  30. package/dist/operations/search.cjs +1 -1
  31. package/dist/operations/search.mjs +1 -1
  32. package/dist/operations/search.mjs.map +1 -1
  33. package/dist/sqlite-afs.cjs +247 -26
  34. package/dist/sqlite-afs.d.cts +29 -4
  35. package/dist/sqlite-afs.d.cts.map +1 -1
  36. package/dist/sqlite-afs.d.mts +29 -4
  37. package/dist/sqlite-afs.d.mts.map +1 -1
  38. package/dist/sqlite-afs.mjs +248 -27
  39. package/dist/sqlite-afs.mjs.map +1 -1
  40. package/package.json +4 -3
@@ -1 +1 @@
1
- {"version":3,"file":"built-in.mjs","names":[],"sources":["../../src/actions/built-in.ts"],"sourcesContent":["import { sql } from \"@aigne/sqlite\";\nimport type { LibSQLDatabase } from \"drizzle-orm/libsql\";\nimport type { TableSchema } from \"../schema/types.js\";\nimport type { ActionsRegistry } from \"./registry.js\";\nimport type { ActionContext, ActionResult, SchemaGeneratorContext } from \"./types.js\";\n\n/**\n * Executes a raw SQL query and returns all rows\n */\nasync function execAll<T>(db: LibSQLDatabase, query: string): Promise<T[]> {\n return db.all<T>(sql.raw(query)).execute();\n}\n\n/**\n * Executes a raw SQL query (for INSERT, UPDATE, DELETE)\n */\nasync function execRun(db: LibSQLDatabase, query: string): Promise<void> {\n await db.run(sql.raw(query)).execute();\n}\n\n/**\n * Registers built-in actions to the registry\n */\nexport function registerBuiltInActions(registry: ActionsRegistry): void {\n // Export table action (table level)\n registry.register({\n name: \"export\",\n description: \"Export table data in specified format (json, csv)\",\n tableLevel: true,\n rowLevel: false,\n inputSchema: {\n type: \"object\",\n properties: {\n format: {\n type: \"string\",\n enum: [\"json\", \"csv\"],\n default: \"json\",\n },\n },\n },\n handler: async (ctx: ActionContext, params): Promise<ActionResult> => {\n const format = (params.format as string) ?? \"json\";\n const data = await ctx.module.exportTable(ctx.table, format);\n return {\n success: true,\n data,\n };\n },\n });\n\n // Count rows action (table level)\n registry.register({\n name: \"count\",\n description: \"Get the total row count for this table\",\n tableLevel: true,\n rowLevel: false,\n handler: async (ctx: ActionContext): Promise<ActionResult> => {\n const result = await execAll<{ count: number }>(\n ctx.db,\n `SELECT COUNT(*) as count FROM \"${ctx.table}\"`,\n );\n return {\n success: true,\n data: { count: result[0]?.count ?? 0 },\n };\n },\n });\n\n // Duplicate row action (row level)\n registry.register({\n name: \"duplicate\",\n description: \"Create a copy of this row\",\n tableLevel: false,\n rowLevel: true,\n inputSchemaGenerator: (schemaCtx: SchemaGeneratorContext) => {\n if (!schemaCtx.tableSchema) {\n return { type: \"object\", properties: {}, additionalProperties: false };\n }\n return generateDuplicateSchema(schemaCtx.tableSchema);\n },\n handler: async (ctx: ActionContext): Promise<ActionResult> => {\n if (!ctx.row) {\n return { success: false, message: \"Row data not available\" };\n }\n\n const schema = await ctx.schemaService.getSchema(ctx.table);\n if (!schema) {\n return { success: false, message: `Table '${ctx.table}' not found` };\n }\n\n // Create a copy without the primary key\n const pkColumn = schema.primaryKey[0] ?? \"rowid\";\n const rowCopy = { ...ctx.row };\n delete rowCopy[pkColumn];\n delete rowCopy.rowid;\n\n // Build insert query\n const columns = Object.keys(rowCopy);\n const values = columns.map((col) => formatValueForSQL(rowCopy[col]));\n\n await execRun(\n ctx.db,\n `INSERT INTO \"${ctx.table}\" (${columns.map((c) => `\"${c}\"`).join(\", \")}) VALUES (${values.join(\", \")})`,\n );\n\n // Get the new row's ID\n const lastIdResult = await execAll<{ id: number }>(\n ctx.db,\n \"SELECT last_insert_rowid() as id\",\n );\n\n return {\n success: true,\n data: { newId: lastIdResult[0]?.id },\n message: \"Row duplicated successfully\",\n };\n },\n });\n\n // Validate row action (row level)\n registry.register({\n name: \"validate\",\n description: \"Validate row data against schema constraints\",\n tableLevel: false,\n rowLevel: true,\n inputSchemaGenerator: (schemaCtx: SchemaGeneratorContext) => {\n if (!schemaCtx.tableSchema) {\n return { type: \"object\", properties: {}, additionalProperties: false };\n }\n return generateValidateSchema(schemaCtx.tableSchema);\n },\n handler: async (ctx: ActionContext): Promise<ActionResult> => {\n if (!ctx.row) {\n return { success: false, message: \"Row data not available\" };\n }\n\n const schema = await ctx.schemaService.getSchema(ctx.table);\n if (!schema) {\n return { success: false, message: `Table '${ctx.table}' not found` };\n }\n\n const errors: string[] = [];\n\n // Check NOT NULL constraints\n for (const col of schema.columns) {\n if (col.notnull && (ctx.row[col.name] === null || ctx.row[col.name] === undefined)) {\n errors.push(`Column '${col.name}' cannot be null`);\n }\n }\n\n // Check foreign key references\n for (const fk of schema.foreignKeys) {\n const value = ctx.row[fk.from];\n if (value !== null && value !== undefined) {\n const refResult = await execAll<{ count: number }>(\n ctx.db,\n `SELECT COUNT(*) as count FROM \"${fk.table}\" WHERE \"${fk.to}\" = '${String(value).replace(/'/g, \"''\")}'`,\n );\n if (refResult[0]?.count === 0) {\n errors.push(\n `Foreign key violation: ${fk.from} references non-existent ${fk.table}.${fk.to}`,\n );\n }\n }\n }\n\n return {\n success: errors.length === 0,\n data: { errors, valid: errors.length === 0 },\n message: errors.length > 0 ? `Validation failed: ${errors.join(\"; \")}` : \"Row is valid\",\n };\n },\n });\n\n // Create table action (root level)\n registry.register({\n name: \"create-table\",\n description: \"Create a new table in the database\",\n rootLevel: true,\n tableLevel: false,\n rowLevel: false,\n inputSchema: {\n type: \"object\",\n description: \"Create a new SQLite table with specified columns\",\n properties: {\n name: {\n type: \"string\",\n description: \"Table name (alphanumeric and underscores, must start with letter)\",\n pattern: \"^[a-zA-Z][a-zA-Z0-9_]*$\",\n minLength: 1,\n maxLength: 128,\n },\n columns: {\n type: \"array\",\n description: \"Column definitions (at least one required)\",\n minItems: 1,\n items: {\n type: \"object\",\n description: \"Column definition\",\n properties: {\n name: {\n type: \"string\",\n description: \"Column name (alphanumeric and underscores)\",\n pattern: \"^[a-zA-Z_][a-zA-Z0-9_]*$\",\n minLength: 1,\n maxLength: 128,\n },\n type: {\n type: \"string\",\n description: \"SQLite column type\",\n enum: [\n // SQLite native types\n \"INTEGER\",\n \"TEXT\",\n \"REAL\",\n \"BLOB\",\n \"NUMERIC\",\n // Common SQL types (mapped to SQLite affinities)\n \"INT\",\n \"TINYINT\",\n \"SMALLINT\",\n \"MEDIUMINT\",\n \"BIGINT\",\n \"UNSIGNED BIG INT\",\n \"INT2\",\n \"INT8\",\n \"CHARACTER\",\n \"VARCHAR\",\n \"VARYING CHARACTER\",\n \"NCHAR\",\n \"NATIVE CHARACTER\",\n \"NVARCHAR\",\n \"CLOB\",\n \"DOUBLE\",\n \"DOUBLE PRECISION\",\n \"FLOAT\",\n \"DECIMAL\",\n \"BOOLEAN\",\n \"DATE\",\n \"DATETIME\",\n \"TIMESTAMP\",\n ],\n \"x-affinity-mapping\": {\n INTEGER: [\n \"INTEGER\",\n \"INT\",\n \"TINYINT\",\n \"SMALLINT\",\n \"MEDIUMINT\",\n \"BIGINT\",\n \"UNSIGNED BIG INT\",\n \"INT2\",\n \"INT8\",\n ],\n TEXT: [\n \"TEXT\",\n \"CHARACTER\",\n \"VARCHAR\",\n \"VARYING CHARACTER\",\n \"NCHAR\",\n \"NATIVE CHARACTER\",\n \"NVARCHAR\",\n \"CLOB\",\n ],\n REAL: [\"REAL\", \"DOUBLE\", \"DOUBLE PRECISION\", \"FLOAT\"],\n NUMERIC: [\"NUMERIC\", \"DECIMAL\", \"BOOLEAN\", \"DATE\", \"DATETIME\", \"TIMESTAMP\"],\n BLOB: [\"BLOB\"],\n },\n },\n nullable: {\n type: \"boolean\",\n description: \"Whether the column allows NULL values (default: true)\",\n default: true,\n },\n primaryKey: {\n type: \"boolean\",\n description:\n \"Whether this column is the primary key (default: false). INTEGER PRIMARY KEY will auto-increment.\",\n default: false,\n },\n unique: {\n type: \"boolean\",\n description: \"Whether this column must have unique values (default: false)\",\n default: false,\n },\n defaultValue: {\n oneOf: [\n { type: \"string\" },\n { type: \"number\" },\n { type: \"boolean\" },\n { type: \"null\" },\n ],\n description:\n \"Default value for the column. Use string 'CURRENT_TIMESTAMP' for auto timestamp.\",\n },\n references: {\n type: \"object\",\n description: \"Foreign key reference\",\n properties: {\n table: {\n type: \"string\",\n description: \"Referenced table name\",\n },\n column: {\n type: \"string\",\n description: \"Referenced column name\",\n },\n onDelete: {\n type: \"string\",\n enum: [\"CASCADE\", \"SET NULL\", \"SET DEFAULT\", \"RESTRICT\", \"NO ACTION\"],\n description: \"Action on delete (default: NO ACTION)\",\n },\n onUpdate: {\n type: \"string\",\n enum: [\"CASCADE\", \"SET NULL\", \"SET DEFAULT\", \"RESTRICT\", \"NO ACTION\"],\n description: \"Action on update (default: NO ACTION)\",\n },\n },\n required: [\"table\", \"column\"],\n },\n },\n required: [\"name\", \"type\"],\n additionalProperties: false,\n },\n },\n ifNotExists: {\n type: \"boolean\",\n description: \"If true, do not throw error if table already exists (default: false)\",\n default: false,\n },\n },\n required: [\"name\", \"columns\"],\n additionalProperties: false,\n },\n handler: async (ctx: ActionContext, params): Promise<ActionResult> => {\n const tableName = params.name as string;\n const columns = params.columns as Array<{\n name: string;\n type: string;\n nullable?: boolean;\n primaryKey?: boolean;\n unique?: boolean;\n defaultValue?: string | number | boolean | null;\n references?: {\n table: string;\n column: string;\n onDelete?: string;\n onUpdate?: string;\n };\n }>;\n const ifNotExists = params.ifNotExists as boolean | undefined;\n\n // Validate required params\n if (!tableName) {\n throw new Error(\"Table name is required\");\n }\n if (!/^[a-zA-Z][a-zA-Z0-9_]*$/.test(tableName)) {\n throw new Error(\n \"Table name must start with a letter and contain only alphanumeric characters and underscores\",\n );\n }\n if (!columns || columns.length === 0) {\n throw new Error(\"At least one column is required\");\n }\n\n // Validate column names\n for (const col of columns) {\n if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(col.name)) {\n throw new Error(\n `Invalid column name: ${col.name}. Must start with a letter or underscore and contain only alphanumeric characters and underscores`,\n );\n }\n }\n\n // Validate column types\n const validTypes = [\n \"INTEGER\",\n \"TEXT\",\n \"REAL\",\n \"BLOB\",\n \"NUMERIC\",\n \"INT\",\n \"TINYINT\",\n \"SMALLINT\",\n \"MEDIUMINT\",\n \"BIGINT\",\n \"UNSIGNED BIG INT\",\n \"INT2\",\n \"INT8\",\n \"CHARACTER\",\n \"VARCHAR\",\n \"VARYING CHARACTER\",\n \"NCHAR\",\n \"NATIVE CHARACTER\",\n \"NVARCHAR\",\n \"CLOB\",\n \"DOUBLE\",\n \"DOUBLE PRECISION\",\n \"FLOAT\",\n \"DECIMAL\",\n \"BOOLEAN\",\n \"DATE\",\n \"DATETIME\",\n \"TIMESTAMP\",\n ];\n for (const col of columns) {\n const upperType = col.type.toUpperCase();\n if (!validTypes.includes(upperType)) {\n throw new Error(\n `Invalid column type: ${col.type}. Valid types are: ${validTypes.join(\", \")}`,\n );\n }\n }\n\n // Check if table already exists (unless ifNotExists is true)\n if (!ifNotExists) {\n const exists = await ctx.schemaService.hasTable(tableName);\n if (exists) {\n throw new Error(`Table '${tableName}' already exists`);\n }\n }\n\n // Build CREATE TABLE SQL\n const columnDefs: string[] = [];\n const foreignKeys: string[] = [];\n\n for (const col of columns) {\n const parts = [`\"${col.name}\"`, col.type.toUpperCase()];\n\n if (col.primaryKey) {\n parts.push(\"PRIMARY KEY\");\n // Only auto-increment for INTEGER primary keys\n if (col.type.toUpperCase() === \"INTEGER\" || col.type.toUpperCase() === \"INT\") {\n parts.push(\"AUTOINCREMENT\");\n }\n }\n\n if (col.nullable === false && !col.primaryKey) {\n parts.push(\"NOT NULL\");\n }\n\n if (col.unique && !col.primaryKey) {\n parts.push(\"UNIQUE\");\n }\n\n if (col.defaultValue !== undefined) {\n // Handle special default values\n if (\n col.defaultValue === \"CURRENT_TIMESTAMP\" ||\n col.defaultValue === \"CURRENT_DATE\" ||\n col.defaultValue === \"CURRENT_TIME\"\n ) {\n parts.push(`DEFAULT ${col.defaultValue}`);\n } else {\n parts.push(`DEFAULT ${formatValueForSQL(col.defaultValue)}`);\n }\n }\n\n columnDefs.push(parts.join(\" \"));\n\n // Handle foreign key references\n if (col.references) {\n let fkDef = `FOREIGN KEY (\"${col.name}\") REFERENCES \"${col.references.table}\"(\"${col.references.column}\")`;\n if (col.references.onDelete) {\n fkDef += ` ON DELETE ${col.references.onDelete}`;\n }\n if (col.references.onUpdate) {\n fkDef += ` ON UPDATE ${col.references.onUpdate}`;\n }\n foreignKeys.push(fkDef);\n }\n }\n\n // Combine column definitions and foreign keys\n const allDefs = [...columnDefs, ...foreignKeys];\n const ifNotExistsClause = ifNotExists ? \"IF NOT EXISTS \" : \"\";\n const createSQL = `CREATE TABLE ${ifNotExistsClause}\"${tableName}\" (${allDefs.join(\", \")})`;\n\n await execRun(ctx.db, createSQL);\n\n return {\n success: true,\n data: {\n tableName,\n columnCount: columns.length,\n sql: createSQL,\n },\n message: `Table '${tableName}' created successfully`,\n };\n },\n });\n\n // Insert action (table level)\n registry.register({\n name: \"insert\",\n description: \"Insert a new row into the table\",\n rootLevel: false,\n tableLevel: true,\n rowLevel: false,\n // Dynamic schema generator - generates schema based on table columns\n inputSchemaGenerator: (schemaCtx: SchemaGeneratorContext) => {\n if (!schemaCtx.tableSchema) {\n // Fallback to generic schema if no table schema available\n return {\n type: \"object\",\n properties: {\n data: {\n type: \"object\",\n description: \"Row data to insert (column names as keys)\",\n additionalProperties: true,\n },\n },\n required: [\"data\"],\n };\n }\n return generateInsertSchema(schemaCtx.tableSchema);\n },\n handler: async (ctx: ActionContext, params): Promise<ActionResult> => {\n const data = params.data as Record<string, unknown>;\n\n if (!data || Object.keys(data).length === 0) {\n throw new Error(\"Insert data is required\");\n }\n\n const schema = await ctx.schemaService.getSchema(ctx.table);\n if (!schema) {\n throw new Error(`Table '${ctx.table}' not found`);\n }\n\n // Build insert query\n const columns = Object.keys(data);\n const values = columns.map((col) => formatValueForSQL(data[col]));\n\n const insertSQL = `INSERT INTO \"${ctx.table}\" (${columns.map((c) => `\"${c}\"`).join(\", \")}) VALUES (${values.join(\", \")})`;\n\n try {\n await execRun(ctx.db, insertSQL);\n } catch (error) {\n // Re-throw with more context\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(`Insert failed: ${message}`);\n }\n\n // Get the new row's ID\n const lastIdResult = await execAll<{ id: number }>(\n ctx.db,\n \"SELECT last_insert_rowid() as id\",\n );\n const newId = lastIdResult[0]?.id;\n\n return {\n success: true,\n data: { id: newId, ...data },\n message: `Row inserted successfully with id ${newId}`,\n };\n },\n });\n}\n\n/**\n * Formats a value for SQL insertion\n */\nfunction formatValueForSQL(value: unknown): string {\n if (value === null || value === undefined) {\n return \"NULL\";\n }\n if (typeof value === \"number\") {\n return String(value);\n }\n if (typeof value === \"boolean\") {\n return value ? \"1\" : \"0\";\n }\n if (value instanceof Date) {\n return `'${value.toISOString()}'`;\n }\n if (typeof value === \"object\") {\n return `'${JSON.stringify(value).replace(/'/g, \"''\")}'`;\n }\n return `'${String(value).replace(/'/g, \"''\")}'`;\n}\n\n/**\n * Maps SQLite column type to JSON Schema type\n */\nfunction sqliteTypeToJsonSchema(sqliteType: string): {\n type: string;\n format?: string;\n description?: string;\n} {\n const upperType = sqliteType.toUpperCase();\n\n if (upperType.includes(\"INT\")) {\n return { type: \"integer\" };\n }\n if (upperType.includes(\"REAL\") || upperType.includes(\"FLOAT\") || upperType.includes(\"DOUBLE\")) {\n return { type: \"number\" };\n }\n if (upperType.includes(\"BOOL\")) {\n return { type: \"boolean\", description: \"Stored as INTEGER (0/1)\" };\n }\n if (upperType.includes(\"DATE\") || upperType.includes(\"TIME\")) {\n return { type: \"string\", format: \"date-time\" };\n }\n if (upperType.includes(\"BLOB\")) {\n return { type: \"string\", format: \"binary\", description: \"Base64 encoded binary data\" };\n }\n // TEXT and everything else\n return { type: \"string\" };\n}\n\n/**\n * Generates JSON Schema for insert action based on table schema\n */\nfunction generateInsertSchema(tableSchema: TableSchema): Record<string, unknown> {\n const properties: Record<string, unknown> = {};\n const required: string[] = [];\n\n for (const col of tableSchema.columns) {\n // Skip auto-increment primary keys (they're auto-generated)\n const isPrimaryKeyAutoIncrement = col.pk > 0 && col.type.toUpperCase().includes(\"INTEGER\");\n if (isPrimaryKeyAutoIncrement) {\n continue;\n }\n\n const typeInfo = sqliteTypeToJsonSchema(col.type);\n const propSchema: Record<string, unknown> = {\n ...typeInfo,\n };\n\n // Add default value info if present\n if (col.dfltValue !== null) {\n propSchema.default = col.dfltValue;\n propSchema.description =\n `${propSchema.description ?? \"\"}${propSchema.description ? \". \" : \"\"}Default: ${col.dfltValue}`.trim();\n }\n\n // Track required fields (NOT NULL without default)\n if (col.notnull && col.dfltValue === null && col.pk === 0) {\n required.push(col.name);\n }\n\n properties[col.name] = propSchema;\n }\n\n return {\n type: \"object\",\n description: `Insert a new row into \"${tableSchema.name}\" table`,\n properties: {\n data: {\n type: \"object\",\n description: \"Row data to insert\",\n properties,\n required: required.length > 0 ? required : undefined,\n additionalProperties: false,\n },\n },\n required: [\"data\"],\n };\n}\n\n/**\n * Generates JSON Schema for validate action based on table schema\n */\nfunction generateValidateSchema(tableSchema: TableSchema): Record<string, unknown> {\n const columnInfo = tableSchema.columns.map((col) => ({\n name: col.name,\n type: col.type,\n nullable: !col.notnull,\n primaryKey: col.pk > 0,\n }));\n\n const foreignKeyInfo = tableSchema.foreignKeys.map((fk) => ({\n column: fk.from,\n references: `${fk.table}.${fk.to}`,\n }));\n\n return {\n type: \"object\",\n description: `Validate row data against \"${tableSchema.name}\" table constraints`,\n properties: {},\n additionalProperties: false,\n // Include schema info in metadata for documentation\n \"x-table-schema\": {\n columns: columnInfo,\n foreignKeys: foreignKeyInfo,\n },\n };\n}\n\n/**\n * Generates JSON Schema for duplicate action based on table schema\n */\nfunction generateDuplicateSchema(tableSchema: TableSchema): Record<string, unknown> {\n const pkColumn = tableSchema.primaryKey[0] ?? \"rowid\";\n const copiedColumns = tableSchema.columns\n .filter((col) => col.name !== pkColumn)\n .map((col) => col.name);\n\n return {\n type: \"object\",\n description: `Create a copy of the row (excluding primary key \"${pkColumn}\")`,\n properties: {},\n additionalProperties: false,\n \"x-copied-columns\": copiedColumns,\n };\n}\n"],"mappings":"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AK;IAC1E;;EAEJ,CAAC;AAGF,UAAS,SAAS;EAChB,MAAM;EACN,aAAa;EACb,WAAW;EACX,YAAY;EACZ,UAAU;EACV,aAAa;GACX,MAAM;GACN,aAAa;GACb,YAAY;IACV,MAAM;KACJ,MAAM;KACN,aAAa;KACb,SAAS;KACT,WAAW;KACX,WAAW;KACZ;IACD,SAAS;KACP,MAAM;KACN,aAAa;KACb,UAAU;KACV,OAAO;MACL,MAAM;MACN,aAAa;MACb,YAAY;OACV,MAAM;QACJ,MAAM;QACN,aAAa;QACb,SAAS;QACT,WAAW;QACX,WAAW;QACZ;OACD,MAAM;QACJ,MAAM;QACN,aAAa;QACb,MAAM;SAEJ;SACA;SACA;SACA;SACA;SAEA;SACA;SACA;SACA;SACA;SACA;SACA;SACA;SACA;SACA;SACA;SACA;SACA;SACA;SACA;SACA;SACA;SACA;SACA;SACA;SACA;SACA;SACA;SACD;QACD,sBAAsB;SACpB,SAAS;UACP;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACD;SACD,MAAM;UACJ;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACD;SACD,MAAM;UAAC;UAAQ;UAAU;UAAoB;UAAQ;SACrD,SAAS;UAAC;UAAW;UAAW;UAAW;UAAQ;UAAY;UAAY;SAC3E,MAAM,CAAC,OAAO;SACf;QACF;OACD,UAAU;QACR,MAAM;QACN,aAAa;QACb,SAAS;QACV;OACD,YAAY;QACV,MAAM;QACN,aACE;QACF,SAAS;QACV;OACD,QAAQ;QACN,MAAM;QACN,aAAa;QACb,SAAS;QACV;OACD,cAAc;QACZ,OAAO;SACL,EAAE,MAAM,UAAU;SAClB,EAAE,MAAM,UAAU;SAClB,EAAE,MAAM,WAAW;SACnB,EAAE,MAAM,QAAQ;SACjB;QACD,aACE;QACH;OACD,YAAY;QACV,MAAM;QACN,aAAa;QACb,YAAY;SACV,OAAO;UACL,MAAM;UACN,aAAa;UACd;SACD,QAAQ;UACN,MAAM;UACN,aAAa;UACd;SACD,UAAU;UACR,MAAM;UACN,MAAM;WAAC;WAAW;WAAY;WAAe;WAAY;WAAY;UACrE,aAAa;UACd;SACD,UAAU;UACR,MAAM;UACN,MAAM;WAAC;WAAW;WAAY;WAAe;WAAY;WAAY;UACrE,aAAa;UACd;SACF;QACD,UAAU,CAAC,SAAS,SAAS;QAC9B;OACF;MACD,UAAU,CAAC,QAAQ,OAAO;MAC1B,sBAAsB;MACvB;KACF;IACD,aAAa;KACX,MAAM;KACN,aAAa;KACb,SAAS;KACV;IACF;GACD,UAAU,CAAC,QAAQ,UAAU;GAC7B,sBAAsB;GACvB;EACD,SAAS,OAAO,KAAoB,WAAkC;GACpE,MAAM,YAAY,OAAO;GACzB,MAAM,UAAU,OAAO;GAcvB,MAAM,cAAc,OAAO;AAG3B,OAAI,CAAC,UACH,OAAM,IAAI,MAAM,yBAAyB;AAE3C,OAAI,CAAC,0BAA0B,KAAK,UAAU,CAC5C,OAAM,IAAI,MACR,+FACD;AAEH,OAAI,CAAC,WAAW,QAAQ,WAAW,EACjC,OAAM,IAAI,MAAM,kCAAkC;AAIpD,QAAK,MAAM,OAAO,QAChB,KAAI,CAAC,2BAA2B,KAAK,IAAI,KAAK,CAC5C,OAAM,IAAI,MACR,wBAAwB,IAAI,KAAK,mGAClC;GAKL,MAAM,aAAa;IACjB;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACD;AACD,QAAK,MAAM,OAAO,SAAS;IACzB,MAAM,YAAY,IAAI,KAAK,aAAa;AACxC,QAAI,CAAC,WAAW,SAAS,UAAU,CACjC,OAAM,IAAI,MACR,wBAAwB,IAAI,KAAK,qBAAqB,WAAW,KAAK,KAAK,GAC5E;;AAKL,OAAI,CAAC,aAEH;QADe,MAAM,IAAI,cAAc,SAAS,UAAU,CAExD,OAAM,IAAI,MAAM,UAAU,UAAU,kBAAkB;;GAK1D,MAAM,aAAuB,EAAE;GAC/B,MAAM,cAAwB,EAAE;AAEhC,QAAK,MAAM,OAAO,SAAS;IACzB,MAAM,QAAQ,CAAC,IAAI,IAAI,KAAK,IAAI,IAAI,KAAK,aAAa,CAAC;AAEvD,QAAI,IAAI,YAAY;AAClB,WAAM,KAAK,cAAc;AAEzB,SAAI,IAAI,KAAK,aAAa,KAAK,aAAa,IAAI,KAAK,aAAa,KAAK,MACrE,OAAM,KAAK,gBAAgB;;AAI/B,QAAI,IAAI,aAAa,SAAS,CAAC,IAAI,WACjC,OAAM,KAAK,WAAW;AAGxB,QAAI,IAAI,UAAU,CAAC,IAAI,WACrB,OAAM,KAAK,SAAS;AAGtB,QAAI,IAAI,iBAAiB,OAEvB,KACE,IAAI,iBAAiB,uBACrB,IAAI,iBAAiB,kBACrB,IAAI,iBAAiB,eAErB,OAAM,KAAK,WAAW,IAAI,eAAe;QAEzC,OAAM,KAAK,WAAW,kBAAkB,IAAI,aAAa,GAAG;AAIhE,eAAW,KAAK,MAAM,KAAK,IAAI,CAAC;AAGhC,QAAI,IAAI,YAAY;KAClB,IAAI,QAAQ,iBAAiB,IAAI,KAAK,iBAAiB,IAAI,WAAW,MAAM,KAAK,IAAI,WAAW,OAAO;AACvG,SAAI,IAAI,WAAW,SACjB,UAAS,cAAc,IAAI,WAAW;AAExC,SAAI,IAAI,WAAW,SACjB,UAAS,cAAc,IAAI,WAAW;AAExC,iBAAY,KAAK,MAAM;;;GAK3B,MAAM,UAAU,CAAC,GAAG,YAAY,GAAG,YAAY;GAE/C,MAAM,YAAY,gBADQ,cAAc,mBAAmB,GACP,GAAG,UAAU,KAAK,QAAQ,KAAK,KAAK,CAAC;AAEzF,SAAM,QAAQ,IAAI,IAAI,UAAU;AAEhC,UAAO;IACL,SAAS;IACT,MAAM;KACJ;KACA,aAAa,QAAQ;KACrB,KAAK;KACN;IACD,SAAS,UAAU,UAAU;IAC9B;;EAEJ,CAAC;AAGF,UAAS,SAAS;EAChB,MAAM;EACN,aAAa;EACb,WAAW;EACX,YAAY;EACZ,UAAU;EAEV,uBAAuB,cAAsC;AAC3D,OAAI,CAAC,UAAU,YAEb,QAAO;IACL,MAAM;IACN,YAAY,EACV,MAAM;KACJ,MAAM;KACN,aAAa;KACb,sBAAsB;KACvB,EACF;IACD,UAAU,CAAC,OAAO;IACnB;AAEH,UAAO,qBAAqB,UAAU,YAAY;;EAEpD,SAAS,OAAO,KAAoB,WAAkC;GACpE,MAAM,OAAO,OAAO;AAEpB,OAAI,CAAC,QAAQ,OAAO,KAAK,KAAK,CAAC,WAAW,EACxC,OAAM,IAAI,MAAM,0BAA0B;AAI5C,OAAI,CADW,MAAM,IAAI,cAAc,UAAU,IAAI,MAAM,CAEzD,OAAM,IAAI,MAAM,UAAU,IAAI,MAAM,aAAa;GAInD,MAAM,UAAU,OAAO,KAAK,KAAK;GACjC,MAAM,SAAS,QAAQ,KAAK,QAAQ,kBAAkB,KAAK,KAAK,CAAC;GAEjE,MAAM,YAAY,gBAAgB,IAAI,MAAM,KAAK,QAAQ,KAAK,MAAM,IAAI,EAAE,GAAG,CAAC,KAAK,KAAK,CAAC,YAAY,OAAO,KAAK,KAAK,CAAC;AAEvH,OAAI;AACF,UAAM,QAAQ,IAAI,IAAI,UAAU;YACzB,OAAO;IAEd,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;AACtE,UAAM,IAAI,MAAM,kBAAkB,UAAU;;GAQ9C,MAAM,SAJe,MAAM,QACzB,IAAI,IACJ,mCACD,EAC0B,IAAI;AAE/B,UAAO;IACL,SAAS;IACT,MAAM;KAAE,IAAI;KAAO,GAAG;KAAM;IAC5B,SAAS,qCAAqC;IAC/C;;EAEJ,CAAC;;;;;AAMJ,SAAS,kBAAkB,OAAwB;AACjD,KAAI,UAAU,QAAQ,UAAU,OAC9B,QAAO;AAET,KAAI,OAAO,UAAU,SACnB,QAAO,OAAO,MAAM;AAEtB,KAAI,OAAO,UAAU,UACnB,QAAO,QAAQ,MAAM;AAEvB,KAAI,iBAAiB,KACnB,QAAO,IAAI,MAAM,aAAa,CAAC;AAEjC,KAAI,OAAO,UAAU,SACnB,QAAO,IAAI,KAAK,UAAU,MAAM,CAAC,QAAQ,MAAM,KAAK,CAAC;AAEvD,QAAO,IAAI,OAAO,MAAM,CAAC,QAAQ,MAAM,KAAK,CAAC;;;;;AAM/C,SAAS,uBAAuB,YAI9B;CACA,MAAM,YAAY,WAAW,aAAa;AAE1C,KAAI,UAAU,SAAS,MAAM,CAC3B,QAAO,EAAE,MAAM,WAAW;AAE5B,KAAI,UAAU,SAAS,OAAO,IAAI,UAAU,SAAS,QAAQ,IAAI,UAAU,SAAS,SAAS,CAC3F,QAAO,EAAE,MAAM,UAAU;AAE3B,KAAI,UAAU,SAAS,OAAO,CAC5B,QAAO;EAAE,MAAM;EAAW,aAAa;EAA2B;AAEpE,KAAI,UAAU,SAAS,OAAO,IAAI,UAAU,SAAS,OAAO,CAC1D,QAAO;EAAE,MAAM;EAAU,QAAQ;EAAa;AAEhD,KAAI,UAAU,SAAS,OAAO,CAC5B,QAAO;EAAE,MAAM;EAAU,QAAQ;EAAU,aAAa;EAA8B;AAGxF,QAAO,EAAE,MAAM,UAAU;;;;;AAM3B,SAAS,qBAAqB,aAAmD;CAC/E,MAAM,aAAsC,EAAE;CAC9C,MAAM,WAAqB,EAAE;AAE7B,MAAK,MAAM,OAAO,YAAY,SAAS;AAGrC,MADkC,IAAI,KAAK,KAAK,IAAI,KAAK,aAAa,CAAC,SAAS,UAAU,CAExF;EAIF,MAAM,aAAsC,EAC1C,GAFe,uBAAuB,IAAI,KAAK,EAGhD;AAGD,MAAI,IAAI,cAAc,MAAM;AAC1B,cAAW,UAAU,IAAI;AACzB,cAAW,cACT,GAAG,WAAW,eAAe,KAAK,WAAW,cAAc,OAAO,GAAG,WAAW,IAAI,YAAY,MAAM;;AAI1G,MAAI,IAAI,WAAW,IAAI,cAAc,QAAQ,IAAI,OAAO,EACtD,UAAS,KAAK,IAAI,KAAK;AAGzB,aAAW,IAAI,QAAQ;;AAGzB,QAAO;EACL,MAAM;EACN,aAAa,0BAA0B,YAAY,KAAK;EACxD,YAAY,EACV,MAAM;GACJ,MAAM;GACN,aAAa;GACb;GACA,UAAU,SAAS,SAAS,IAAI,WAAW;GAC3C,sBAAsB;GACvB,EACF;EACD,UAAU,CAAC,OAAO;EACnB;;;;;AAMH,SAAS,uBAAuB,aAAmD;CACjF,MAAM,aAAa,YAAY,QAAQ,KAAK,SAAS;EACnD,MAAM,IAAI;EACV,MAAM,IAAI;EACV,UAAU,CAAC,IAAI;EACf,YAAY,IAAI,KAAK;EACtB,EAAE;CAEH,MAAM,iBAAiB,YAAY,YAAY,KAAK,QAAQ;EAC1D,QAAQ,GAAG;EACX,YAAY,GAAG,GAAG,MAAM,GAAG,GAAG;EAC/B,EAAE;AAEH,QAAO;EACL,MAAM;EACN,aAAa,8BAA8B,YAAY,KAAK;EAC5D,YAAY,EAAE;EACd,sBAAsB;EAEtB,kBAAkB;GAChB,SAAS;GACT,aAAa;GACd;EACF;;;;;AAMH,SAAS,wBAAwB,aAAmD;CAClF,MAAM,WAAW,YAAY,WAAW,MAAM;CAC9C,MAAM,gBAAgB,YAAY,QAC/B,QAAQ,QAAQ,IAAI,SAAS,SAAS,CACtC,KAAK,QAAQ,IAAI,KAAK;AAEzB,QAAO;EACL,MAAM;EACN,aAAa,oDAAoD,SAAS;EAC1E,YAAY,EAAE;EACd,sBAAsB;EACtB,oBAAoB;EACrB"}
1
+ {"version":3,"file":"built-in.mjs","names":[],"sources":["../../src/actions/built-in.ts"],"sourcesContent":["import type { SQL } from \"@aigne/sqlite\";\nimport { sql } from \"@aigne/sqlite\";\nimport type { LibSQLDatabase } from \"drizzle-orm/libsql\";\nimport type { TableSchema } from \"../schema/types.js\";\nimport { buildWhereClause, type WhereClause } from \"./operators.js\";\nimport type { ActionsRegistry } from \"./registry.js\";\nimport {\n type ActionContext,\n type ActionResult,\n errorResult,\n type SchemaGeneratorContext,\n SQLiteActionErrorCode,\n} from \"./types.js\";\n\n/**\n * Executes a raw SQL query and returns all rows\n */\nasync function execAll<T>(db: LibSQLDatabase, query: string): Promise<T[]> {\n return db.all<T>(sql.raw(query)).execute();\n}\n\n/**\n * Executes a raw SQL query (for INSERT, UPDATE, DELETE)\n */\nasync function execRun(db: LibSQLDatabase, query: string): Promise<void> {\n await db.run(sql.raw(query)).execute();\n}\n\n/**\n * Executes a parameterized SQL query and returns all rows\n */\nasync function execSql<T>(db: LibSQLDatabase, sqlQuery: SQL): Promise<T[]> {\n return db.all<T>(sqlQuery).execute();\n}\n\n/**\n * Executes a parameterized SQL statement (for INSERT, UPDATE, DELETE)\n */\nasync function runSql(db: LibSQLDatabase, sqlQuery: SQL): Promise<{ changes: number }> {\n const result = await db.run(sqlQuery).execute();\n return { changes: result.rowsAffected };\n}\n\n/**\n * Registers built-in actions to the registry\n */\nexport function registerBuiltInActions(registry: ActionsRegistry): void {\n // Export table action (table level)\n registry.register({\n name: \"export\",\n description: \"Export table data in specified format (json, csv)\",\n tableLevel: true,\n rowLevel: false,\n inputSchema: {\n type: \"object\",\n properties: {\n format: {\n type: \"string\",\n enum: [\"json\", \"csv\"],\n default: \"json\",\n },\n },\n },\n handler: async (ctx: ActionContext, params): Promise<ActionResult> => {\n const format = (params.format as string) ?? \"json\";\n const data = await ctx.module.exportTable(ctx.table, format);\n return {\n success: true,\n data,\n };\n },\n });\n\n // Count rows action (table level)\n registry.register({\n name: \"count\",\n description: \"Get the total row count for this table\",\n tableLevel: true,\n rowLevel: false,\n handler: async (ctx: ActionContext): Promise<ActionResult> => {\n const result = await execAll<{ count: number }>(\n ctx.db,\n `SELECT COUNT(*) as count FROM \"${ctx.table}\"`,\n );\n return {\n success: true,\n data: { count: result[0]?.count ?? 0 },\n };\n },\n });\n\n // Duplicate row action (row level)\n registry.register({\n name: \"duplicate\",\n description: \"Create a copy of this row\",\n tableLevel: false,\n rowLevel: true,\n inputSchemaGenerator: (schemaCtx: SchemaGeneratorContext) => {\n if (!schemaCtx.tableSchema) {\n return { type: \"object\", properties: {}, additionalProperties: false };\n }\n return generateDuplicateSchema(schemaCtx.tableSchema);\n },\n handler: async (ctx: ActionContext): Promise<ActionResult> => {\n if (!ctx.row) {\n return { success: false, message: \"Row data not available\" };\n }\n\n const schema = await ctx.schemaService.getSchema(ctx.table);\n if (!schema) {\n return { success: false, message: `Table '${ctx.table}' not found` };\n }\n\n // Create a copy without the primary key\n const pkColumn = schema.primaryKey[0] ?? \"rowid\";\n const rowCopy = { ...ctx.row };\n delete rowCopy[pkColumn];\n delete rowCopy.rowid;\n\n // Build insert query\n const columns = Object.keys(rowCopy);\n const values = columns.map((col) => formatValueForSQL(rowCopy[col]));\n\n await execRun(\n ctx.db,\n `INSERT INTO \"${ctx.table}\" (${columns.map((c) => `\"${c}\"`).join(\", \")}) VALUES (${values.join(\", \")})`,\n );\n\n // Get the new row's ID\n const lastIdResult = await execAll<{ id: number }>(\n ctx.db,\n \"SELECT last_insert_rowid() as id\",\n );\n\n return {\n success: true,\n data: { newId: lastIdResult[0]?.id },\n message: \"Row duplicated successfully\",\n };\n },\n });\n\n // Validate row action (row level)\n registry.register({\n name: \"validate\",\n description: \"Validate row data against schema constraints\",\n tableLevel: false,\n rowLevel: true,\n inputSchemaGenerator: (schemaCtx: SchemaGeneratorContext) => {\n if (!schemaCtx.tableSchema) {\n return { type: \"object\", properties: {}, additionalProperties: false };\n }\n return generateValidateSchema(schemaCtx.tableSchema);\n },\n handler: async (ctx: ActionContext): Promise<ActionResult> => {\n if (!ctx.row) {\n return { success: false, message: \"Row data not available\" };\n }\n\n const schema = await ctx.schemaService.getSchema(ctx.table);\n if (!schema) {\n return { success: false, message: `Table '${ctx.table}' not found` };\n }\n\n const errors: string[] = [];\n\n // Check NOT NULL constraints\n for (const col of schema.columns) {\n if (col.notnull && (ctx.row[col.name] === null || ctx.row[col.name] === undefined)) {\n errors.push(`Column '${col.name}' cannot be null`);\n }\n }\n\n // Check foreign key references\n for (const fk of schema.foreignKeys) {\n const value = ctx.row[fk.from];\n if (value !== null && value !== undefined) {\n const refResult = await execAll<{ count: number }>(\n ctx.db,\n `SELECT COUNT(*) as count FROM \"${fk.table}\" WHERE \"${fk.to}\" = '${String(value).replace(/'/g, \"''\")}'`,\n );\n if (refResult[0]?.count === 0) {\n errors.push(\n `Foreign key violation: ${fk.from} references non-existent ${fk.table}.${fk.to}`,\n );\n }\n }\n }\n\n return {\n success: errors.length === 0,\n data: { errors, valid: errors.length === 0 },\n message: errors.length > 0 ? `Validation failed: ${errors.join(\"; \")}` : \"Row is valid\",\n };\n },\n });\n\n // Insert action (table level)\n registry.register({\n name: \"insert\",\n description: \"Insert a new row into the table\",\n rootLevel: false,\n tableLevel: true,\n rowLevel: false,\n // Dynamic schema generator - generates schema based on table columns\n inputSchemaGenerator: (schemaCtx: SchemaGeneratorContext) => {\n if (!schemaCtx.tableSchema) {\n // Fallback to generic schema if no table schema available\n return {\n type: \"object\",\n properties: {\n data: {\n type: \"object\",\n description: \"Row data to insert (column names as keys)\",\n additionalProperties: true,\n },\n },\n required: [\"data\"],\n };\n }\n return generateInsertSchema(schemaCtx.tableSchema);\n },\n handler: async (ctx: ActionContext, params): Promise<ActionResult> => {\n const data = params.data as Record<string, unknown>;\n\n if (!data || Object.keys(data).length === 0) {\n throw new Error(\"Insert data is required\");\n }\n\n const schema = await ctx.schemaService.getSchema(ctx.table);\n if (!schema) {\n throw new Error(`Table '${ctx.table}' not found`);\n }\n\n // Build insert query\n const columns = Object.keys(data);\n const values = columns.map((col) => formatValueForSQL(data[col]));\n\n const insertSQL = `INSERT INTO \"${ctx.table}\" (${columns.map((c) => `\"${c}\"`).join(\", \")}) VALUES (${values.join(\", \")})`;\n\n try {\n await execRun(ctx.db, insertSQL);\n } catch (error) {\n // Re-throw with more context\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(`Insert failed: ${message}`);\n }\n\n // Get the new row's ID\n const lastIdResult = await execAll<{ id: number }>(\n ctx.db,\n \"SELECT last_insert_rowid() as id\",\n );\n const newId = lastIdResult[0]?.id;\n\n return {\n success: true,\n data: { id: newId, ...data },\n message: `Row inserted successfully with id ${newId}`,\n };\n },\n });\n\n // create_table - Root level action to create a new table\n registry.register({\n name: \"create_table\",\n description: \"Create a new table in the database\",\n rootLevel: true,\n tableLevel: false,\n rowLevel: false,\n inputSchema: {\n type: \"object\",\n description: \"Create a new SQLite table with specified columns\",\n properties: {\n name: {\n type: \"string\",\n description: \"Table name (alphanumeric and underscores, must start with letter)\",\n pattern: \"^[a-zA-Z][a-zA-Z0-9_]*$\",\n minLength: 1,\n maxLength: 128,\n },\n columns: {\n type: \"array\",\n description: \"Column definitions (at least one required)\",\n minItems: 1,\n items: {\n type: \"object\",\n description: \"Column definition\",\n properties: {\n name: {\n type: \"string\",\n description: \"Column name (alphanumeric and underscores)\",\n pattern: \"^[a-zA-Z_][a-zA-Z0-9_]*$\",\n minLength: 1,\n maxLength: 128,\n },\n type: {\n type: \"string\",\n description: \"SQLite column type\",\n enum: [\n // SQLite native types\n \"INTEGER\",\n \"TEXT\",\n \"REAL\",\n \"BLOB\",\n \"NUMERIC\",\n // Common SQL types (mapped to SQLite affinities)\n \"INT\",\n \"TINYINT\",\n \"SMALLINT\",\n \"MEDIUMINT\",\n \"BIGINT\",\n \"UNSIGNED BIG INT\",\n \"INT2\",\n \"INT8\",\n \"CHARACTER\",\n \"VARCHAR\",\n \"VARYING CHARACTER\",\n \"NCHAR\",\n \"NATIVE CHARACTER\",\n \"NVARCHAR\",\n \"CLOB\",\n \"DOUBLE\",\n \"DOUBLE PRECISION\",\n \"FLOAT\",\n \"DECIMAL\",\n \"BOOLEAN\",\n \"DATE\",\n \"DATETIME\",\n \"TIMESTAMP\",\n ],\n \"x-affinity-mapping\": {\n INTEGER: [\n \"INTEGER\",\n \"INT\",\n \"TINYINT\",\n \"SMALLINT\",\n \"MEDIUMINT\",\n \"BIGINT\",\n \"UNSIGNED BIG INT\",\n \"INT2\",\n \"INT8\",\n ],\n TEXT: [\n \"TEXT\",\n \"CHARACTER\",\n \"VARCHAR\",\n \"VARYING CHARACTER\",\n \"NCHAR\",\n \"NATIVE CHARACTER\",\n \"NVARCHAR\",\n \"CLOB\",\n ],\n REAL: [\"REAL\", \"DOUBLE\", \"DOUBLE PRECISION\", \"FLOAT\"],\n NUMERIC: [\"NUMERIC\", \"DECIMAL\", \"BOOLEAN\", \"DATE\", \"DATETIME\", \"TIMESTAMP\"],\n BLOB: [\"BLOB\"],\n },\n },\n nullable: {\n type: \"boolean\",\n description: \"Whether the column allows NULL values (default: true)\",\n default: true,\n },\n primaryKey: {\n type: \"boolean\",\n description:\n \"Whether this column is the primary key (default: false). INTEGER PRIMARY KEY will auto-increment.\",\n default: false,\n },\n unique: {\n type: \"boolean\",\n description: \"Whether this column must have unique values (default: false)\",\n default: false,\n },\n defaultValue: {\n oneOf: [\n { type: \"string\" },\n { type: \"number\" },\n { type: \"boolean\" },\n { type: \"null\" },\n ],\n description:\n \"Default value for the column. Use string 'CURRENT_TIMESTAMP' for auto timestamp.\",\n },\n references: {\n type: \"object\",\n description: \"Foreign key reference\",\n properties: {\n table: {\n type: \"string\",\n description: \"Referenced table name\",\n },\n column: {\n type: \"string\",\n description: \"Referenced column name\",\n },\n onDelete: {\n type: \"string\",\n enum: [\"CASCADE\", \"SET NULL\", \"SET DEFAULT\", \"RESTRICT\", \"NO ACTION\"],\n description: \"Action on delete (default: NO ACTION)\",\n },\n onUpdate: {\n type: \"string\",\n enum: [\"CASCADE\", \"SET NULL\", \"SET DEFAULT\", \"RESTRICT\", \"NO ACTION\"],\n description: \"Action on update (default: NO ACTION)\",\n },\n },\n required: [\"table\", \"column\"],\n },\n },\n required: [\"name\", \"type\"],\n additionalProperties: false,\n },\n },\n ifNotExists: {\n type: \"boolean\",\n description: \"If true, do not throw error if table already exists (default: false)\",\n default: false,\n },\n },\n required: [\"name\", \"columns\"],\n additionalProperties: false,\n },\n handler: async (ctx: ActionContext, params): Promise<ActionResult> => {\n const tableName = params.name as string;\n const columns = params.columns as Array<{\n name: string;\n type: string;\n nullable?: boolean;\n primaryKey?: boolean;\n unique?: boolean;\n defaultValue?: string | number | boolean | null;\n references?: {\n table: string;\n column: string;\n onDelete?: string;\n onUpdate?: string;\n };\n }>;\n const ifNotExists = params.ifNotExists as boolean | undefined;\n\n // Validate required params\n if (!tableName) {\n throw new Error(\"Table name is required\");\n }\n if (!/^[a-zA-Z][a-zA-Z0-9_]*$/.test(tableName)) {\n throw new Error(\n \"Table name must start with a letter and contain only alphanumeric characters and underscores\",\n );\n }\n if (!columns || columns.length === 0) {\n throw new Error(\"At least one column is required\");\n }\n\n // Validate column names\n for (const col of columns) {\n if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(col.name)) {\n throw new Error(\n `Invalid column name: ${col.name}. Must start with a letter or underscore and contain only alphanumeric characters and underscores`,\n );\n }\n }\n\n // Validate column types\n const validTypes = [\n \"INTEGER\",\n \"TEXT\",\n \"REAL\",\n \"BLOB\",\n \"NUMERIC\",\n \"INT\",\n \"TINYINT\",\n \"SMALLINT\",\n \"MEDIUMINT\",\n \"BIGINT\",\n \"UNSIGNED BIG INT\",\n \"INT2\",\n \"INT8\",\n \"CHARACTER\",\n \"VARCHAR\",\n \"VARYING CHARACTER\",\n \"NCHAR\",\n \"NATIVE CHARACTER\",\n \"NVARCHAR\",\n \"CLOB\",\n \"DOUBLE\",\n \"DOUBLE PRECISION\",\n \"FLOAT\",\n \"DECIMAL\",\n \"BOOLEAN\",\n \"DATE\",\n \"DATETIME\",\n \"TIMESTAMP\",\n ];\n for (const col of columns) {\n const upperType = col.type.toUpperCase();\n if (!validTypes.includes(upperType)) {\n throw new Error(\n `Invalid column type: ${col.type}. Valid types are: ${validTypes.join(\", \")}`,\n );\n }\n }\n\n // Check if table already exists (unless ifNotExists is true)\n if (!ifNotExists) {\n const exists = await ctx.schemaService.hasTable(tableName);\n if (exists) {\n throw new Error(`Table '${tableName}' already exists`);\n }\n }\n\n // Build CREATE TABLE SQL\n const columnDefs: string[] = [];\n const foreignKeys: string[] = [];\n\n for (const col of columns) {\n const parts = [`\"${col.name}\"`, col.type.toUpperCase()];\n\n if (col.primaryKey) {\n parts.push(\"PRIMARY KEY\");\n // Only auto-increment for INTEGER primary keys\n if (col.type.toUpperCase() === \"INTEGER\" || col.type.toUpperCase() === \"INT\") {\n parts.push(\"AUTOINCREMENT\");\n }\n }\n\n if (col.nullable === false && !col.primaryKey) {\n parts.push(\"NOT NULL\");\n }\n\n if (col.unique && !col.primaryKey) {\n parts.push(\"UNIQUE\");\n }\n\n if (col.defaultValue !== undefined) {\n // Handle special default values\n if (\n col.defaultValue === \"CURRENT_TIMESTAMP\" ||\n col.defaultValue === \"CURRENT_DATE\" ||\n col.defaultValue === \"CURRENT_TIME\"\n ) {\n parts.push(`DEFAULT ${col.defaultValue}`);\n } else {\n parts.push(`DEFAULT ${formatValueForSQL(col.defaultValue)}`);\n }\n }\n\n columnDefs.push(parts.join(\" \"));\n\n // Handle foreign key references\n if (col.references) {\n let fkDef = `FOREIGN KEY (\"${col.name}\") REFERENCES \"${col.references.table}\"(\"${col.references.column}\")`;\n if (col.references.onDelete) {\n fkDef += ` ON DELETE ${col.references.onDelete}`;\n }\n if (col.references.onUpdate) {\n fkDef += ` ON UPDATE ${col.references.onUpdate}`;\n }\n foreignKeys.push(fkDef);\n }\n }\n\n // Combine column definitions and foreign keys\n const allDefs = [...columnDefs, ...foreignKeys];\n const ifNotExistsClause = ifNotExists ? \"IF NOT EXISTS \" : \"\";\n const createSQL = `CREATE TABLE ${ifNotExistsClause}\"${tableName}\" (${allDefs.join(\", \")})`;\n\n await execRun(ctx.db, createSQL);\n\n return {\n success: true,\n data: {\n tableName,\n columnCount: columns.length,\n sql: createSQL,\n },\n message: `Table '${tableName}' created successfully`,\n };\n },\n });\n\n // drop_table - Root level action to drop a table\n registry.register({\n name: \"drop_table\",\n description: \"Drop a table from the database\",\n rootLevel: true,\n tableLevel: false,\n rowLevel: false,\n inputSchema: {\n type: \"object\",\n properties: {\n name: { type: \"string\", description: \"Table name to drop\" },\n ifExists: {\n type: \"boolean\",\n default: false,\n description: \"Don't error if table doesn't exist\",\n },\n },\n required: [\"name\"],\n },\n handler: async (ctx: ActionContext, params): Promise<ActionResult> => {\n const tableName = params.name as string;\n const ifExists = params.ifExists as boolean | undefined;\n\n if (!tableName) {\n return errorResult(SQLiteActionErrorCode.INVALID_INPUT, \"Table name is required\");\n }\n\n // Check if table exists\n const exists = await ctx.schemaService.hasTable(tableName);\n if (!exists && !ifExists) {\n return errorResult(SQLiteActionErrorCode.NOT_FOUND, `Table '${tableName}' does not exist`);\n }\n\n if (exists) {\n const ifExistsClause = ifExists ? \"IF EXISTS \" : \"\";\n await execRun(ctx.db, `DROP TABLE ${ifExistsClause}\"${tableName}\"`);\n }\n\n return {\n success: true,\n data: { tableName },\n message: `Table '${tableName}' dropped successfully`,\n };\n },\n });\n\n // rename_table - Root level action to rename a table\n registry.register({\n name: \"rename_table\",\n description: \"Rename a table in the database\",\n rootLevel: true,\n tableLevel: false,\n rowLevel: false,\n inputSchema: {\n type: \"object\",\n properties: {\n oldName: { type: \"string\", description: \"Current table name\" },\n newName: { type: \"string\", description: \"New table name\" },\n },\n required: [\"oldName\", \"newName\"],\n },\n handler: async (ctx: ActionContext, params): Promise<ActionResult> => {\n const oldName = params.oldName as string;\n const newName = params.newName as string;\n\n if (!oldName || !newName) {\n return errorResult(\n SQLiteActionErrorCode.INVALID_INPUT,\n \"Both oldName and newName are required\",\n );\n }\n\n if (!/^[a-zA-Z][a-zA-Z0-9_]*$/.test(newName)) {\n return errorResult(\n SQLiteActionErrorCode.INVALID_INPUT,\n \"New table name must start with a letter and contain only alphanumeric characters and underscores\",\n );\n }\n\n // Check if source table exists\n const exists = await ctx.schemaService.hasTable(oldName);\n if (!exists) {\n return errorResult(SQLiteActionErrorCode.NOT_FOUND, `Table '${oldName}' does not exist`);\n }\n\n // Check if target name already exists\n const targetExists = await ctx.schemaService.hasTable(newName);\n if (targetExists) {\n return errorResult(\n SQLiteActionErrorCode.CONSTRAINT_VIOLATION,\n `Table '${newName}' already exists`,\n );\n }\n\n await execRun(ctx.db, `ALTER TABLE \"${oldName}\" RENAME TO \"${newName}\"`);\n\n return {\n success: true,\n data: { oldName, newName },\n message: `Table renamed from '${oldName}' to '${newName}'`,\n };\n },\n });\n\n // add_column - Table level action to add a column\n registry.register({\n name: \"add_column\",\n description: \"Add a new column to the table\",\n rootLevel: false,\n tableLevel: true,\n rowLevel: false,\n inputSchema: {\n type: \"object\",\n properties: {\n name: { type: \"string\", description: \"Column name\" },\n type: {\n type: \"string\",\n enum: [\"INTEGER\", \"TEXT\", \"REAL\", \"BLOB\", \"NUMERIC\"],\n description: \"Column type\",\n },\n nullable: {\n type: \"boolean\",\n default: true,\n description: \"Whether the column allows NULL values\",\n },\n defaultValue: {\n oneOf: [{ type: \"string\" }, { type: \"number\" }, { type: \"boolean\" }, { type: \"null\" }],\n description: \"Default value for the column\",\n },\n },\n required: [\"name\", \"type\"],\n },\n handler: async (ctx: ActionContext, params): Promise<ActionResult> => {\n const colName = params.name as string;\n const colType = params.type as string;\n const nullable = params.nullable !== false;\n const defaultValue = params.defaultValue;\n\n if (!colName || !colType) {\n return errorResult(\n SQLiteActionErrorCode.INVALID_INPUT,\n \"Column name and type are required\",\n );\n }\n\n // Build ALTER TABLE statement\n let columnDef = `\"${colName}\" ${colType.toUpperCase()}`;\n if (!nullable) {\n columnDef += \" NOT NULL\";\n }\n if (defaultValue !== undefined) {\n columnDef += ` DEFAULT ${formatValueForSQL(defaultValue)}`;\n }\n\n try {\n await execRun(ctx.db, `ALTER TABLE \"${ctx.table}\" ADD COLUMN ${columnDef}`);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n if (message.includes(\"duplicate column name\")) {\n return errorResult(\n SQLiteActionErrorCode.CONSTRAINT_VIOLATION,\n `Column '${colName}' already exists`,\n );\n }\n throw error;\n }\n\n return {\n success: true,\n data: { table: ctx.table, column: colName, type: colType },\n message: `Column '${colName}' added to table '${ctx.table}'`,\n };\n },\n });\n\n // rename_column - Table level action to rename a column\n registry.register({\n name: \"rename_column\",\n description: \"Rename a column in the table\",\n rootLevel: false,\n tableLevel: true,\n rowLevel: false,\n inputSchema: {\n type: \"object\",\n properties: {\n oldName: { type: \"string\", description: \"Current column name\" },\n newName: { type: \"string\", description: \"New column name\" },\n },\n required: [\"oldName\", \"newName\"],\n },\n handler: async (ctx: ActionContext, params): Promise<ActionResult> => {\n const oldName = params.oldName as string;\n const newName = params.newName as string;\n\n if (!oldName || !newName) {\n return errorResult(\n SQLiteActionErrorCode.INVALID_INPUT,\n \"Both oldName and newName are required\",\n );\n }\n\n // Verify column exists\n const schema = await ctx.schemaService.getSchema(ctx.table);\n if (!schema) {\n return errorResult(SQLiteActionErrorCode.NOT_FOUND, `Table '${ctx.table}' not found`);\n }\n\n const columnExists = schema.columns.some((c) => c.name === oldName);\n if (!columnExists) {\n return errorResult(\n SQLiteActionErrorCode.NOT_FOUND,\n `Column '${oldName}' not found in table '${ctx.table}'`,\n );\n }\n\n await execRun(\n ctx.db,\n `ALTER TABLE \"${ctx.table}\" RENAME COLUMN \"${oldName}\" TO \"${newName}\"`,\n );\n\n return {\n success: true,\n data: { table: ctx.table, oldName, newName },\n message: `Column renamed from '${oldName}' to '${newName}'`,\n };\n },\n });\n\n // drop_column - Table level action to drop a column\n registry.register({\n name: \"drop_column\",\n description: \"Drop a column from the table\",\n rootLevel: false,\n tableLevel: true,\n rowLevel: false,\n inputSchema: {\n type: \"object\",\n properties: {\n name: { type: \"string\", description: \"Column name to drop\" },\n },\n required: [\"name\"],\n },\n handler: async (ctx: ActionContext, params): Promise<ActionResult> => {\n const colName = params.name as string;\n\n if (!colName) {\n return errorResult(SQLiteActionErrorCode.INVALID_INPUT, \"Column name is required\");\n }\n\n // Verify column exists\n const schema = await ctx.schemaService.getSchema(ctx.table);\n if (!schema) {\n return errorResult(SQLiteActionErrorCode.NOT_FOUND, `Table '${ctx.table}' not found`);\n }\n\n const columnExists = schema.columns.some((c) => c.name === colName);\n if (!columnExists) {\n return errorResult(\n SQLiteActionErrorCode.NOT_FOUND,\n `Column '${colName}' not found in table '${ctx.table}'`,\n );\n }\n\n await execRun(ctx.db, `ALTER TABLE \"${ctx.table}\" DROP COLUMN \"${colName}\"`);\n\n return {\n success: true,\n data: { table: ctx.table, column: colName },\n message: `Column '${colName}' dropped from table '${ctx.table}'`,\n };\n },\n });\n\n // create_index - Table level action to create an index\n registry.register({\n name: \"create_index\",\n description: \"Create an index on the table\",\n rootLevel: false,\n tableLevel: true,\n rowLevel: false,\n inputSchema: {\n type: \"object\",\n properties: {\n name: { type: \"string\", description: \"Index name\" },\n columns: {\n type: \"array\",\n items: { type: \"string\" },\n minItems: 1,\n description: \"Columns to index (supports compound indexes)\",\n },\n unique: { type: \"boolean\", default: false, description: \"Whether the index is unique\" },\n ifNotExists: {\n type: \"boolean\",\n default: false,\n description: \"Don't error if index already exists\",\n },\n },\n required: [\"name\", \"columns\"],\n },\n handler: async (ctx: ActionContext, params): Promise<ActionResult> => {\n const indexName = params.name as string;\n const columns = params.columns as string[];\n const unique = params.unique as boolean | undefined;\n const ifNotExists = params.ifNotExists as boolean | undefined;\n\n if (!indexName || !columns || columns.length === 0) {\n return errorResult(\n SQLiteActionErrorCode.INVALID_INPUT,\n \"Index name and columns are required\",\n );\n }\n\n const uniqueClause = unique ? \"UNIQUE \" : \"\";\n const ifNotExistsClause = ifNotExists ? \"IF NOT EXISTS \" : \"\";\n const columnsClause = columns.map((c) => `\"${c}\"`).join(\", \");\n\n await execRun(\n ctx.db,\n `CREATE ${uniqueClause}INDEX ${ifNotExistsClause}\"${indexName}\" ON \"${ctx.table}\" (${columnsClause})`,\n );\n\n return {\n success: true,\n data: { indexName, table: ctx.table, columns, unique: !!unique },\n message: `Index '${indexName}' created on table '${ctx.table}'`,\n };\n },\n });\n\n // drop_index - Table level action to drop an index\n registry.register({\n name: \"drop_index\",\n description: \"Drop an index from the table\",\n rootLevel: false,\n tableLevel: true,\n rowLevel: false,\n inputSchema: {\n type: \"object\",\n properties: {\n name: { type: \"string\", description: \"Index name to drop\" },\n ifExists: {\n type: \"boolean\",\n default: false,\n description: \"Don't error if index doesn't exist\",\n },\n },\n required: [\"name\"],\n },\n handler: async (ctx: ActionContext, params): Promise<ActionResult> => {\n const indexName = params.name as string;\n const ifExists = params.ifExists as boolean | undefined;\n\n if (!indexName) {\n return errorResult(SQLiteActionErrorCode.INVALID_INPUT, \"Index name is required\");\n }\n\n const ifExistsClause = ifExists ? \"IF EXISTS \" : \"\";\n await execRun(ctx.db, `DROP INDEX ${ifExistsClause}\"${indexName}\"`);\n\n return {\n success: true,\n data: { indexName },\n message: `Index '${indexName}' dropped`,\n };\n },\n });\n\n // update - Row level action to update a single row by PK\n registry.register({\n name: \"update\",\n description: \"Update this row\",\n rootLevel: false,\n tableLevel: false,\n rowLevel: true,\n inputSchemaGenerator: (schemaCtx: SchemaGeneratorContext) => {\n if (!schemaCtx.tableSchema) {\n return {\n type: \"object\",\n properties: {\n data: { type: \"object\", description: \"Fields to update\", additionalProperties: true },\n },\n required: [\"data\"],\n };\n }\n return generateUpdateSchema(schemaCtx.tableSchema);\n },\n handler: async (ctx: ActionContext, params): Promise<ActionResult> => {\n const data = params.data as Record<string, unknown>;\n\n if (!data || Object.keys(data).length === 0) {\n return errorResult(SQLiteActionErrorCode.INVALID_INPUT, \"Update data is required\");\n }\n\n if (!ctx.pk) {\n return errorResult(\n SQLiteActionErrorCode.INVALID_INPUT,\n \"Primary key is required for row-level update\",\n );\n }\n\n const schema = await ctx.schemaService.getSchema(ctx.table);\n if (!schema) {\n return errorResult(SQLiteActionErrorCode.NOT_FOUND, `Table '${ctx.table}' not found`);\n }\n\n const pkColumn = schema.primaryKey[0] ?? \"rowid\";\n\n // Build SET clause\n const setClauses = Object.entries(data)\n .map(([col, val]) => `\"${col}\" = ${formatValueForSQL(val)}`)\n .join(\", \");\n\n const updateSQL = `UPDATE \"${ctx.table}\" SET ${setClauses} WHERE \"${pkColumn}\" = ${formatValueForSQL(ctx.pk)}`;\n\n try {\n await execRun(ctx.db, updateSQL);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n if (message.includes(\"UNIQUE constraint failed\")) {\n return errorResult(\n SQLiteActionErrorCode.CONSTRAINT_VIOLATION,\n `Unique constraint violation: ${message}`,\n );\n }\n throw error;\n }\n\n // Return updated row\n const rows = await execAll<Record<string, unknown>>(\n ctx.db,\n `SELECT * FROM \"${ctx.table}\" WHERE \"${pkColumn}\" = ${formatValueForSQL(ctx.pk)}`,\n );\n\n return {\n success: true,\n data: rows[0],\n message: \"Row updated successfully\",\n };\n },\n });\n\n // delete - Row level action to delete a single row by PK\n registry.register({\n name: \"delete\",\n description: \"Delete this row\",\n rootLevel: false,\n tableLevel: false,\n rowLevel: true,\n inputSchema: {\n type: \"object\",\n properties: {},\n description: \"Delete the current row\",\n },\n handler: async (ctx: ActionContext): Promise<ActionResult> => {\n if (!ctx.pk) {\n return errorResult(\n SQLiteActionErrorCode.INVALID_INPUT,\n \"Primary key is required for row-level delete\",\n );\n }\n\n const schema = await ctx.schemaService.getSchema(ctx.table);\n if (!schema) {\n return errorResult(SQLiteActionErrorCode.NOT_FOUND, `Table '${ctx.table}' not found`);\n }\n\n const pkColumn = schema.primaryKey[0] ?? \"rowid\";\n\n await execRun(\n ctx.db,\n `DELETE FROM \"${ctx.table}\" WHERE \"${pkColumn}\" = ${formatValueForSQL(ctx.pk)}`,\n );\n\n return {\n success: true,\n data: { pk: ctx.pk },\n message: \"Row deleted successfully\",\n };\n },\n });\n\n // query - Table level action to query rows with conditions\n registry.register({\n name: \"query\",\n description: \"Query rows with conditions, ordering, and pagination\",\n rootLevel: false,\n tableLevel: true,\n rowLevel: false,\n inputSchema: {\n type: \"object\",\n properties: {\n where: { type: \"object\", description: \"Query conditions (MongoDB-style operators)\" },\n orderBy: {\n type: \"array\",\n items: {\n type: \"object\",\n properties: {\n column: { type: \"string\" },\n direction: { type: \"string\", enum: [\"asc\", \"desc\"], default: \"asc\" },\n },\n required: [\"column\"],\n },\n description: \"Sort order\",\n },\n limit: { type: \"integer\", minimum: 1, description: \"Maximum rows to return\" },\n offset: { type: \"integer\", minimum: 0, description: \"Number of rows to skip\" },\n },\n },\n handler: async (ctx: ActionContext, params): Promise<ActionResult> => {\n const where = params.where as WhereClause | undefined;\n const orderBy = params.orderBy as Array<{ column: string; direction?: string }> | undefined;\n const limit = params.limit as number | undefined;\n const offset = params.offset as number | undefined;\n\n // Build query\n let querySQL = sql`SELECT * FROM ${sql.identifier(ctx.table)}`;\n querySQL = sql`${querySQL}${buildWhereClause(where)}`;\n\n // Add ORDER BY\n if (orderBy && orderBy.length > 0) {\n const orderClauses = orderBy.map((o) => {\n const dir = o.direction?.toUpperCase() === \"DESC\" ? sql` DESC` : sql` ASC`;\n return sql`${sql.identifier(o.column)}${dir}`;\n });\n querySQL = sql`${querySQL} ORDER BY ${sql.join(orderClauses, sql`, `)}`;\n }\n\n // Add LIMIT/OFFSET\n if (limit !== undefined) {\n querySQL = sql`${querySQL} LIMIT ${limit}`;\n }\n if (offset !== undefined) {\n querySQL = sql`${querySQL} OFFSET ${offset}`;\n }\n\n const rows = await execSql<Record<string, unknown>>(ctx.db, querySQL);\n\n return {\n success: true,\n data: { rows, count: rows.length },\n };\n },\n });\n\n // update_where - Table level action to update multiple rows\n registry.register({\n name: \"update_where\",\n description: \"Update rows matching conditions\",\n rootLevel: false,\n tableLevel: true,\n rowLevel: false,\n inputSchema: {\n type: \"object\",\n properties: {\n where: { type: \"object\", description: \"Update conditions (MongoDB-style operators)\" },\n data: { type: \"object\", description: \"Fields to update\" },\n },\n required: [\"where\", \"data\"],\n },\n handler: async (ctx: ActionContext, params): Promise<ActionResult> => {\n const where = params.where as WhereClause;\n const data = params.data as Record<string, unknown>;\n\n if (!where || Object.keys(where).length === 0) {\n return errorResult(\n SQLiteActionErrorCode.INVALID_INPUT,\n \"Where clause is required for update_where\",\n );\n }\n\n if (!data || Object.keys(data).length === 0) {\n return errorResult(SQLiteActionErrorCode.INVALID_INPUT, \"Update data is required\");\n }\n\n // Build SET clause with parameterized values\n const setEntries = Object.entries(data);\n const setClauses = setEntries.map(([col, val]) => sql`${sql.identifier(col)} = ${val}`);\n\n const updateSQL = sql`UPDATE ${sql.identifier(ctx.table)} SET ${sql.join(setClauses, sql`, `)}${buildWhereClause(where)}`;\n\n const result = await runSql(ctx.db, updateSQL);\n\n return {\n success: true,\n data: { affectedRows: result.changes },\n message: `${result.changes} row(s) updated`,\n };\n },\n });\n\n // delete_where - Table level action to delete multiple rows\n registry.register({\n name: \"delete_where\",\n description: \"Delete rows matching conditions\",\n rootLevel: false,\n tableLevel: true,\n rowLevel: false,\n inputSchema: {\n type: \"object\",\n properties: {\n where: { type: \"object\", description: \"Delete conditions (MongoDB-style operators)\" },\n },\n required: [\"where\"],\n },\n handler: async (ctx: ActionContext, params): Promise<ActionResult> => {\n const where = params.where as WhereClause;\n\n if (!where || Object.keys(where).length === 0) {\n return errorResult(\n SQLiteActionErrorCode.INVALID_INPUT,\n \"Where clause is required for delete_where\",\n );\n }\n\n const deleteSQL = sql`DELETE FROM ${sql.identifier(ctx.table)}${buildWhereClause(where)}`;\n\n const result = await runSql(ctx.db, deleteSQL);\n\n return {\n success: true,\n data: { affectedRows: result.changes },\n message: `${result.changes} row(s) deleted`,\n };\n },\n });\n\n // bulk_insert - Table level action to insert multiple rows\n registry.register({\n name: \"bulk_insert\",\n description: \"Insert multiple rows at once\",\n rootLevel: false,\n tableLevel: true,\n rowLevel: false,\n inputSchema: {\n type: \"object\",\n properties: {\n rows: {\n type: \"array\",\n items: { type: \"object\" },\n minItems: 1,\n description: \"Array of row data to insert\",\n },\n },\n required: [\"rows\"],\n },\n handler: async (ctx: ActionContext, params): Promise<ActionResult> => {\n const rows = params.rows as Array<Record<string, unknown>>;\n\n if (!rows || rows.length === 0) {\n return errorResult(SQLiteActionErrorCode.INVALID_INPUT, \"At least one row is required\");\n }\n\n // Get columns from first row\n const columns = Object.keys(rows[0]!);\n const columnsList = columns.map((c) => `\"${c}\"`).join(\", \");\n\n // Build values for each row\n const insertedIds: number[] = [];\n\n for (const row of rows) {\n const values = columns.map((col) => formatValueForSQL(row[col]));\n const insertSQL = `INSERT INTO \"${ctx.table}\" (${columnsList}) VALUES (${values.join(\", \")})`;\n\n try {\n await execRun(ctx.db, insertSQL);\n const lastIdResult = await execAll<{ id: number }>(\n ctx.db,\n \"SELECT last_insert_rowid() as id\",\n );\n insertedIds.push(lastIdResult[0]?.id ?? 0);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return errorResult(\n SQLiteActionErrorCode.CONSTRAINT_VIOLATION,\n `Insert failed at row ${insertedIds.length}: ${message}`,\n { insertedCount: insertedIds.length, insertedIds },\n );\n }\n }\n\n return {\n success: true,\n data: { insertedCount: rows.length, insertedIds },\n message: `${rows.length} row(s) inserted`,\n };\n },\n });\n\n // pragma - Root level action to execute PRAGMA commands\n registry.register({\n name: \"pragma\",\n description: \"Execute a PRAGMA command (whitelist-restricted)\",\n rootLevel: true,\n tableLevel: false,\n rowLevel: false,\n inputSchema: {\n type: \"object\",\n properties: {\n command: {\n type: \"string\",\n enum: [\n \"table_info\",\n \"table_list\",\n \"index_list\",\n \"index_info\",\n \"foreign_key_list\",\n \"database_list\",\n \"collation_list\",\n \"journal_mode\",\n \"synchronous\",\n \"cache_size\",\n \"page_size\",\n \"encoding\",\n \"auto_vacuum\",\n \"integrity_check\",\n \"quick_check\",\n ],\n description: \"PRAGMA command to execute\",\n },\n argument: { type: \"string\", description: \"Argument for the command (e.g., table name)\" },\n value: {\n oneOf: [{ type: \"string\" }, { type: \"number\" }],\n description: \"Value for writable PRAGMAs\",\n },\n },\n required: [\"command\"],\n },\n handler: async (ctx: ActionContext, params): Promise<ActionResult> => {\n const command = params.command as string;\n const argument = params.argument as string | undefined;\n const value = params.value as string | number | undefined;\n\n const allowedCommands = [\n \"table_info\",\n \"table_list\",\n \"index_list\",\n \"index_info\",\n \"foreign_key_list\",\n \"database_list\",\n \"collation_list\",\n \"journal_mode\",\n \"synchronous\",\n \"cache_size\",\n \"page_size\",\n \"encoding\",\n \"auto_vacuum\",\n \"integrity_check\",\n \"quick_check\",\n ];\n\n if (!allowedCommands.includes(command)) {\n return errorResult(\n SQLiteActionErrorCode.INVALID_INPUT,\n `PRAGMA command '${command}' is not allowed. Allowed: ${allowedCommands.join(\", \")}`,\n );\n }\n\n // Build PRAGMA query\n let pragmaSQL = `PRAGMA ${command}`;\n if (argument) {\n pragmaSQL += `(\"${argument}\")`;\n }\n if (value !== undefined) {\n pragmaSQL += ` = ${typeof value === \"string\" ? `'${value}'` : value}`;\n }\n\n const result = await execAll<Record<string, unknown>>(ctx.db, pragmaSQL);\n\n return {\n success: true,\n data:\n result.length === 1 && Object.keys(result[0]!).length === 1\n ? Object.values(result[0]!)[0]\n : result,\n };\n },\n });\n\n // Import data action (table level)\n registry.register({\n name: \"import\",\n description: \"Import data into table from JSON or CSV format\",\n tableLevel: true,\n rowLevel: false,\n inputSchema: {\n type: \"object\",\n properties: {\n format: {\n type: \"string\",\n enum: [\"json\", \"csv\"],\n description: \"Data format (json or csv)\",\n },\n data: {\n type: \"string\",\n description: \"The data to import (JSON array string or CSV string)\",\n },\n onConflict: {\n type: \"string\",\n enum: [\"abort\", \"ignore\", \"replace\"],\n default: \"abort\",\n description: \"Conflict resolution strategy\",\n },\n delimiter: {\n type: \"string\",\n default: \",\",\n description: \"CSV delimiter character\",\n },\n header: {\n type: \"boolean\",\n default: true,\n description: \"Whether CSV has a header row\",\n },\n },\n required: [\"format\", \"data\"],\n },\n handler: async (ctx: ActionContext, params): Promise<ActionResult> => {\n const format = params.format as string;\n const data = params.data as string;\n const onConflict = (params.onConflict as string) ?? \"abort\";\n const delimiter = (params.delimiter as string) ?? \",\";\n const hasHeader = params.header !== false;\n\n if (![\"json\", \"csv\"].includes(format)) {\n return errorResult(\n SQLiteActionErrorCode.INVALID_INPUT,\n `Unsupported import format: ${format}. Supported: json, csv`,\n );\n }\n\n // Verify table exists\n const schema = await ctx.schemaService.getSchema(ctx.table);\n if (!schema) {\n return errorResult(SQLiteActionErrorCode.NOT_FOUND, `Table not found: ${ctx.table}`);\n }\n\n // Parse data\n let rows: Record<string, unknown>[];\n try {\n if (format === \"json\") {\n const parsed = JSON.parse(data);\n if (!Array.isArray(parsed)) {\n return errorResult(\n SQLiteActionErrorCode.INVALID_INPUT,\n \"JSON data must be an array of objects\",\n );\n }\n rows = parsed;\n } else {\n // Parse CSV\n rows = parseCSV(data, delimiter, hasHeader, schema);\n }\n } catch (error) {\n return errorResult(\n SQLiteActionErrorCode.INVALID_INPUT,\n `Failed to parse ${format} data: ${error instanceof Error ? error.message : \"unknown error\"}`,\n );\n }\n\n if (rows.length === 0) {\n return { success: true, data: { imported: 0, skipped: 0 } };\n }\n\n // Build conflict clause\n let conflictClause = \"\";\n if (onConflict === \"ignore\") {\n conflictClause = \" OR IGNORE\";\n } else if (onConflict === \"replace\") {\n conflictClause = \" OR REPLACE\";\n }\n // abort is the default SQLite behavior (no clause needed)\n\n // Get column names from schema\n const columnNames = schema.columns.map((c) => c.name);\n\n // Execute import in a transaction\n let imported = 0;\n let skipped = 0;\n\n try {\n await execRun(ctx.db, \"BEGIN TRANSACTION\");\n\n for (const row of rows) {\n // Only use columns that exist in the schema\n const usedColumns: string[] = [];\n const values: string[] = [];\n\n for (const colName of columnNames) {\n if (colName in row) {\n usedColumns.push(colName);\n values.push(formatValueForSQL(row[colName]));\n }\n }\n\n if (usedColumns.length === 0) continue;\n\n const insertSQL = `INSERT${conflictClause} INTO \"${ctx.table}\" (${usedColumns.map((c) => `\"${c}\"`).join(\", \")}) VALUES (${values.join(\", \")})`;\n\n try {\n await execAll<Record<string, unknown>>(ctx.db, insertSQL);\n // For IGNORE, check if the row was actually inserted\n const changesResult = await execAll<{ changes: number }>(\n ctx.db,\n \"SELECT changes() as changes\",\n );\n const changes = changesResult[0]?.changes ?? 0;\n if (changes > 0) {\n imported++;\n } else {\n skipped++;\n }\n } catch (error) {\n if (onConflict === \"abort\") {\n // Rollback and re-throw\n await execRun(ctx.db, \"ROLLBACK\");\n return errorResult(\n SQLiteActionErrorCode.CONSTRAINT_VIOLATION,\n `Import aborted: ${error instanceof Error ? error.message : \"constraint violation\"}`,\n );\n }\n skipped++;\n }\n }\n\n await execRun(ctx.db, \"COMMIT\");\n\n return { success: true, data: { imported, skipped } };\n } catch (error) {\n try {\n await execRun(ctx.db, \"ROLLBACK\");\n } catch {\n // Ignore rollback errors\n }\n return errorResult(\n SQLiteActionErrorCode.INVALID_INPUT,\n `Import failed: ${error instanceof Error ? error.message : \"unknown error\"}`,\n );\n }\n },\n });\n\n // Vacuum action (root level)\n registry.register({\n name: \"vacuum\",\n description: \"Compact the database file and reclaim unused space\",\n rootLevel: true,\n tableLevel: false,\n rowLevel: false,\n inputSchema: {\n type: \"object\",\n properties: {},\n additionalProperties: false,\n },\n handler: async (ctx: ActionContext): Promise<ActionResult> => {\n // Get size before vacuum\n const pageCountBefore = await execAll<{ page_count: number }>(ctx.db, \"PRAGMA page_count\");\n const pageSizeResult = await execAll<{ page_size: number }>(ctx.db, \"PRAGMA page_size\");\n const pageSize = pageSizeResult[0]?.page_size ?? 4096;\n const sizeBefore = (pageCountBefore[0]?.page_count ?? 0) * pageSize;\n\n try {\n await execRun(ctx.db, \"VACUUM\");\n } catch (error) {\n return errorResult(\n SQLiteActionErrorCode.INVALID_INPUT,\n `Vacuum failed: ${error instanceof Error ? error.message : \"unknown error\"}`,\n );\n }\n\n // Get size after vacuum\n const pageCountAfter = await execAll<{ page_count: number }>(ctx.db, \"PRAGMA page_count\");\n const sizeAfter = (pageCountAfter[0]?.page_count ?? 0) * pageSize;\n\n return {\n success: true,\n data: { sizeBefore, sizeAfter, freedBytes: sizeBefore - sizeAfter },\n };\n },\n });\n}\n\n/**\n * Formats a value for SQL insertion\n */\nfunction formatValueForSQL(value: unknown): string {\n if (value === null || value === undefined) {\n return \"NULL\";\n }\n if (typeof value === \"number\") {\n return String(value);\n }\n if (typeof value === \"boolean\") {\n return value ? \"1\" : \"0\";\n }\n if (value instanceof Date) {\n return `'${value.toISOString()}'`;\n }\n if (typeof value === \"object\") {\n return `'${JSON.stringify(value).replace(/'/g, \"''\")}'`;\n }\n return `'${String(value).replace(/'/g, \"''\")}'`;\n}\n\n/**\n * Parse a CSV string into an array of row objects.\n */\nfunction parseCSV(\n data: string,\n delimiter: string,\n hasHeader: boolean,\n schema: TableSchema,\n): Record<string, unknown>[] {\n const lines = data.split(\"\\n\").filter((line) => line.trim() !== \"\");\n if (lines.length === 0) return [];\n\n let headers: string[];\n let startIndex: number;\n\n if (hasHeader) {\n if (lines.length < 1) return [];\n headers = parseCsvLine(lines[0]!, delimiter);\n startIndex = 1;\n } else {\n // Use column names from schema\n headers = schema.columns.map((c) => c.name);\n startIndex = 0;\n }\n\n const rows: Record<string, unknown>[] = [];\n for (let i = startIndex; i < lines.length; i++) {\n const values = parseCsvLine(lines[i]!, delimiter);\n const row: Record<string, unknown> = {};\n for (let j = 0; j < headers.length && j < values.length; j++) {\n row[headers[j]!] = values[j];\n }\n rows.push(row);\n }\n\n return rows;\n}\n\n/**\n * Parse a single CSV line, handling quoted fields.\n */\nfunction parseCsvLine(line: string, delimiter: string): string[] {\n const fields: string[] = [];\n let current = \"\";\n let inQuotes = false;\n let i = 0;\n\n while (i < line.length) {\n const char = line[i]!;\n\n if (inQuotes) {\n if (char === '\"') {\n if (i + 1 < line.length && line[i + 1] === '\"') {\n current += '\"';\n i += 2;\n } else {\n inQuotes = false;\n i++;\n }\n } else {\n current += char;\n i++;\n }\n } else {\n if (char === '\"') {\n inQuotes = true;\n i++;\n } else if (line.substring(i, i + delimiter.length) === delimiter) {\n fields.push(current);\n current = \"\";\n i += delimiter.length;\n } else {\n current += char;\n i++;\n }\n }\n }\n\n fields.push(current);\n return fields;\n}\n\n/**\n * Maps SQLite column type to JSON Schema type\n */\nfunction sqliteTypeToJsonSchema(sqliteType: string): {\n type: string;\n format?: string;\n description?: string;\n} {\n const upperType = sqliteType.toUpperCase();\n\n if (upperType.includes(\"INT\")) {\n return { type: \"integer\" };\n }\n if (upperType.includes(\"REAL\") || upperType.includes(\"FLOAT\") || upperType.includes(\"DOUBLE\")) {\n return { type: \"number\" };\n }\n if (upperType.includes(\"BOOL\")) {\n return { type: \"boolean\", description: \"Stored as INTEGER (0/1)\" };\n }\n if (upperType.includes(\"DATE\") || upperType.includes(\"TIME\")) {\n return { type: \"string\", format: \"date-time\" };\n }\n if (upperType.includes(\"BLOB\")) {\n return { type: \"string\", format: \"binary\", description: \"Base64 encoded binary data\" };\n }\n // TEXT and everything else\n return { type: \"string\" };\n}\n\n/**\n * Generates JSON Schema for insert action based on table schema\n */\nfunction generateInsertSchema(tableSchema: TableSchema): Record<string, unknown> {\n const properties: Record<string, unknown> = {};\n const required: string[] = [];\n\n for (const col of tableSchema.columns) {\n // Skip auto-increment primary keys (they're auto-generated)\n const isPrimaryKeyAutoIncrement = col.pk > 0 && col.type.toUpperCase().includes(\"INTEGER\");\n if (isPrimaryKeyAutoIncrement) {\n continue;\n }\n\n const typeInfo = sqliteTypeToJsonSchema(col.type);\n const propSchema: Record<string, unknown> = {\n ...typeInfo,\n };\n\n // Add default value info if present\n if (col.dfltValue !== null) {\n propSchema.default = col.dfltValue;\n propSchema.description =\n `${propSchema.description ?? \"\"}${propSchema.description ? \". \" : \"\"}Default: ${col.dfltValue}`.trim();\n }\n\n // Track required fields (NOT NULL without default)\n if (col.notnull && col.dfltValue === null && col.pk === 0) {\n required.push(col.name);\n }\n\n properties[col.name] = propSchema;\n }\n\n return {\n type: \"object\",\n description: `Insert a new row into \"${tableSchema.name}\" table`,\n properties: {\n data: {\n type: \"object\",\n description: \"Row data to insert\",\n properties,\n required: required.length > 0 ? required : undefined,\n additionalProperties: false,\n },\n },\n required: [\"data\"],\n };\n}\n\n/**\n * Generates JSON Schema for validate action based on table schema\n */\nfunction generateValidateSchema(tableSchema: TableSchema): Record<string, unknown> {\n const columnInfo = tableSchema.columns.map((col) => ({\n name: col.name,\n type: col.type,\n nullable: !col.notnull,\n primaryKey: col.pk > 0,\n }));\n\n const foreignKeyInfo = tableSchema.foreignKeys.map((fk) => ({\n column: fk.from,\n references: `${fk.table}.${fk.to}`,\n }));\n\n return {\n type: \"object\",\n description: `Validate row data against \"${tableSchema.name}\" table constraints`,\n properties: {},\n additionalProperties: false,\n // Include schema info in metadata for documentation\n \"x-table-schema\": {\n columns: columnInfo,\n foreignKeys: foreignKeyInfo,\n },\n };\n}\n\n/**\n * Generates JSON Schema for duplicate action based on table schema\n */\nfunction generateDuplicateSchema(tableSchema: TableSchema): Record<string, unknown> {\n const pkColumn = tableSchema.primaryKey[0] ?? \"rowid\";\n const copiedColumns = tableSchema.columns\n .filter((col) => col.name !== pkColumn)\n .map((col) => col.name);\n\n return {\n type: \"object\",\n description: `Create a copy of the row (excluding primary key \"${pkColumn}\")`,\n properties: {},\n additionalProperties: false,\n \"x-copied-columns\": copiedColumns,\n };\n}\n\n/**\n * Generates JSON Schema for update action based on table schema\n */\nfunction generateUpdateSchema(tableSchema: TableSchema): Record<string, unknown> {\n const properties: Record<string, unknown> = {};\n const pkColumn = tableSchema.primaryKey[0] ?? \"rowid\";\n\n for (const col of tableSchema.columns) {\n // Skip primary key (can't update)\n if (col.name === pkColumn) {\n continue;\n }\n\n const typeInfo = sqliteTypeToJsonSchema(col.type);\n properties[col.name] = typeInfo;\n }\n\n return {\n type: \"object\",\n description: `Update fields in \"${tableSchema.name}\" table`,\n properties: {\n data: {\n type: \"object\",\n description: \"Fields to update\",\n properties,\n additionalProperties: false,\n },\n },\n required: [\"data\"],\n };\n}\n"],"mappings":"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CN,aAAa;GACb,YAAY;IACV,MAAM;KACJ,MAAM;KACN,aAAa;KACb,SAAS;KACT,WAAW;KACX,WAAW;KACZ;IACD,SAAS;KACP,MAAM;KACN,aAAa;KACb,UAAU;KACV,OAAO;MACL,MAAM;MACN,aAAa;MACb,YAAY;OACV,MAAM;QACJ,MAAM;QACN,aAAa;QACb,SAAS;QACT,WAAW;QACX,WAAW;QACZ;OACD,MAAM;QACJ,MAAM;QACN,aAAa;QACb,MAAM;SAEJ;SACA;SACA;SACA;SACA;SAEA;SACA;SACA;SACA;SACA;SACA;SACA;SACA;SACA;SACA;SACA;SACA;SACA;SACA;SACA;SACA;SACA;SACA;SACA;SACA;SACA;SACA;SACA;SACD;QACD,sBAAsB;SACpB,SAAS;UACP;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACD;SACD,MAAM;UACJ;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACD;SACD,MAAM;UAAC;UAAQ;UAAU;UAAoB;UAAQ;SACrD,SAAS;UAAC;UAAW;UAAW;UAAW;UAAQ;UAAY;UAAY;SAC3E,MAAM,CAAC,OAAO;SACf;QACF;OACD,UAAU;QACR,MAAM;QACN,aAAa;QACb,SAAS;QACV;OACD,YAAY;QACV,MAAM;QACN,aACE;QACF,SAAS;QACV;OACD,QAAQ;QACN,MAAM;QACN,aAAa;QACb,SAAS;QACV;OACD,cAAc;QACZ,OAAO;SACL,EAAE,MAAM,UAAU;SAClB,EAAE,MAAM,UAAU;SAClB,EAAE,MAAM,WAAW;SACnB,EAAE,MAAM,QAAQ;SACjB;QACD,aACE;QACH;OACD,YAAY;QACV,MAAM;QACN,aAAa;QACb,YAAY;SACV,OAAO;UACL,MAAM;UACN,aAAa;UACd;SACD,QAAQ;UACN,MAAM;UACN,aAAa;UACd;SACD,UAAU;UACR,MAAM;UACN,MAAM;WAAC;WAAW;WAAY;WAAe;WAAY;WAAY;UACrE,aAAa;UACd;SACD,UAAU;UACR,MAAM;UACN,MAAM;WAAC;WAAW;WAAY;WAAe;WAAY;WAAY;UACrE,aAAa;UACd;SACF;QACD,UAAU,CAAC,SAAS,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"}
@@ -0,0 +1,156 @@
1
+ let _aigne_sqlite = require("@aigne/sqlite");
2
+
3
+ //#region src/actions/operators.ts
4
+ const COMPARISON_OPERATORS = [
5
+ "$eq",
6
+ "$ne",
7
+ "$gt",
8
+ "$gte",
9
+ "$lt",
10
+ "$lte",
11
+ "$in",
12
+ "$notIn",
13
+ "$like",
14
+ "$isNull",
15
+ "$between"
16
+ ];
17
+ /**
18
+ * Check if value is an operator object (has $ prefixed keys)
19
+ */
20
+ function isOperatorObject(value) {
21
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
22
+ const keys = Object.keys(value);
23
+ return keys.length > 0 && keys.every((k) => COMPARISON_OPERATORS.includes(k));
24
+ }
25
+ /**
26
+ * Check if key is a logical operator
27
+ */
28
+ function isLogicalOperator(key) {
29
+ return key === "$and" || key === "$or" || key === "$not";
30
+ }
31
+ /**
32
+ * Validate operator name
33
+ */
34
+ function validateOperator(op) {
35
+ if (op.startsWith("$") && !COMPARISON_OPERATORS.includes(op) && !isLogicalOperator(op)) throw new Error(`Invalid operator: ${op}`);
36
+ }
37
+ /**
38
+ * Parse a column condition with operators
39
+ */
40
+ function parseColumnCondition(column, condition) {
41
+ const parts = [];
42
+ const col = _aigne_sqlite.sql.identifier(column);
43
+ for (const [op, value] of Object.entries(condition)) {
44
+ validateOperator(op);
45
+ switch (op) {
46
+ case "$eq":
47
+ parts.push(_aigne_sqlite.sql`${col} = ${value}`);
48
+ break;
49
+ case "$ne":
50
+ parts.push(_aigne_sqlite.sql`${col} <> ${value}`);
51
+ break;
52
+ case "$gt":
53
+ parts.push(_aigne_sqlite.sql`${col} > ${value}`);
54
+ break;
55
+ case "$gte":
56
+ parts.push(_aigne_sqlite.sql`${col} >= ${value}`);
57
+ break;
58
+ case "$lt":
59
+ parts.push(_aigne_sqlite.sql`${col} < ${value}`);
60
+ break;
61
+ case "$lte":
62
+ parts.push(_aigne_sqlite.sql`${col} <= ${value}`);
63
+ break;
64
+ case "$in": {
65
+ const arr = value;
66
+ if (!Array.isArray(arr) || arr.length === 0) throw new Error("$in requires a non-empty array");
67
+ const placeholders = arr.map((v) => _aigne_sqlite.sql`${v}`);
68
+ parts.push(_aigne_sqlite.sql`${col} IN (${_aigne_sqlite.sql.join(placeholders, _aigne_sqlite.sql`, `)})`);
69
+ break;
70
+ }
71
+ case "$notIn": {
72
+ const arr = value;
73
+ if (!Array.isArray(arr) || arr.length === 0) throw new Error("$notIn requires a non-empty array");
74
+ const placeholders = arr.map((v) => _aigne_sqlite.sql`${v}`);
75
+ parts.push(_aigne_sqlite.sql`${col} NOT IN (${_aigne_sqlite.sql.join(placeholders, _aigne_sqlite.sql`, `)})`);
76
+ break;
77
+ }
78
+ case "$like":
79
+ parts.push(_aigne_sqlite.sql`${col} LIKE ${value}`);
80
+ break;
81
+ case "$isNull":
82
+ if (value === true) parts.push(_aigne_sqlite.sql`${col} IS NULL`);
83
+ else parts.push(_aigne_sqlite.sql`${col} IS NOT NULL`);
84
+ break;
85
+ case "$between": {
86
+ const [min, max] = value;
87
+ parts.push(_aigne_sqlite.sql`${col} BETWEEN ${min} AND ${max}`);
88
+ break;
89
+ }
90
+ }
91
+ }
92
+ if (parts.length === 0) return _aigne_sqlite.sql`1 = 1`;
93
+ return parts.length === 1 ? parts[0] : _aigne_sqlite.sql`(${_aigne_sqlite.sql.join(parts, _aigne_sqlite.sql` AND `)})`;
94
+ }
95
+ /**
96
+ * Parse $and clause
97
+ */
98
+ function parseAndClause(clauses) {
99
+ if (!Array.isArray(clauses) || clauses.length === 0) return _aigne_sqlite.sql`1 = 1`;
100
+ const parts = clauses.map((c) => parseWhereClause(c));
101
+ return _aigne_sqlite.sql`(${_aigne_sqlite.sql.join(parts, _aigne_sqlite.sql` AND `)})`;
102
+ }
103
+ /**
104
+ * Parse $or clause
105
+ */
106
+ function parseOrClause(clauses) {
107
+ if (!Array.isArray(clauses) || clauses.length === 0) return _aigne_sqlite.sql`1 = 1`;
108
+ const parts = clauses.map((c) => parseWhereClause(c));
109
+ return _aigne_sqlite.sql`(${_aigne_sqlite.sql.join(parts, _aigne_sqlite.sql` OR `)})`;
110
+ }
111
+ /**
112
+ * Parse $not clause
113
+ */
114
+ function parseNotClause(clause) {
115
+ return _aigne_sqlite.sql`NOT (${parseWhereClause(clause)})`;
116
+ }
117
+ /**
118
+ * Parse a complete WHERE clause object into parameterized SQL
119
+ *
120
+ * @param where - The where clause object with MongoDB-style operators
121
+ * @returns Parameterized SQL fragment
122
+ *
123
+ * @example
124
+ * // Simple equality
125
+ * parseWhereClause({ status: "active" })
126
+ *
127
+ * // With operators
128
+ * parseWhereClause({ age: { $gte: 18, $lt: 65 } })
129
+ *
130
+ * // Logical combination
131
+ * parseWhereClause({ $or: [{ status: "active" }, { role: "admin" }] })
132
+ */
133
+ function parseWhereClause(where) {
134
+ if (!where || typeof where !== "object") return _aigne_sqlite.sql`1 = 1`;
135
+ const conditions = [];
136
+ for (const [key, value] of Object.entries(where)) if (key === "$and") conditions.push(parseAndClause(value));
137
+ else if (key === "$or") conditions.push(parseOrClause(value));
138
+ else if (key === "$not") conditions.push(parseNotClause(value));
139
+ else if (isOperatorObject(value)) conditions.push(parseColumnCondition(key, value));
140
+ else {
141
+ const col = _aigne_sqlite.sql.identifier(key);
142
+ conditions.push(_aigne_sqlite.sql`${col} = ${value}`);
143
+ }
144
+ if (conditions.length === 0) return _aigne_sqlite.sql`1 = 1`;
145
+ return conditions.length === 1 ? conditions[0] : _aigne_sqlite.sql.join(conditions, _aigne_sqlite.sql` AND `);
146
+ }
147
+ /**
148
+ * Build a complete WHERE clause (including the WHERE keyword)
149
+ */
150
+ function buildWhereClause(where) {
151
+ if (!where || Object.keys(where).length === 0) return _aigne_sqlite.sql``;
152
+ return _aigne_sqlite.sql` WHERE ${parseWhereClause(where)}`;
153
+ }
154
+
155
+ //#endregion
156
+ exports.buildWhereClause = buildWhereClause;
@@ -0,0 +1,157 @@
1
+ import { sql } from "@aigne/sqlite";
2
+
3
+ //#region src/actions/operators.ts
4
+ const COMPARISON_OPERATORS = [
5
+ "$eq",
6
+ "$ne",
7
+ "$gt",
8
+ "$gte",
9
+ "$lt",
10
+ "$lte",
11
+ "$in",
12
+ "$notIn",
13
+ "$like",
14
+ "$isNull",
15
+ "$between"
16
+ ];
17
+ /**
18
+ * Check if value is an operator object (has $ prefixed keys)
19
+ */
20
+ function isOperatorObject(value) {
21
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
22
+ const keys = Object.keys(value);
23
+ return keys.length > 0 && keys.every((k) => COMPARISON_OPERATORS.includes(k));
24
+ }
25
+ /**
26
+ * Check if key is a logical operator
27
+ */
28
+ function isLogicalOperator(key) {
29
+ return key === "$and" || key === "$or" || key === "$not";
30
+ }
31
+ /**
32
+ * Validate operator name
33
+ */
34
+ function validateOperator(op) {
35
+ if (op.startsWith("$") && !COMPARISON_OPERATORS.includes(op) && !isLogicalOperator(op)) throw new Error(`Invalid operator: ${op}`);
36
+ }
37
+ /**
38
+ * Parse a column condition with operators
39
+ */
40
+ function parseColumnCondition(column, condition) {
41
+ const parts = [];
42
+ const col = sql.identifier(column);
43
+ for (const [op, value] of Object.entries(condition)) {
44
+ validateOperator(op);
45
+ switch (op) {
46
+ case "$eq":
47
+ parts.push(sql`${col} = ${value}`);
48
+ break;
49
+ case "$ne":
50
+ parts.push(sql`${col} <> ${value}`);
51
+ break;
52
+ case "$gt":
53
+ parts.push(sql`${col} > ${value}`);
54
+ break;
55
+ case "$gte":
56
+ parts.push(sql`${col} >= ${value}`);
57
+ break;
58
+ case "$lt":
59
+ parts.push(sql`${col} < ${value}`);
60
+ break;
61
+ case "$lte":
62
+ parts.push(sql`${col} <= ${value}`);
63
+ break;
64
+ case "$in": {
65
+ const arr = value;
66
+ if (!Array.isArray(arr) || arr.length === 0) throw new Error("$in requires a non-empty array");
67
+ const placeholders = arr.map((v) => sql`${v}`);
68
+ parts.push(sql`${col} IN (${sql.join(placeholders, sql`, `)})`);
69
+ break;
70
+ }
71
+ case "$notIn": {
72
+ const arr = value;
73
+ if (!Array.isArray(arr) || arr.length === 0) throw new Error("$notIn requires a non-empty array");
74
+ const placeholders = arr.map((v) => sql`${v}`);
75
+ parts.push(sql`${col} NOT IN (${sql.join(placeholders, sql`, `)})`);
76
+ break;
77
+ }
78
+ case "$like":
79
+ parts.push(sql`${col} LIKE ${value}`);
80
+ break;
81
+ case "$isNull":
82
+ if (value === true) parts.push(sql`${col} IS NULL`);
83
+ else parts.push(sql`${col} IS NOT NULL`);
84
+ break;
85
+ case "$between": {
86
+ const [min, max] = value;
87
+ parts.push(sql`${col} BETWEEN ${min} AND ${max}`);
88
+ break;
89
+ }
90
+ }
91
+ }
92
+ if (parts.length === 0) return sql`1 = 1`;
93
+ return parts.length === 1 ? parts[0] : sql`(${sql.join(parts, sql` AND `)})`;
94
+ }
95
+ /**
96
+ * Parse $and clause
97
+ */
98
+ function parseAndClause(clauses) {
99
+ if (!Array.isArray(clauses) || clauses.length === 0) return sql`1 = 1`;
100
+ const parts = clauses.map((c) => parseWhereClause(c));
101
+ return sql`(${sql.join(parts, sql` AND `)})`;
102
+ }
103
+ /**
104
+ * Parse $or clause
105
+ */
106
+ function parseOrClause(clauses) {
107
+ if (!Array.isArray(clauses) || clauses.length === 0) return sql`1 = 1`;
108
+ const parts = clauses.map((c) => parseWhereClause(c));
109
+ return sql`(${sql.join(parts, sql` OR `)})`;
110
+ }
111
+ /**
112
+ * Parse $not clause
113
+ */
114
+ function parseNotClause(clause) {
115
+ return sql`NOT (${parseWhereClause(clause)})`;
116
+ }
117
+ /**
118
+ * Parse a complete WHERE clause object into parameterized SQL
119
+ *
120
+ * @param where - The where clause object with MongoDB-style operators
121
+ * @returns Parameterized SQL fragment
122
+ *
123
+ * @example
124
+ * // Simple equality
125
+ * parseWhereClause({ status: "active" })
126
+ *
127
+ * // With operators
128
+ * parseWhereClause({ age: { $gte: 18, $lt: 65 } })
129
+ *
130
+ * // Logical combination
131
+ * parseWhereClause({ $or: [{ status: "active" }, { role: "admin" }] })
132
+ */
133
+ function parseWhereClause(where) {
134
+ if (!where || typeof where !== "object") return sql`1 = 1`;
135
+ const conditions = [];
136
+ for (const [key, value] of Object.entries(where)) if (key === "$and") conditions.push(parseAndClause(value));
137
+ else if (key === "$or") conditions.push(parseOrClause(value));
138
+ else if (key === "$not") conditions.push(parseNotClause(value));
139
+ else if (isOperatorObject(value)) conditions.push(parseColumnCondition(key, value));
140
+ else {
141
+ const col = sql.identifier(key);
142
+ conditions.push(sql`${col} = ${value}`);
143
+ }
144
+ if (conditions.length === 0) return sql`1 = 1`;
145
+ return conditions.length === 1 ? conditions[0] : sql.join(conditions, sql` AND `);
146
+ }
147
+ /**
148
+ * Build a complete WHERE clause (including the WHERE keyword)
149
+ */
150
+ function buildWhereClause(where) {
151
+ if (!where || Object.keys(where).length === 0) return sql``;
152
+ return sql` WHERE ${parseWhereClause(where)}`;
153
+ }
154
+
155
+ //#endregion
156
+ export { buildWhereClause };
157
+ //# sourceMappingURL=operators.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"operators.mjs","names":[],"sources":["../../src/actions/operators.ts"],"sourcesContent":["/**\n * MongoDB-style condition operators parser for SQLite queries\n *\n * Converts operator objects like { age: { $gte: 18, $lt: 65 } }\n * to parameterized SQL WHERE clauses.\n */\n\nimport type { SQL } from \"@aigne/sqlite\";\nimport { sql } from \"@aigne/sqlite\";\n\n// Type definitions\n\ntype PrimitiveValue = string | number | boolean | null;\n\ninterface ColumnCondition {\n $eq?: PrimitiveValue;\n $ne?: PrimitiveValue;\n $gt?: number | string;\n $gte?: number | string;\n $lt?: number | string;\n $lte?: number | string;\n $in?: PrimitiveValue[];\n $notIn?: PrimitiveValue[];\n $like?: string;\n $isNull?: boolean;\n $between?: [number | string, number | string];\n}\n\nexport type WhereClause = {\n [key: string]: ColumnCondition | PrimitiveValue | WhereClause[] | WhereClause | undefined;\n} & {\n $and?: WhereClause[];\n $or?: WhereClause[];\n $not?: WhereClause;\n};\n\nconst COMPARISON_OPERATORS = [\n \"$eq\",\n \"$ne\",\n \"$gt\",\n \"$gte\",\n \"$lt\",\n \"$lte\",\n \"$in\",\n \"$notIn\",\n \"$like\",\n \"$isNull\",\n \"$between\",\n];\n\n/**\n * Check if value is an operator object (has $ prefixed keys)\n */\nfunction isOperatorObject(value: unknown): value is ColumnCondition {\n if (value === null || typeof value !== \"object\" || Array.isArray(value)) {\n return false;\n }\n const keys = Object.keys(value);\n return keys.length > 0 && keys.every((k) => COMPARISON_OPERATORS.includes(k));\n}\n\n/**\n * Check if key is a logical operator\n */\nfunction isLogicalOperator(key: string): boolean {\n return key === \"$and\" || key === \"$or\" || key === \"$not\";\n}\n\n/**\n * Validate operator name\n */\nfunction validateOperator(op: string): void {\n if (op.startsWith(\"$\") && !COMPARISON_OPERATORS.includes(op) && !isLogicalOperator(op)) {\n throw new Error(`Invalid operator: ${op}`);\n }\n}\n\n/**\n * Parse a column condition with operators\n */\nfunction parseColumnCondition(column: string, condition: ColumnCondition): SQL {\n const parts: SQL[] = [];\n const col = sql.identifier(column);\n\n for (const [op, value] of Object.entries(condition)) {\n validateOperator(op);\n\n switch (op) {\n case \"$eq\":\n parts.push(sql`${col} = ${value}`);\n break;\n case \"$ne\":\n parts.push(sql`${col} <> ${value}`);\n break;\n case \"$gt\":\n parts.push(sql`${col} > ${value}`);\n break;\n case \"$gte\":\n parts.push(sql`${col} >= ${value}`);\n break;\n case \"$lt\":\n parts.push(sql`${col} < ${value}`);\n break;\n case \"$lte\":\n parts.push(sql`${col} <= ${value}`);\n break;\n case \"$in\": {\n const arr = value as PrimitiveValue[];\n if (!Array.isArray(arr) || arr.length === 0) {\n throw new Error(\"$in requires a non-empty array\");\n }\n const placeholders = arr.map((v) => sql`${v}`);\n parts.push(sql`${col} IN (${sql.join(placeholders, sql`, `)})`);\n break;\n }\n case \"$notIn\": {\n const arr = value as PrimitiveValue[];\n if (!Array.isArray(arr) || arr.length === 0) {\n throw new Error(\"$notIn requires a non-empty array\");\n }\n const placeholders = arr.map((v) => sql`${v}`);\n parts.push(sql`${col} NOT IN (${sql.join(placeholders, sql`, `)})`);\n break;\n }\n case \"$like\":\n parts.push(sql`${col} LIKE ${value}`);\n break;\n case \"$isNull\":\n if (value === true) {\n parts.push(sql`${col} IS NULL`);\n } else {\n parts.push(sql`${col} IS NOT NULL`);\n }\n break;\n case \"$between\": {\n const [min, max] = value as [number | string, number | string];\n parts.push(sql`${col} BETWEEN ${min} AND ${max}`);\n break;\n }\n }\n }\n\n if (parts.length === 0) {\n return sql`1 = 1`;\n }\n\n return parts.length === 1 ? parts[0]! : sql`(${sql.join(parts, sql` AND `)})`;\n}\n\n/**\n * Parse $and clause\n */\nfunction parseAndClause(clauses: WhereClause[]): SQL {\n if (!Array.isArray(clauses) || clauses.length === 0) {\n return sql`1 = 1`;\n }\n const parts = clauses.map((c) => parseWhereClause(c));\n return sql`(${sql.join(parts, sql` AND `)})`;\n}\n\n/**\n * Parse $or clause\n */\nfunction parseOrClause(clauses: WhereClause[]): SQL {\n if (!Array.isArray(clauses) || clauses.length === 0) {\n return sql`1 = 1`;\n }\n const parts = clauses.map((c) => parseWhereClause(c));\n return sql`(${sql.join(parts, sql` OR `)})`;\n}\n\n/**\n * Parse $not clause\n */\nfunction parseNotClause(clause: WhereClause): SQL {\n const inner = parseWhereClause(clause);\n return sql`NOT (${inner})`;\n}\n\n/**\n * Parse a complete WHERE clause object into parameterized SQL\n *\n * @param where - The where clause object with MongoDB-style operators\n * @returns Parameterized SQL fragment\n *\n * @example\n * // Simple equality\n * parseWhereClause({ status: \"active\" })\n *\n * // With operators\n * parseWhereClause({ age: { $gte: 18, $lt: 65 } })\n *\n * // Logical combination\n * parseWhereClause({ $or: [{ status: \"active\" }, { role: \"admin\" }] })\n */\nexport function parseWhereClause(where: WhereClause): SQL {\n if (!where || typeof where !== \"object\") {\n return sql`1 = 1`;\n }\n\n const conditions: SQL[] = [];\n\n for (const [key, value] of Object.entries(where)) {\n if (key === \"$and\") {\n conditions.push(parseAndClause(value as WhereClause[]));\n } else if (key === \"$or\") {\n conditions.push(parseOrClause(value as WhereClause[]));\n } else if (key === \"$not\") {\n conditions.push(parseNotClause(value as WhereClause));\n } else if (isOperatorObject(value)) {\n conditions.push(parseColumnCondition(key, value as ColumnCondition));\n } else {\n // Simple equality (implicit $eq)\n const col = sql.identifier(key);\n conditions.push(sql`${col} = ${value as PrimitiveValue}`);\n }\n }\n\n if (conditions.length === 0) {\n return sql`1 = 1`;\n }\n\n return conditions.length === 1 ? conditions[0]! : sql.join(conditions, sql` AND `);\n}\n\n/**\n * Build a complete WHERE clause (including the WHERE keyword)\n */\nexport function buildWhereClause(where: WhereClause | undefined): SQL {\n if (!where || Object.keys(where).length === 0) {\n return sql``;\n }\n return sql` WHERE ${parseWhereClause(where)}`;\n}\n"],"mappings":"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"}