@toiroakr/lines-db 0.9.2 → 0.10.1
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.
- package/CHANGELOG.md +20 -0
- package/bin/cli.mjs +7172 -125
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +3 -3
- package/dist/index.mjs.map +1 -1
- package/package.json +17 -27
- package/src/cli.ts +112 -111
- package/tsdown.config.ts +9 -5
- package/dist/index.cjs +0 -1463
- package/dist/index.d.cts +0 -604
- package/dist/index.d.cts.map +0 -1
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["schema"],"sources":["../src/runtime.ts","../src/sqlite-adapter.ts","../src/jsonl-reader.ts","../src/jsonl-writer.ts","../src/schema-extensions.ts","../src/schema-loader.ts","../src/directory-scanner.ts","../src/schema.ts","../src/database.ts","../src/type-generator.ts","../src/jsonl-migration.ts","../src/error-formatter.ts"],"sourcesContent":["/**\n * Runtime detection utilities\n */\n\nexport type RuntimeEnvironment = 'node' | 'unknown';\n\nexport function detectRuntime(): RuntimeEnvironment {\n // Check for Node.js\n if (typeof process !== 'undefined' && process.versions && process.versions.node) {\n return 'node';\n }\n\n return 'unknown';\n}\n\nexport const RUNTIME = detectRuntime();\n","/**\n * SQLite adapter for Node.js\n */\n\nimport { RUNTIME } from './runtime.js';\n\n/**\n * Common interface for SQLite database\n */\nexport interface SQLiteDatabase {\n prepare(sql: string): SQLiteStatement;\n exec(sql: string): void;\n close(): void;\n}\n\nexport interface SQLiteStatement {\n run(...params: any[]): { changes: number; lastInsertRowid: number | bigint };\n get(...params: any[]): any;\n all(...params: any[]): any[];\n}\n\n/**\n * Create a SQLite database instance for Node.js\n */\nexport function createDatabase(path: string = ':memory:'): SQLiteDatabase {\n if (RUNTIME === 'node') {\n return createNodeDatabase(path);\n } else {\n throw new Error(`Unsupported runtime: ${RUNTIME}`);\n }\n}\n\n/**\n * Create a Node.js SQLite database\n */\nfunction createNodeDatabase(path: string): SQLiteDatabase {\n // Dynamic import for Node.js\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const { DatabaseSync } = require('node:sqlite');\n const db = new DatabaseSync(path);\n\n // CRITICAL: Enable foreign key constraints\n // SQLite disables foreign keys by default, which is a major data integrity issue\n db.exec('PRAGMA foreign_keys = ON');\n\n return {\n prepare(sql: string): SQLiteStatement {\n const stmt = db.prepare(sql);\n return {\n run(...params: any[]) {\n return stmt.run(...params);\n },\n get(...params: any[]) {\n return stmt.get(...params);\n },\n all(...params: any[]) {\n return stmt.all(...params);\n },\n };\n },\n exec(sql: string): void {\n db.exec(sql);\n },\n close(): void {\n db.close();\n },\n };\n}\n","import { readFile } from 'node:fs/promises';\nimport { normalize } from 'node:path';\nimport type { JsonObject, ColumnDefinition, TableSchema } from './types.js';\n\nexport class JsonlReader {\n private static overrides: Map<string, JsonObject[]> | null = null;\n\n /**\n * Temporarily override the data returned for specific JSONL files.\n * Useful for scenarios like migration validation where in-memory data should be used.\n */\n static async withOverrides<T>(overrides: Map<string, JsonObject[]>, fn: () => Promise<T>): Promise<T> {\n const normalized = new Map<string, JsonObject[]>();\n for (const [filePath, rows] of overrides) {\n normalized.set(normalize(filePath), rows);\n }\n\n const previousOverrides = this.overrides;\n this.overrides = normalized;\n\n try {\n return await fn();\n } finally {\n this.overrides = previousOverrides;\n }\n }\n\n /**\n * Read JSONL file and parse each line as JSON\n */\n static async read(filePath: string): Promise<JsonObject[]> {\n const overrideRows = this.overrides?.get(normalize(filePath));\n if (overrideRows) {\n // Return clones to avoid accidental mutations from consumers\n return overrideRows.map((row) => JSON.parse(JSON.stringify(row)) as JsonObject);\n }\n\n const content = await readFile(filePath, 'utf-8');\n const lines = content.trim().split('\\n');\n\n return lines\n .filter((line) => line.trim().length > 0)\n .map((line) => {\n try {\n return JSON.parse(line) as JsonObject;\n } catch (error) {\n throw new Error(`Failed to parse JSON line: ${line}`, { cause: error });\n }\n });\n }\n\n /**\n * Infer schema from JSONL data\n */\n static inferSchema(tableName: string, data: JsonObject[]): TableSchema {\n if (data.length === 0) {\n throw new Error('Cannot infer schema from empty data');\n }\n\n const columnTypes = new Map<string, Set<string>>();\n const booleanColumns = new Set<string>();\n const nonBooleanColumns = new Set<string>();\n\n // Collect all column names and their types\n for (const row of data) {\n for (const [key, value] of Object.entries(row)) {\n if (!columnTypes.has(key)) {\n columnTypes.set(key, new Set());\n }\n columnTypes.get(key)!.add(this.inferType(value));\n\n if (typeof value === 'boolean') {\n booleanColumns.add(key);\n } else if (value !== null) {\n nonBooleanColumns.add(key);\n }\n }\n }\n\n // Convert to column definitions\n const columns: ColumnDefinition[] = [];\n for (const [columnName, types] of columnTypes.entries()) {\n const typeArray = Array.from(types);\n\n // If multiple types exist, prefer TEXT as a safe fallback\n let sqlType: ColumnDefinition['type'] = 'TEXT';\n\n if (typeArray.length === 1) {\n sqlType = typeArray[0] as ColumnDefinition['type'];\n } else if (typeArray.every((t) => t === 'INTEGER' || t === 'REAL')) {\n sqlType = 'REAL'; // Use REAL if we have mixed numeric types\n } else if (!typeArray.includes('NULL')) {\n // If there are multiple non-null types, use TEXT\n sqlType = 'TEXT';\n } else if (typeArray.length === 2 && typeArray.includes('NULL')) {\n // If one type + NULL, use the non-null type\n sqlType = typeArray.find((t) => t !== 'NULL') as ColumnDefinition['type'];\n }\n\n const isBooleanColumn = booleanColumns.has(columnName) && !nonBooleanColumns.has(columnName);\n\n columns.push({\n name: columnName,\n type: sqlType,\n notNull: !typeArray.includes('NULL'),\n valueType: isBooleanColumn ? 'boolean' : undefined,\n });\n }\n\n // If there's an 'id' column, make it primary key\n const idColumn = columns.find((col) => col.name === 'id');\n if (idColumn) {\n idColumn.primaryKey = true;\n }\n\n return {\n name: tableName,\n columns,\n };\n }\n\n private static inferType(value: unknown): string {\n if (value === null || value === undefined) return 'NULL';\n if (typeof value === 'number') {\n return Number.isInteger(value) ? 'INTEGER' : 'REAL';\n }\n if (typeof value === 'string') return 'TEXT';\n if (typeof value === 'boolean') return 'INTEGER'; // SQLite stores booleans as integers\n if (typeof value === 'object') return 'JSON'; // Store objects/arrays as JSON\n return 'TEXT';\n }\n}\n","import { writeFile } from 'node:fs/promises';\nimport type { JsonObject } from './types.js';\n\nexport class JsonlWriter {\n /**\n * Write data to JSONL file\n */\n static async write(filePath: string, data: JsonObject[]): Promise<void> {\n const lines = data.map((obj) => JSON.stringify(obj)).join('\\n');\n await writeFile(filePath, lines + '\\n', 'utf-8');\n }\n\n /**\n * Append data to JSONL file\n */\n static async append(filePath: string, data: JsonObject[]): Promise<void> {\n const { readFile, writeFile } = await import('node:fs/promises');\n\n try {\n const existing = await readFile(filePath, 'utf-8');\n const lines = data.map((obj) => JSON.stringify(obj)).join('\\n');\n const newContent = existing.trim() + '\\n' + lines + '\\n';\n await writeFile(filePath, newContent, 'utf-8');\n } catch (error) {\n // If file doesn't exist, just write the data\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n await this.write(filePath, data);\n } else {\n throw error;\n }\n }\n }\n}\n","import { access } from 'node:fs/promises';\nimport { join } from 'node:path';\n\n/**\n * Supported schema file extensions, in priority order.\n * The first match wins when discovering schema files.\n */\nexport const SCHEMA_EXTENSIONS = ['.schema.ts', '.schema.mts', '.schema.cts'] as const;\nexport type SchemaExtension = (typeof SCHEMA_EXTENSIONS)[number];\n\n/**\n * Map from schema extensions to their JavaScript import counterparts.\n */\nconst SCHEMA_TO_JS_IMPORT_MAP: Record<string, string> = {\n '.schema.ts': '.schema.js',\n '.schema.mts': '.schema.mjs',\n '.schema.cts': '.schema.cjs',\n};\n\n/**\n * Try each supported schema extension and return the full path of the first\n * one that exists on disk. Returns undefined if none is found.\n */\nexport async function findSchemaFile(dir: string, tableName: string): Promise<string | undefined> {\n for (const ext of SCHEMA_EXTENSIONS) {\n const candidate = join(dir, `${tableName}${ext}`);\n try {\n await access(candidate);\n return candidate;\n } catch {\n // Continue to next extension\n }\n }\n return undefined;\n}\n\n/**\n * Synchronously find a schema file among directory entries.\n * Returns the full path of the first match, or undefined.\n */\nexport function findSchemaFileInEntries(\n dataDirPath: string,\n tableName: string,\n entries: { isFile(): boolean; name: string }[],\n): string | undefined {\n for (const ext of SCHEMA_EXTENSIONS) {\n const candidateName = `${tableName}${ext}`;\n if (entries.some((e) => e.isFile() && e.name === candidateName)) {\n return join(dataDirPath, candidateName);\n }\n }\n return undefined;\n}\n\n/**\n * Check if a filename matches any supported schema file pattern.\n */\nexport function isSchemaFile(fileName: string): boolean {\n return SCHEMA_EXTENSIONS.some((ext) => fileName.endsWith(ext));\n}\n\n/**\n * Extract table name from a schema filename.\n * e.g., \"users.schema.ts\" -> \"users\", \"users.schema.mts\" -> \"users\"\n */\nexport function extractTableNameFromSchemaFile(fileName: string): string | null {\n for (const ext of SCHEMA_EXTENSIONS) {\n if (fileName.endsWith(ext)) {\n return fileName.slice(0, -ext.length);\n }\n }\n return null;\n}\n\n/**\n * Rewrite a TypeScript path to its JavaScript counterpart for ESM imports.\n * \".schema.ts\" -> \".schema.js\", \".schema.mts\" -> \".schema.mjs\", \".schema.cts\" -> \".schema.cjs\"\n */\nexport function rewriteExtensionForImport(filePath: string): string {\n for (const [tsExt, jsExt] of Object.entries(SCHEMA_TO_JS_IMPORT_MAP)) {\n if (filePath.endsWith(tsExt)) {\n return filePath.slice(0, -tsExt.length) + jsExt;\n }\n }\n return filePath;\n}\n","import { pathToFileURL } from 'node:url';\nimport { dirname, basename } from 'node:path';\nimport type { StandardSchema } from './types.js';\nimport { findSchemaFile, SCHEMA_EXTENSIONS } from './schema-extensions.js';\n\nexport class SchemaLoader {\n /**\n * Check if a schema file exists for a table\n */\n static async hasSchema(jsonlPath: string): Promise<boolean> {\n const dir = dirname(jsonlPath);\n const tableName = basename(jsonlPath, '.jsonl');\n const schemaPath = await findSchemaFile(dir, tableName);\n return schemaPath !== undefined;\n }\n\n /**\n * Load a validation schema file for a table\n * Requires ${tableName}.schema.{ts,mts,cts} to exist alongside the JSONL file\n */\n static async loadSchema(jsonlPath: string): Promise<StandardSchema> {\n const dir = dirname(jsonlPath);\n const tableName = basename(jsonlPath, '.jsonl');\n const schemaPath = await findSchemaFile(dir, tableName);\n\n if (!schemaPath) {\n throw new Error(\n `Schema file not found for table '${tableName}'. Expected one of: ${SCHEMA_EXTENSIONS.map((ext) => `${tableName}${ext}`).join(', ')}`,\n );\n }\n\n try {\n const schemaUrl = pathToFileURL(schemaPath).href;\n // Add cache busting query parameter to force reload on each import\n // This ensures schema changes are picked up immediately\n const cacheBustedUrl = `${schemaUrl}?t=${Date.now()}`;\n const module = await import(cacheBustedUrl);\n const schema = module.default || module.schema;\n\n if (schema && this.isStandardSchema(schema)) {\n return schema;\n }\n\n throw new Error(`Schema file ${schemaPath} does not export a valid StandardSchema`);\n } catch (error) {\n throw new Error(\n `Failed to load schema for table '${tableName}' from ${schemaPath}: ${error instanceof Error ? error.message : String(error)}`,\n { cause: error instanceof Error ? error : undefined },\n );\n }\n }\n\n /**\n * Check if an object implements the StandardSchema interface\n */\n private static isStandardSchema(obj: unknown): obj is StandardSchema {\n if (!obj || typeof obj !== 'object') return false;\n\n const schema = obj as Record<string, unknown>;\n const standard = schema['~standard'];\n\n if (!standard || typeof standard !== 'object') return false;\n\n const standardObj = standard as Record<string, unknown>;\n\n return (\n standardObj.version === 1 && typeof standardObj.vendor === 'string' && typeof standardObj.validate === 'function'\n );\n }\n}\n","import { readdir } from 'node:fs/promises';\nimport { join, basename, extname } from 'node:path';\nimport type { TableConfig } from './types.js';\n\nexport class DirectoryScanner {\n /**\n * Scan directory for JSONL files and create table configurations\n */\n static async scanDirectory(dataDir: string): Promise<Map<string, TableConfig>> {\n const tables = new Map<string, TableConfig>();\n\n try {\n const files = await readdir(dataDir);\n\n for (const file of files) {\n if (extname(file) === '.jsonl') {\n const tableName = basename(file, '.jsonl');\n const jsonlPath = join(dataDir, file);\n\n tables.set(tableName, {\n jsonlPath,\n autoInferSchema: true,\n });\n }\n }\n\n if (tables.size === 0) {\n console.warn(`Warning: No JSONL files found in directory: ${dataDir}`);\n }\n\n return tables;\n } catch (error) {\n throw new Error(`Failed to scan directory ${dataDir}: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n}\n","import type { StandardSchema, Table, ForeignKeyDefinition, IndexDefinition } from './types.js';\n\n/**\n * Schema options for defining constraints and indexes\n * When Input and Output types differ, backward transformation is required\n */\nexport type SchemaOptions<Input extends Table, Output extends Table> = {\n /**\n * Primary key column\n */\n primaryKey?: string;\n\n /**\n * Foreign key constraints\n */\n foreignKeys?: ForeignKeyDefinition[];\n\n /**\n * Indexes to create\n */\n indexes?: IndexDefinition[];\n} & (Output extends Input\n ? {\n /**\n * Backward transformation from Output to Input (optional when output is substitutable for input)\n */\n backward?: (output: Output) => Input;\n }\n : {\n /**\n * Backward transformation from Output to Input (REQUIRED when types differ)\n */\n backward: (output: Output) => Input;\n });\n\n/**\n * BiDirectional Schema interface\n * Extends StandardSchema with optional backward transformation and schema metadata\n */\nexport interface BiDirectionalSchema<Input extends Table = Table, Output extends Table = Input> extends StandardSchema<\n Input,\n Output\n> {\n /**\n * Backward transformation from Output to Input\n * Required when Input and Output types differ (e.g., with transformations)\n */\n backward?: (output: Output) => Input;\n\n /**\n * Primary key column\n */\n primaryKey?: string;\n\n /**\n * Foreign key constraints\n */\n foreignKeys?: ForeignKeyDefinition[];\n\n /**\n * Indexes to create\n */\n indexes?: IndexDefinition[];\n}\n\n/**\n * Define a bidirectional schema with optional backward transformation\n *\n * @param schema - Standard Schema for validation\n * @param options - SchemaOptions object. When Input and Output types differ, backward transformation is required\n *\n * @example\n * // No transformation - backward not needed\n * const schema = defineSchema(\n * v.object({ id: v.number(), name: v.string() })\n * );\n *\n * @example\n * // With transformation - backward REQUIRED\n * const schema = defineSchema(\n * v.pipe(v.string(), v.transform(Number)),\n * {\n * backward: (num) => String(num) // backward: number → string (REQUIRED)\n * }\n * );\n *\n * @example\n * // With primary key and foreign key\n * const schema = defineSchema(\n * v.object({ id: v.number(), customerId: v.number() }),\n * {\n * primaryKey: 'id',\n * foreignKeys: [\n * { column: 'customerId', references: { table: 'users', column: 'id' } }\n * ]\n * }\n * );\n */\nexport function defineSchema<Input extends Table, Output extends Table>(\n schema: StandardSchema<Input, Output>,\n ...args: Output extends Input ? [options?: SchemaOptions<Input, Output>] : [options: SchemaOptions<Input, Output>]\n): BiDirectionalSchema<Input, Output> {\n const options = args[0];\n // Create a new object that extends the schema\n const bidirectionalSchema = Object.create(schema) as BiDirectionalSchema<Input, Output>;\n\n // Handle options object\n if (options) {\n if (options.backward) {\n bidirectionalSchema.backward = options.backward as (output: Output) => Input;\n }\n if (options.primaryKey) {\n bidirectionalSchema.primaryKey = options.primaryKey;\n }\n if (options.foreignKeys) {\n bidirectionalSchema.foreignKeys = options.foreignKeys;\n }\n if (options.indexes) {\n bidirectionalSchema.indexes = options.indexes;\n }\n }\n\n // Copy '~standard' property\n Object.defineProperty(bidirectionalSchema, '~standard', {\n value: schema['~standard'],\n enumerable: true,\n configurable: true,\n });\n\n return bidirectionalSchema;\n}\n\n/**\n * Check if a schema has backward transformation\n */\nexport function hasBackward<Input extends Table, Output extends Table>(\n schema: StandardSchema<Input, Output>,\n): schema is BiDirectionalSchema<Input, Output> {\n return 'backward' in schema && typeof (schema as { backward?: unknown }).backward === 'function';\n}\n","import { createDatabase, type SQLiteDatabase } from './sqlite-adapter.js';\nimport { JsonlReader } from './jsonl-reader.js';\nimport { JsonlWriter } from './jsonl-writer.js';\nimport { SchemaLoader } from './schema-loader.js';\nimport { DirectoryScanner } from './directory-scanner.js';\nimport { hasBackward } from './schema.js';\nimport { findSchemaFile } from './schema-extensions.js';\nimport { dirname, basename } from 'node:path';\nimport type {\n DatabaseConfig,\n TableSchema,\n JsonObject,\n TableConfig,\n StandardSchema,\n ValidationError,\n Table,\n TableDefs,\n WhereCondition,\n ValidationResult,\n ValidationErrorDetail,\n TableValidationResult,\n ForeignKeyDefinition,\n} from './types.js';\nimport type { BiDirectionalSchema } from './schema.js';\n\nexport class LinesDB<Tables extends TableDefs> {\n private db: SQLiteDatabase;\n private config: DatabaseConfig<Tables>;\n private schemas: Map<string, TableSchema> = new Map();\n private validationSchemas: Map<string, StandardSchema | undefined> = new Map();\n private tables: Map<string, TableConfig> = new Map();\n private inTransaction: boolean = false;\n\n private constructor(config: DatabaseConfig<Tables>, dbPath?: string) {\n this.config = config;\n this.db = createDatabase(dbPath ?? ':memory:');\n }\n\n static create<Tables extends TableDefs>(config: DatabaseConfig<Tables>, dbPath?: string): LinesDB<Tables> {\n return new LinesDB<Tables>(config, dbPath);\n }\n\n /**\n * Initialize database by loading all JSONL files or a specific table\n * Uses dependency resolution to ensure foreign key references are loaded in correct order\n * @param options Optional configuration for initialization\n * @param options.tableName Optional table name to initialize. If not provided, initializes all tables\n * @param options.detailedValidate If true, performs detailed validation by inserting rows one by one to catch constraint violations\n * @param options.transform Optional transform function to apply to rows before validation (only applied to the specified tableName)\n * @returns ValidationResult containing validation status, errors, and warnings\n */\n async initialize(options?: {\n tableName?: string;\n detailedValidate?: boolean;\n transform?: (row: JsonObject) => JsonObject;\n }): Promise<ValidationResult> {\n const allErrors: ValidationErrorDetail[] = [];\n const allWarnings: string[] = [];\n const allRowCounts = new Map<string, number>();\n const tableName = options?.tableName;\n const detailedValidate = options?.detailedValidate ?? false;\n const transform = options?.transform;\n\n // Scan directory for JSONL files\n this.tables = await DirectoryScanner.scanDirectory(this.config.dataDir);\n\n // Determine which tables to load\n const tablesToLoad = tableName ? [tableName] : Array.from(this.tables.keys());\n\n // Validate that all requested tables exist BEFORE starting to load\n for (const tableNameToLoad of tablesToLoad) {\n if (!this.tables.has(tableNameToLoad)) {\n throw new Error(`Table '${tableNameToLoad}' not found in directory '${this.config.dataDir}'`);\n }\n }\n\n // Track loaded tables and tables currently being loaded (for circular dependency detection)\n const loadedTables = new Set<string>();\n const loadingTables = new Set<string>();\n const attemptedTables = new Set<string>(); // Track all attempted tables (loaded or not)\n const allDeferredForeignKeys: Array<{\n tableName: string;\n foreignKey: ForeignKeyDefinition;\n filePath: string;\n }> = [];\n\n // Load tables with dependency resolution\n for (const tableNameToLoad of tablesToLoad) {\n if (!attemptedTables.has(tableNameToLoad)) {\n // Only apply transform to the specified table\n const tableTransform = tableNameToLoad === tableName ? transform : undefined;\n const {\n errors,\n warnings,\n rowCounts: tableRowCounts,\n deferredForeignKeys,\n } = await this.loadTableWithDependencies(\n tableNameToLoad,\n loadedTables,\n loadingTables,\n attemptedTables,\n detailedValidate,\n tableTransform,\n );\n allErrors.push(...errors);\n allWarnings.push(...warnings);\n allDeferredForeignKeys.push(...deferredForeignKeys);\n for (const [k, v] of tableRowCounts) {\n allRowCounts.set(k, v);\n }\n }\n }\n\n // Validate deferred foreign keys (from circular dependencies) now that all tables are loaded\n if (detailedValidate && allDeferredForeignKeys.length > 0) {\n for (const { tableName: tName, foreignKey: fk, filePath } of allDeferredForeignKeys) {\n // Only validate if the referenced table was actually loaded\n if (!loadedTables.has(fk.references.table)) {\n continue;\n }\n const deferredErrors = this.validateDeferredForeignKey(tName, fk, filePath);\n allErrors.push(...deferredErrors);\n }\n }\n\n // Build per-table results\n const tableResults: TableValidationResult[] = tablesToLoad.map((name) => {\n const tableErrors = allErrors.filter((e) => e.tableName === name);\n const tableWarnings = allWarnings.filter((w) => w.includes(`'${name}'`));\n return {\n tableName: name,\n valid: tableErrors.length === 0,\n rowCount: allRowCounts.get(name) ?? 0,\n errors: tableErrors,\n warnings: tableWarnings,\n };\n });\n\n return {\n valid: allErrors.length === 0,\n errors: allErrors,\n warnings: allWarnings,\n tableResults,\n };\n }\n\n /**\n * Load a table and its dependencies recursively\n */\n private async loadTableWithDependencies(\n tableName: string,\n loadedTables: Set<string>,\n loadingTables: Set<string>,\n attemptedTables: Set<string>,\n detailedValidate: boolean,\n transform?: (row: JsonObject) => JsonObject,\n ): Promise<{\n errors: ValidationErrorDetail[];\n warnings: string[];\n rowCounts: Map<string, number>;\n deferredForeignKeys: Array<{\n tableName: string;\n foreignKey: ForeignKeyDefinition;\n filePath: string;\n }>;\n }> {\n const errors: ValidationErrorDetail[] = [];\n const warnings: string[] = [];\n const rowCounts = new Map<string, number>();\n const deferredForeignKeys: Array<{\n tableName: string;\n foreignKey: ForeignKeyDefinition;\n filePath: string;\n }> = [];\n\n // Skip if already attempted (loaded or not)\n if (attemptedTables.has(tableName)) {\n return { errors, warnings, rowCounts, deferredForeignKeys };\n }\n\n // Mark as attempted\n attemptedTables.add(tableName);\n\n // Check for circular dependencies\n if (loadingTables.has(tableName)) {\n throw new Error(`Circular dependency detected for table '${tableName}'`);\n }\n\n // Get table config\n const tableConfig = this.tables.get(tableName);\n if (!tableConfig) {\n throw new Error(`Table configuration not found for '${tableName}'`);\n }\n\n // Mark as currently loading\n loadingTables.add(tableName);\n\n try {\n // Load schema module to check for foreign key dependencies\n // We need to load the entire module to access foreignKeys export\n let foreignKeys: BiDirectionalSchema['foreignKeys'];\n\n try {\n const { pathToFileURL } = await import('node:url');\n const schemaPath = await findSchemaFile(\n dirname(tableConfig.jsonlPath),\n basename(tableConfig.jsonlPath, '.jsonl'),\n );\n if (schemaPath) {\n const schemaUrl = pathToFileURL(schemaPath).href;\n const schemaModule = await import(`${schemaUrl}?t=${Date.now()}`);\n\n // Try to get foreign keys from exported 'schema' or directly from module\n const schemaExport = schemaModule.schema || schemaModule.default;\n foreignKeys = schemaExport?.foreignKeys || schemaModule.foreignKeys;\n }\n } catch {\n // Schema file not found - will continue without validation\n }\n\n // If there are foreign key dependencies, load them first\n if (foreignKeys && foreignKeys.length > 0) {\n for (const fk of foreignKeys) {\n const referencedTable = fk.references.table;\n\n // Skip self-referencing foreign keys (e.g., nullable parent_id columns)\n if (referencedTable === tableName) {\n continue;\n }\n\n if (!attemptedTables.has(referencedTable)) {\n // Check if referenced table exists in our tables map\n if (this.tables.has(referencedTable)) {\n // Dependencies should not have transform applied\n const depResult = await this.loadTableWithDependencies(\n referencedTable,\n loadedTables,\n loadingTables,\n attemptedTables,\n detailedValidate,\n undefined,\n );\n errors.push(...depResult.errors);\n warnings.push(...depResult.warnings);\n deferredForeignKeys.push(...depResult.deferredForeignKeys);\n for (const [k, v] of depResult.rowCounts) {\n rowCounts.set(k, v);\n }\n } else {\n throw new Error(\n `Foreign key reference to non-existent table '${referencedTable}' in table '${tableName}'`,\n );\n }\n }\n }\n }\n\n // Determine which FK dependencies failed or are circular (attempted but not loaded)\n const failedDependencies = new Set<string>();\n const circularDependencies = new Set<string>();\n if (foreignKeys && foreignKeys.length > 0) {\n for (const fk of foreignKeys) {\n const referencedTable = fk.references.table;\n if (referencedTable === tableName) continue;\n if (attemptedTables.has(referencedTable) && !loadedTables.has(referencedTable)) {\n if (loadingTables.has(referencedTable)) {\n // Circular dependency: table is currently being loaded\n circularDependencies.add(referencedTable);\n } else {\n // Actual failure: table attempted but not loaded\n failedDependencies.add(referencedTable);\n }\n }\n }\n if (failedDependencies.size > 0) {\n for (const dep of failedDependencies) {\n warnings.push(\n `Skipping foreign key validation for table '${tableName}': referenced table '${dep}' has validation errors`,\n );\n }\n }\n }\n\n // Combine failed and circular dependencies for table loading (both need FK skipping)\n const allSkippedDependencies = new Set([...failedDependencies, ...circularDependencies]);\n\n // Now load this table\n const {\n loaded,\n rowCount,\n errors: loadErrors,\n } = await this.loadTable(tableName, tableConfig, detailedValidate, transform, allSkippedDependencies);\n errors.push(...loadErrors);\n rowCounts.set(tableName, rowCount);\n\n if (loaded) {\n loadedTables.add(tableName);\n\n // Track circular dependency FKs for deferred validation\n if (foreignKeys && circularDependencies.size > 0) {\n for (const fk of foreignKeys) {\n if (circularDependencies.has(fk.references.table)) {\n deferredForeignKeys.push({\n tableName,\n foreignKey: fk,\n filePath: tableConfig.jsonlPath,\n });\n }\n }\n }\n } else {\n // Table was not loaded (e.g., empty data)\n warnings.push(`Table '${tableName}' was not loaded (no data or skipped)`);\n this.tables.delete(tableName);\n }\n } finally {\n // Remove from loading set\n loadingTables.delete(tableName);\n }\n\n return { errors, warnings, rowCounts, deferredForeignKeys };\n }\n\n /**\n * Load a single table from JSONL file\n * @returns Object with loaded status and validation errors\n */\n private async loadTable(\n tableName: string,\n config: TableConfig,\n detailedValidate: boolean,\n transform?: (row: JsonObject) => JsonObject,\n failedDependencies?: Set<string>,\n ): Promise<{ loaded: boolean; rowCount: number; errors: ValidationErrorDetail[] }> {\n // Read JSONL file\n let data = await JsonlReader.read(config.jsonlPath);\n\n // Apply transform if provided (before validation)\n if (transform) {\n data = data.map((row) => transform(row));\n }\n\n // Load validation schema if provided or try to auto-load\n let validationSchema = config.validationSchema;\n const schemaMetadata: {\n primaryKey?: string;\n foreignKeys?: BiDirectionalSchema['foreignKeys'];\n indexes?: BiDirectionalSchema['indexes'];\n } = {};\n\n if (!validationSchema) {\n try {\n validationSchema = await SchemaLoader.loadSchema(config.jsonlPath);\n } catch (_error) {\n // Schema file not found or failed to load - this is OK, table can still be used without validation\n }\n }\n\n // Load schema metadata (foreignKeys, primaryKey, indexes) from schema module\n // SchemaLoader.loadSchema() only returns the validation schema object, not metadata\n if (!config.validationSchema) {\n // Only load if not already provided via config\n try {\n const { pathToFileURL } = await import('node:url');\n const schemaPath = await findSchemaFile(dirname(config.jsonlPath), basename(config.jsonlPath, '.jsonl'));\n if (!schemaPath) throw new Error('Schema file not found');\n const schemaUrl = pathToFileURL(schemaPath).href;\n const schemaModule = await import(`${schemaUrl}?t=${Date.now()}`);\n\n // Try to get metadata from exported 'schema' or directly from module\n const schemaExport = schemaModule.schema || schemaModule.default;\n\n if (schemaExport?.primaryKey) {\n schemaMetadata.primaryKey = schemaExport.primaryKey;\n } else if (schemaModule.primaryKey) {\n schemaMetadata.primaryKey = schemaModule.primaryKey;\n }\n\n if (schemaExport?.foreignKeys) {\n schemaMetadata.foreignKeys = schemaExport.foreignKeys;\n } else if (schemaModule.foreignKeys) {\n schemaMetadata.foreignKeys = schemaModule.foreignKeys;\n }\n\n if (schemaExport?.indexes) {\n schemaMetadata.indexes = schemaExport.indexes;\n } else if (schemaModule.indexes) {\n schemaMetadata.indexes = schemaModule.indexes;\n }\n\n // Debug: log loaded metadata\n if (process.env.DEBUG_LINES_DB) {\n console.log(`[lines-db] Schema metadata for ${tableName}:`);\n console.log(` primaryKey: ${schemaMetadata.primaryKey}`);\n console.log(` foreignKeys: ${JSON.stringify(schemaMetadata.foreignKeys)}`);\n console.log(` indexes: ${JSON.stringify(schemaMetadata.indexes)}`);\n }\n } catch (_error) {\n // Schema file not found - this is OK\n // Debug: log error for investigation\n if (process.env.DEBUG_LINES_DB) {\n console.warn(\n `[lines-db] Failed to load schema metadata for ${tableName}:`,\n _error instanceof Error ? _error.message : String(_error),\n );\n }\n }\n }\n\n this.validationSchemas.set(tableName, validationSchema);\n\n // Validate data first and collect validated (transformed) data\n const validationErrors: Array<{\n rowIndex: number;\n rowData: JsonObject;\n error: ValidationError;\n }> = [];\n const validatedData: JsonObject[] = [];\n\n for (let rowIndex = 0; rowIndex < data.length; rowIndex++) {\n const row = data[rowIndex];\n try {\n const validatedRow = this.validateAndTransform(tableName, row);\n validatedData.push(validatedRow);\n } catch (error) {\n if (error instanceof Error && error.name === 'ValidationError') {\n validationErrors.push({\n rowIndex,\n rowData: row,\n error: error as ValidationError,\n });\n } else {\n throw error;\n }\n }\n }\n\n // Convert validation errors to ValidationErrorDetail format\n const validationErrorDetails: ValidationErrorDetail[] = validationErrors.map((ve) => ({\n file: config.jsonlPath,\n tableName,\n rowIndex: ve.rowIndex,\n issues: ve.error.issues,\n type: 'schema' as const,\n }));\n\n if (validationErrors.length > 0) {\n // Return errors instead of throwing\n return { loaded: false, rowCount: data.length, errors: validationErrorDetails };\n }\n\n // Determine schema - infer from validated data if auto-inference is enabled\n let schema: TableSchema;\n let inferredSchema: TableSchema | undefined;\n\n // Always infer schema from validated data to capture valueType information (e.g., boolean)\n if (validatedData.length > 0) {\n inferredSchema = JsonlReader.inferSchema(tableName, validatedData);\n }\n\n if (config.schema) {\n schema = config.schema;\n // Merge valueType information from inferred schema\n if (inferredSchema) {\n for (const inferredCol of inferredSchema.columns) {\n const schemaCol = schema.columns.find((c) => c.name === inferredCol.name);\n if (schemaCol && inferredCol.valueType && !schemaCol.valueType) {\n schemaCol.valueType = inferredCol.valueType;\n }\n }\n }\n } else if (config.autoInferSchema !== false) {\n if (validatedData.length === 0) {\n return { loaded: false, rowCount: 0, errors: [] };\n }\n // Use inferred schema\n schema = inferredSchema!;\n } else {\n // Critical error - throw exception\n throw new Error(`No schema provided for table ${tableName} and autoInferSchema is disabled`);\n }\n\n // Enhance schema with constraints from validation schema and schema metadata\n // Priority: config.validationSchema (as BiDirectionalSchema) > schemaMetadata\n const biSchema = validationSchema as BiDirectionalSchema;\n const primaryKey = biSchema?.primaryKey || schemaMetadata.primaryKey;\n const foreignKeys = biSchema?.foreignKeys || schemaMetadata.foreignKeys;\n const indexes = biSchema?.indexes || schemaMetadata.indexes;\n\n if (primaryKey && !schema.columns.some((col) => col.primaryKey)) {\n // Add primary key constraint to column\n const col = schema.columns.find((c) => c.name === primaryKey);\n if (col) {\n col.primaryKey = true;\n }\n } else if (!primaryKey && !schema.columns.some((col) => col.primaryKey)) {\n // If no primary key is defined, use 'id' column as primary key if it exists\n // This matches the behavior of JsonlReader.inferSchema()\n const idColumn = schema.columns.find((c) => c.name === 'id');\n if (idColumn) {\n idColumn.primaryKey = true;\n }\n }\n if (foreignKeys) {\n schema.foreignKeys =\n failedDependencies && failedDependencies.size > 0\n ? foreignKeys.filter((fk) => !failedDependencies.has(fk.references.table))\n : foreignKeys;\n }\n if (indexes) {\n schema.indexes = indexes;\n\n // Apply unique constraint from single-column unique indexes to column definitions\n // This is required for foreign key references, as SQLite requires the referenced column\n // to have a UNIQUE constraint in the table definition (not just an index)\n for (const index of indexes) {\n if (index.unique && index.columns.length === 1) {\n const col = schema.columns.find((c) => c.name === index.columns[0]);\n if (col && !col.unique && !col.primaryKey) {\n col.unique = true;\n }\n }\n }\n }\n\n this.schemas.set(tableName, schema);\n\n // Create table\n this.createTable(schema);\n\n // Insert validated data (with detailed validation if requested)\n if (detailedValidate) {\n const insertErrors = this.insertDataWithDetailedValidation(tableName, schema, validatedData, config.jsonlPath);\n if (insertErrors.length > 0) {\n return { loaded: false, rowCount: data.length, errors: insertErrors };\n }\n } else {\n this.insertData(tableName, schema, validatedData);\n }\n\n return { loaded: true, rowCount: data.length, errors: [] };\n }\n\n /**\n * Create table in SQLite with constraints and indexes\n */\n private createTable(schema: TableSchema): void {\n // Note: Foreign key constraints are enabled at database connection level (see sqlite-adapter.ts)\n // No need to enable them here for each table\n\n // Quote table name to handle special characters\n const quotedTableName = this.quoteTableName(schema.name);\n\n // Build a set of columns that should have UNIQUE constraint\n // This includes columns marked as unique in schema AND single-column unique indexes\n // The latter is required for foreign key references, as SQLite requires the referenced column\n // to have a UNIQUE constraint in the table definition (not just a separately created index)\n const uniqueColumns = new Set<string>();\n for (const col of schema.columns) {\n if (col.unique) {\n uniqueColumns.add(col.name);\n }\n }\n if (schema.indexes) {\n for (const index of schema.indexes) {\n if (index.unique && index.columns.length === 1) {\n uniqueColumns.add(index.columns[0]);\n }\n }\n }\n\n const columnDefs = schema.columns.map((col) => {\n // JSON type is stored as TEXT in SQLite\n const sqlType = col.type === 'JSON' ? 'TEXT' : col.type;\n const parts = [this.quoteIdentifier(col.name), sqlType];\n if (col.primaryKey) parts.push('PRIMARY KEY');\n if (col.notNull) parts.push('NOT NULL');\n if (uniqueColumns.has(col.name) && !col.primaryKey) parts.push('UNIQUE');\n return parts.join(' ');\n });\n\n // Add foreign key constraints\n const foreignKeyDefs: string[] = [];\n if (schema.foreignKeys && schema.foreignKeys.length > 0) {\n for (const fk of schema.foreignKeys) {\n const fkParts = [\n `FOREIGN KEY (${this.quoteIdentifier(fk.column)})`,\n `REFERENCES ${this.quoteTableName(fk.references.table)}(${this.quoteIdentifier(fk.references.column)})`,\n ];\n if (fk.onDelete) {\n fkParts.push(`ON DELETE ${fk.onDelete}`);\n }\n if (fk.onUpdate) {\n fkParts.push(`ON UPDATE ${fk.onUpdate}`);\n }\n foreignKeyDefs.push(fkParts.join(' '));\n }\n }\n\n const allDefs = [...columnDefs, ...foreignKeyDefs];\n const sql = `CREATE TABLE IF NOT EXISTS ${quotedTableName} (${allDefs.join(', ')})`;\n this.db.exec(sql);\n\n // Create indexes\n if (schema.indexes && schema.indexes.length > 0) {\n for (let i = 0; i < schema.indexes.length; i++) {\n const index = schema.indexes[i];\n // Create safe index name by replacing special characters\n const safeTableName = schema.name.replace(/[^a-zA-Z0-9]/g, '_');\n const resolvedIndexName = index.name || `idx_${safeTableName}_${index.columns.join('_')}_${i}`;\n const uniqueKeyword = index.unique ? 'UNIQUE ' : '';\n const indexSql = `CREATE ${uniqueKeyword}INDEX IF NOT EXISTS ${this.quoteIdentifier(resolvedIndexName)} ON ${quotedTableName} (${index.columns\n .map((col) => this.quoteIdentifier(col))\n .join(', ')})`;\n this.db.exec(indexSql);\n }\n }\n }\n\n /**\n * Quote table name to handle special characters in SQL\n */\n private quoteTableName(tableName: string): string {\n return this.quoteIdentifier(tableName);\n }\n\n /**\n * Quote identifier for SQL statements, escaping embedded quotes\n */\n private quoteIdentifier(identifier: string): string {\n return `\"${identifier.replace(/\"/g, '\"\"')}\"`;\n }\n\n /**\n * Insert data into table using batch insert (multiple rows per SQL)\n * SQLite has a parameter limit (default 999), so we batch rows accordingly\n * Throws exception if any constraint violation occurs\n */\n private insertData(tableName: string, schema: TableSchema, data: JsonObject[]): void {\n if (data.length === 0) return;\n\n const columnNames = schema.columns.map((col) => col.name);\n const quotedColumns = columnNames.map((name) => this.quoteIdentifier(name));\n const columnCount = columnNames.length;\n\n // Calculate batch size to stay under SQLite's parameter limit (999)\n // Leave some margin for safety\n const maxBatchSize = Math.floor(900 / columnCount);\n const batchSize = Math.max(1, Math.min(maxBatchSize, 100));\n\n // Process data in batches\n for (let i = 0; i < data.length; i += batchSize) {\n const batch = data.slice(i, i + batchSize);\n const rowPlaceholders = columnNames.map(() => '?').join(', ');\n const valuesPlaceholders = batch.map(() => `(${rowPlaceholders})`).join(', ');\n const sql = `INSERT INTO ${this.quoteTableName(tableName)} (${quotedColumns.join(', ')}) VALUES ${valuesPlaceholders}`;\n\n const values: (string | number | bigint | null | Uint8Array)[] = [];\n for (const row of batch) {\n for (const col of columnNames) {\n values.push(this.normalizeValue(row[col]));\n }\n }\n\n const stmt = this.db.prepare(sql);\n stmt.run(...values);\n }\n }\n\n /**\n * Insert data into table one row at a time with detailed error reporting\n * This is used for validation to catch constraint violations\n */\n private insertDataWithDetailedValidation(\n tableName: string,\n schema: TableSchema,\n data: JsonObject[],\n filePath: string,\n ): ValidationErrorDetail[] {\n const errors: ValidationErrorDetail[] = [];\n const columnNames = schema.columns.map((col) => col.name);\n const quotedColumns = columnNames.map((name) => this.quoteIdentifier(name));\n const placeholders = columnNames.map(() => '?').join(', ');\n const sql = `INSERT INTO ${this.quoteTableName(tableName)} (${quotedColumns.join(', ')}) VALUES (${placeholders})`;\n\n const stmt = this.db.prepare(sql);\n\n for (let rowIndex = 0; rowIndex < data.length; rowIndex++) {\n const row = data[rowIndex];\n try {\n const values = columnNames.map((col) => this.normalizeValue(row[col]));\n stmt.run(...values);\n } catch (error) {\n // Constraint violation occurred - analyze and record details\n const constraintError = this.analyzeConstraintError(\n error,\n filePath,\n tableName,\n rowIndex,\n row,\n schema.foreignKeys || [],\n );\n if (constraintError) {\n errors.push(constraintError);\n }\n }\n }\n\n return errors;\n }\n\n /**\n * Analyze constraint error and extract detailed information\n */\n private analyzeConstraintError(\n error: unknown,\n file: string,\n tableName: string,\n rowIndex: number,\n row: JsonObject,\n foreignKeys: ForeignKeyDefinition[],\n ): ValidationErrorDetail | null {\n const errorMessage = error instanceof Error ? error.message : String(error);\n\n // Foreign key constraint\n if (errorMessage.includes('FOREIGN KEY constraint failed')) {\n // Find which foreign key failed\n for (const fk of foreignKeys) {\n const fkValue = row[fk.column];\n if (fkValue === null || fkValue === undefined) continue;\n\n // Check if referenced value exists\n try {\n const result = this.query(\n `SELECT COUNT(*) as count FROM ${this.quoteIdentifier(fk.references.table)} WHERE ${this.quoteIdentifier(fk.references.column)} = ?`,\n [this.normalizeValue(fkValue)],\n );\n if (result.length > 0 && (result[0] as { count: number }).count === 0) {\n return {\n file,\n tableName,\n rowIndex,\n issues: [],\n type: 'foreignKey',\n foreignKeyError: {\n column: fk.column,\n value: fkValue,\n referencedTable: fk.references.table,\n referencedColumn: fk.references.column,\n },\n };\n }\n } catch (_) {\n // Referenced table doesn't exist yet\n }\n }\n }\n\n // Other constraint errors (primary key, unique, etc.)\n return {\n file,\n tableName,\n rowIndex,\n issues: [\n {\n message: errorMessage,\n path: [],\n },\n ],\n type: 'schema',\n };\n }\n\n /**\n * Validate a deferred foreign key constraint after all tables have been loaded.\n * Used for circular dependency FK validation.\n */\n private validateDeferredForeignKey(\n tableName: string,\n fk: ForeignKeyDefinition,\n filePath: string,\n ): ValidationErrorDetail[] {\n const errors: ValidationErrorDetail[] = [];\n const quotedTable = this.quoteTableName(tableName);\n const quotedColumn = this.quoteIdentifier(fk.column);\n const quotedRefTable = this.quoteTableName(fk.references.table);\n const quotedRefColumn = this.quoteIdentifier(fk.references.column);\n\n // Find rows where the FK value does not exist in the referenced table\n const sql = `SELECT rowid - 1 as idx, ${quotedColumn} as val FROM ${quotedTable} WHERE ${quotedColumn} IS NOT NULL AND ${quotedColumn} NOT IN (SELECT ${quotedRefColumn} FROM ${quotedRefTable})`;\n\n try {\n const rows = this.query<{ idx: number; val: string | number }>(sql);\n for (const row of rows) {\n errors.push({\n file: filePath,\n tableName,\n rowIndex: row.idx,\n issues: [],\n type: 'foreignKey',\n foreignKeyError: {\n column: fk.column,\n value: row.val,\n referencedTable: fk.references.table,\n referencedColumn: fk.references.column,\n },\n });\n }\n } catch (_) {\n // Table might not exist - skip validation\n }\n\n return errors;\n }\n\n /**\n * Execute a raw SQL query\n */\n query<T = unknown>(sql: string, params: (string | number | bigint | null | Uint8Array)[] = []): T[] {\n const stmt = this.db.prepare(sql);\n return stmt.all(...params) as T[];\n }\n\n /**\n * Execute a SQL query that returns a single row\n */\n queryOne<T = unknown>(sql: string, params: (string | number | bigint | null | Uint8Array)[] = []): T | null {\n const stmt = this.db.prepare(sql);\n const result = stmt.get(...params);\n return result === undefined ? null : (result as T);\n }\n\n /**\n * Execute a SQL statement (INSERT, UPDATE, DELETE)\n */\n execute(\n sql: string,\n params: (string | number | bigint | null | Uint8Array)[] = [],\n ): { changes: number | bigint; lastInsertRowid: number | bigint } {\n const stmt = this.db.prepare(sql);\n return stmt.run(...params);\n }\n\n /**\n * Find rows by condition (supports OR/AND with arrays and function filters)\n * If where is not provided, returns all rows\n */\n find<K extends keyof Tables & string>(tableName: K, where?: WhereCondition<Tables[K]>) {\n // If no where condition, return all rows\n if (where === undefined) {\n const rows = this.query(`SELECT * FROM ${this.quoteTableName(tableName)}`);\n return rows.map((row) => this.deserializeRow(tableName, row)) as Tables[K][];\n }\n\n // Handle empty array - should return no results\n if (Array.isArray(where) && where.length === 0) {\n return [];\n }\n\n const { sql, values, functionFilters, hasOrWithFunctionFilters } = this.buildWhereClause(where);\n\n let rows: Tables[K][];\n\n // If OR condition has function filters, get all rows and evaluate in JS\n if (hasOrWithFunctionFilters) {\n const rawRows = this.query(`SELECT * FROM ${this.quoteTableName(tableName)}`);\n rows = rawRows.map((row) => this.deserializeRow(tableName, row)) as Tables[K][];\n return this.applyOrConditionWithFilters(rows, where as WhereCondition<Tables[K]>);\n }\n\n // Normal case: use SQL WHERE clause\n if (sql) {\n const rawRows = this.query(`SELECT * FROM ${this.quoteTableName(tableName)} WHERE ${sql}`, values);\n rows = rawRows.map((row) => this.deserializeRow(tableName, row)) as Tables[K][];\n } else {\n // If only function filters (AND case), get all rows\n const rawRows = this.query(`SELECT * FROM ${this.quoteTableName(tableName)}`);\n rows = rawRows.map((row) => this.deserializeRow(tableName, row)) as Tables[K][];\n }\n\n // Apply function filters for AND conditions\n return this.applyFunctionFilters(rows, functionFilters);\n }\n\n /**\n * Find a single row by condition (supports OR/AND with arrays and function filters)\n */\n findOne<K extends keyof Tables & string>(tableName: K, where: WhereCondition<Tables[K]>) {\n const { sql, values, functionFilters } = this.buildWhereClause(where);\n\n let rows: Tables[K][];\n if (sql) {\n const rawRows = this.query(`SELECT * FROM ${this.quoteTableName(tableName)} WHERE ${sql}`, values);\n rows = rawRows.map((row) => this.deserializeRow(tableName, row)) as Tables[K][];\n } else {\n // If only function filters, get all rows\n const rawRows = this.query(`SELECT * FROM ${this.quoteTableName(tableName)}`);\n rows = rawRows.map((row) => this.deserializeRow(tableName, row)) as Tables[K][];\n }\n\n // Apply function filters and return first match\n const filtered = this.applyFunctionFilters(rows, functionFilters);\n return filtered.length > 0 ? filtered[0] : null;\n }\n\n /**\n * Deserialize JSON columns in a row\n */\n private deserializeRow<T>(tableName: string, row: T): T {\n const schema = this.schemas.get(tableName);\n if (!schema) return row;\n\n const deserializedRow = { ...row } as Record<string, unknown>;\n\n for (const column of schema.columns) {\n const colName = column.name;\n if (!(colName in deserializedRow)) continue;\n\n const value = deserializedRow[colName];\n\n if (column.type === 'JSON' && typeof value === 'string') {\n try {\n deserializedRow[colName] = JSON.parse(value);\n } catch (error) {\n // If parsing fails, keep the original value\n console.warn(`Failed to parse JSON column ${colName}:`, error);\n }\n continue;\n }\n\n if (column.valueType === 'boolean') {\n if (typeof value === 'number') {\n deserializedRow[colName] = value === 0 ? false : true;\n } else if (typeof value === 'bigint') {\n deserializedRow[colName] = value === 0n ? false : true;\n }\n }\n }\n\n return deserializedRow as T;\n }\n\n /**\n * Validate data using StandardSchema and return the transformed value\n * Note: Only synchronous validation is supported\n */\n private validateAndTransform(tableName: string, data: unknown): JsonObject {\n const schema = this.validationSchemas.get(tableName);\n if (!schema) {\n return data as JsonObject;\n }\n\n const result = schema['~standard'].validate(data);\n\n // Only synchronous validation is supported\n if (result instanceof Promise) {\n throw new Error('Asynchronous validation is not supported. Please use synchronous validation schemas.');\n }\n\n if (result.issues && result.issues.length > 0) {\n // Format detailed error message with all validation issues\n const issueMessages = result.issues\n .map((issue) => {\n // Handle path: can be array of PathSegment or undefined\n let pathStr = 'root';\n if (issue.path && issue.path.length > 0) {\n pathStr = issue.path\n .map((segment) => {\n // PathSegment can be { key: PropertyKey } or just PropertyKey\n if (typeof segment === 'object' && segment !== null && 'key' in segment) {\n return String(segment.key);\n }\n return String(segment);\n })\n .join('.');\n }\n return ` - ${pathStr}: ${issue.message}`;\n })\n .join('\\n');\n\n const errorMessage = `Validation failed for table '${tableName}':\\n${issueMessages}`;\n const error = new Error(errorMessage) as ValidationError;\n error.name = 'ValidationError';\n error.issues = result.issues;\n throw error;\n }\n\n // Return the transformed value from validation\n // When there are no issues, result.value should be present\n const transformedValue = ('value' in result ? result.value : data) as JsonObject;\n\n // Convert undefined values to null for JSON compatibility\n const normalizedValue: JsonObject = {};\n for (const [key, value] of Object.entries(transformedValue)) {\n normalizedValue[key] = value === undefined ? null : value;\n }\n\n return normalizedValue;\n }\n\n /**\n * Validate data using StandardSchema (without returning transformed value)\n * Note: Only synchronous validation is supported\n */\n private validateData(tableName: string, data: unknown): void {\n // Use validateAndTransform but discard the result\n this.validateAndTransform(tableName, data);\n }\n\n /**\n * Insert a row into a table with validation\n */\n insert<K extends keyof Tables & string>(\n tableName: K,\n data: Tables[K],\n ): { changes: number | bigint; lastInsertRowid: number | bigint } {\n // Validate if schema exists\n this.validateData(tableName, data);\n\n const schema = this.schemas.get(tableName);\n if (!schema) {\n throw new Error(`Table ${tableName} does not exist`);\n }\n\n const columnNames = Object.keys(data);\n const quotedColumns = columnNames.map((col) => this.quoteIdentifier(col));\n const placeholders = columnNames.map(() => '?').join(', ');\n const sql = `INSERT INTO ${this.quoteTableName(tableName)} (${quotedColumns.join(', ')}) VALUES (${placeholders})`;\n\n const values = Object.values(data).map((v) => this.normalizeValue(v));\n const result = this.execute(sql, values);\n\n // Auto-sync if not in transaction\n if (!this.inTransaction) {\n this.syncTable(tableName).catch((err) => {\n console.error(`Failed to sync table ${tableName}:`, err);\n });\n }\n\n return result;\n }\n\n /**\n * Batch insert rows with validation per record.\n */\n batchInsert<K extends keyof Tables & string>(\n tableName: K,\n records: Tables[K][],\n ): { changes: number | bigint; lastInsertRowid: number | bigint } {\n const schema = this.schemas.get(tableName);\n if (!schema) {\n throw new Error(`Table ${tableName} does not exist`);\n }\n\n if (records.length === 0) {\n return { changes: 0, lastInsertRowid: 0 };\n }\n\n let totalChanges = 0n;\n let lastRowid = 0n;\n\n for (const record of records) {\n this.validateData(tableName, record);\n\n const columnNames = Object.keys(record);\n const quotedColumns = columnNames.map((col) => this.quoteIdentifier(col));\n const placeholders = columnNames.map(() => '?').join(', ');\n const sql = `INSERT INTO ${this.quoteTableName(tableName)} (${quotedColumns.join(', ')}) VALUES (${placeholders})`;\n\n const values = columnNames.map((col) => this.normalizeValue(record[col as keyof Tables[K]]));\n\n const result = this.execute(sql, values);\n totalChanges += BigInt(result.changes);\n lastRowid = BigInt(result.lastInsertRowid);\n }\n\n if (!this.inTransaction) {\n this.syncTable(tableName).catch((err) => {\n console.error(`Failed to sync table ${tableName}:`, err);\n });\n }\n\n return {\n changes: totalChanges,\n lastInsertRowid: lastRowid,\n };\n }\n\n /**\n * Update rows in a table with validation (supports OR/AND with arrays)\n * Note: Function filters are not supported for update operations\n * Note: By default, validation is enabled. For partial updates, existing data is fetched\n * and merged before validation. Set options.validate = false to disable validation.\n */\n update<K extends keyof Tables & string>(\n tableName: K,\n data: Partial<Tables[K]>,\n where: WhereCondition<Tables[K]>,\n options?: { validate?: boolean },\n ): { changes: number | bigint; lastInsertRowid: number | bigint } {\n const schema = this.schemas.get(tableName);\n if (!schema) {\n throw new Error(`Table ${tableName} does not exist`);\n }\n\n // Validate by default (can be disabled with validate: false)\n const shouldValidate = options?.validate !== false;\n const hasValidationSchema = this.validationSchemas.has(tableName);\n\n if (shouldValidate && hasValidationSchema) {\n // Get existing rows to merge with partial data\n const existingRows = this.find(tableName, where);\n\n // Validate each merged row\n for (const existingRow of existingRows) {\n const mergedData = { ...existingRow, ...data };\n this.validateData(tableName, mergedData);\n }\n }\n\n const { sql: whereSql, values: whereValues, functionFilters } = this.buildWhereClause(where);\n\n if (functionFilters.length > 0) {\n throw new Error('Function filters are not supported in update operations');\n }\n\n const setClauses = Object.keys(data)\n .map((key) => `${this.quoteIdentifier(key)} = ?`)\n .join(', ');\n const sql = `UPDATE ${this.quoteTableName(tableName)} SET ${setClauses} WHERE ${whereSql}`;\n\n const values = [...Object.values(data).map((v) => this.normalizeValue(v)), ...whereValues];\n\n const result = this.execute(sql, values);\n\n // Auto-sync if not in transaction\n if (!this.inTransaction) {\n this.syncTable(tableName).catch((err) => {\n console.error(`Failed to sync table ${tableName}:`, err);\n });\n }\n\n return result;\n }\n\n /**\n * Batch update rows with record-specific values and validation.\n * Each record must include the primary key to identify the target row.\n * Validation runs once per merged record unless explicitly disabled.\n */\n batchUpdate<K extends keyof Tables & string>(\n tableName: K,\n records: Array<Partial<Tables[K]> & Record<string, unknown>>,\n options?: { validate?: boolean },\n ): { changes: number | bigint; lastInsertRowid: number | bigint } {\n const schema = this.schemas.get(tableName);\n if (!schema) {\n throw new Error(`Table ${tableName} does not exist`);\n }\n\n if (records.length === 0) {\n return { changes: 0, lastInsertRowid: 0 };\n }\n\n // Get primary key column\n const pkColumn = schema.columns.find((col) => col.primaryKey);\n if (!pkColumn) {\n throw new Error(`Table ${tableName} does not have a primary key`);\n }\n\n const pkName = pkColumn.name;\n\n // Extract primary key values from records\n const pkValues: unknown[] = [];\n for (const record of records) {\n const pkValue = record[pkName];\n if (pkValue === undefined) {\n throw new Error(`Record is missing primary key '${String(pkName)}': ${JSON.stringify(record)}`);\n }\n pkValues.push(pkValue);\n }\n\n // Validate by default (can be disabled with validate: false)\n const shouldValidate = options?.validate !== false;\n const hasValidationSchema = this.validationSchemas.has(tableName);\n\n if (shouldValidate && hasValidationSchema) {\n // Build OR condition to fetch all existing rows at once\n const orCondition = pkValues.map((pkValue) => ({\n [pkName]: pkValue,\n })) as WhereCondition<Tables[K]>;\n\n // Fetch all existing rows in one query\n const existingRows = this.find(tableName, orCondition);\n\n // Create a map for fast lookup: pkValue -> existingRow\n const existingRowsMap = new Map<unknown, Tables[K]>();\n for (const row of existingRows) {\n const pkValue = (row as Record<string, unknown>)[pkName];\n existingRowsMap.set(pkValue, row);\n }\n\n // Validate each merged record and collect all errors\n const validationErrors: Array<{\n rowIndex: number;\n rowData: unknown;\n pkValue: unknown;\n error: ValidationError;\n }> = [];\n\n for (let i = 0; i < records.length; i++) {\n const record = records[i];\n const pkValue = record[pkName];\n const existingRow = existingRowsMap.get(pkValue);\n\n if (!existingRow) {\n throw new Error(`No existing row found with ${String(pkName)}=${JSON.stringify(pkValue)}`);\n }\n\n const mergedData = { ...existingRow, ...record };\n\n try {\n this.validateData(tableName, mergedData);\n } catch (error) {\n // Collect validation errors instead of throwing immediately\n if (error instanceof Error && error.name === 'ValidationError') {\n validationErrors.push({\n rowIndex: i,\n rowData: mergedData,\n pkValue,\n error: error as ValidationError,\n });\n } else {\n throw error;\n }\n }\n }\n\n // If there are validation errors, throw with all error information\n if (validationErrors.length > 0) {\n const enhancedError = new Error(\n `Validation failed for ${validationErrors.length} row(s)`,\n ) as ValidationError & { validationErrors: typeof validationErrors };\n enhancedError.name = 'ValidationError';\n enhancedError.validationErrors = validationErrors;\n // For backward compatibility, include issues from first error\n enhancedError.issues = validationErrors[0].error.issues;\n throw enhancedError;\n }\n }\n\n // All validations passed - perform updates\n let totalChanges = 0n;\n let lastRowid = 0n;\n\n for (const record of records) {\n const pkValue = record[pkName];\n const where = { [pkName]: pkValue } as WhereCondition<Tables[K]>;\n\n // Call update without validation (already validated above)\n const result = this.update(tableName, record as Partial<Tables[K]>, where, {\n validate: false,\n });\n\n totalChanges += BigInt(result.changes);\n lastRowid = BigInt(result.lastInsertRowid);\n }\n\n return {\n changes: totalChanges,\n lastInsertRowid: lastRowid,\n };\n }\n\n /**\n * Delete rows from a table (supports OR/AND with arrays)\n * Note: Function filters are not supported for delete operations\n */\n delete<K extends keyof Tables & string>(\n tableName: K,\n where: WhereCondition<Tables[K]>,\n ): { changes: number | bigint; lastInsertRowid: number | bigint } {\n const schema = this.schemas.get(tableName);\n if (!schema) {\n throw new Error(`Table ${tableName} does not exist`);\n }\n\n const { sql: whereSql, values, functionFilters } = this.buildWhereClause(where);\n\n if (functionFilters.length > 0) {\n throw new Error('Function filters are not supported in delete operations');\n }\n\n const sql = `DELETE FROM ${this.quoteTableName(tableName)} WHERE ${whereSql}`;\n const result = this.execute(sql, values);\n\n // Auto-sync if not in transaction\n if (!this.inTransaction) {\n this.syncTable(tableName).catch((err) => {\n console.error(`Failed to sync table ${tableName}:`, err);\n });\n }\n\n return result;\n }\n\n /**\n * Batch delete rows by primary key.\n */\n batchDelete<K extends keyof Tables & string>(\n tableName: K,\n records: Array<Partial<Tables[K]> & Record<string, unknown>>,\n ): { changes: number | bigint; lastInsertRowid: number | bigint } {\n const schema = this.schemas.get(tableName);\n if (!schema) {\n throw new Error(`Table ${tableName} does not exist`);\n }\n\n if (records.length === 0) {\n return { changes: 0, lastInsertRowid: 0 };\n }\n\n const pkColumn = schema.columns.find((col) => col.primaryKey);\n if (!pkColumn) {\n throw new Error(`Table ${tableName} does not have a primary key`);\n }\n const pkName = pkColumn.name;\n\n const pkValues = records.map((record, index) => {\n const pkValue = record[pkName as keyof Tables[K]];\n if (pkValue === undefined) {\n throw new Error(`Record at index ${index} is missing primary key '${String(pkName)}'`);\n }\n return pkValue;\n });\n\n const placeholders = pkValues.map(() => '?').join(', ');\n const sql = `DELETE FROM ${this.quoteTableName(tableName)} WHERE ${this.quoteIdentifier(pkName)} IN (${placeholders})`;\n const values = pkValues.map((value) => this.normalizeValue(value));\n\n const result = this.execute(sql, values);\n\n if (!this.inTransaction) {\n this.syncTable(tableName).catch((err) => {\n console.error(`Failed to sync table ${tableName}:`, err);\n });\n }\n\n return {\n changes: BigInt(result.changes),\n lastInsertRowid: BigInt(result.lastInsertRowid),\n };\n }\n\n /**\n * Normalize value for SQLite\n */\n private normalizeValue(value: unknown): string | number | bigint | null | Uint8Array {\n if (value === null || value === undefined) return null;\n if (typeof value === 'boolean') return value ? 1 : 0;\n if (typeof value === 'string' || typeof value === 'number' || typeof value === 'bigint') return value;\n if (value instanceof Uint8Array) return value;\n // For objects, convert to JSON string\n return JSON.stringify(value);\n }\n\n /**\n * Build WHERE clause from condition (supports OR/AND with arrays and functions)\n */\n private buildWhereClause<T extends Record<string, unknown>>(\n condition: WhereCondition<T>,\n ): {\n sql: string;\n values: Array<string | number | bigint | null | Uint8Array>;\n functionFilters: Array<{\n key: string;\n fn: (value: unknown) => boolean;\n }>;\n hasOrWithFunctionFilters: boolean;\n } {\n const values: Array<string | number | bigint | null | Uint8Array> = [];\n const functionFilters: Array<{ key: string; fn: (value: unknown) => boolean }> = [];\n let hasOrWithFunctionFilters = false;\n\n const buildCondition = (cond: WhereCondition<T>, isInOr = false): string => {\n // Handle array (OR conditions)\n if (Array.isArray(cond)) {\n const clauses = cond\n .map((item) => {\n const clause = Array.isArray(item) ? buildCondition(item, true) : buildCondition(item, true);\n return clause ? `(${clause})` : '';\n })\n .filter((clause) => clause !== ''); // Filter out empty clauses\n\n return clauses.join(' OR ');\n }\n\n // Handle object (AND conditions)\n const conditions: string[] = [];\n let hasFunctionFilter = false;\n for (const [key, value] of Object.entries(cond)) {\n if (typeof value === 'function') {\n // Function filter - will be applied later\n functionFilters.push({ key, fn: value as (value: unknown) => boolean });\n hasFunctionFilter = true;\n } else {\n // Regular value\n conditions.push(`${this.quoteIdentifier(key)} = ?`);\n values.push(this.normalizeValue(value));\n }\n }\n\n if (isInOr && hasFunctionFilter) {\n hasOrWithFunctionFilters = true;\n }\n\n return conditions.join(' AND ');\n };\n\n const sql = buildCondition(condition);\n return { sql, values, functionFilters, hasOrWithFunctionFilters };\n }\n\n /**\n * Apply OR condition with function filters by evaluating each row against the condition\n */\n private applyOrConditionWithFilters<T extends Record<string, unknown>>(rows: T[], condition: WhereCondition<T>): T[] {\n return rows.filter((row) => this.matchesOrCondition(row, condition));\n }\n\n /**\n * Check if a row matches an OR/AND condition (recursively)\n */\n private matchesOrCondition<T extends Record<string, unknown>>(row: T, condition: WhereCondition<T>): boolean {\n // Handle array (OR conditions)\n if (Array.isArray(condition)) {\n return condition.some((item) => this.matchesOrCondition(row, item));\n }\n\n // Handle object (AND conditions)\n return Object.entries(condition).every(([key, value]) => {\n const rowValue = row[key as keyof T];\n if (typeof value === 'function') {\n return (value as (value: unknown) => boolean)(rowValue);\n }\n return rowValue === value;\n });\n }\n\n /**\n * Apply function filters to rows\n */\n private applyFunctionFilters<T extends Record<string, unknown>>(\n rows: T[],\n functionFilters: Array<{ key: string; fn: (value: unknown) => boolean }>,\n ): T[] {\n if (functionFilters.length === 0) return rows;\n\n return rows.filter((row) => {\n return functionFilters.every(({ key, fn }) => {\n const value = row[key as keyof T];\n return fn(value);\n });\n });\n }\n\n /**\n * Get table schema\n */\n getSchema(tableName: string): TableSchema | undefined {\n return this.schemas.get(tableName);\n }\n\n /**\n * Get all table names\n */\n getTableNames(): string[] {\n return Array.from(this.schemas.keys());\n }\n\n /**\n * Sync a specific table back to its JSONL file\n * Uses backward transformation when available\n */\n private async syncTable(tableName: string): Promise<void> {\n const tableConfig = this.tables.get(tableName);\n if (!tableConfig) {\n throw new Error(`Table ${tableName} not found`);\n }\n\n // Get all rows from the table\n const rows = this.query<JsonObject>(`SELECT * FROM ${this.quoteTableName(tableName)}`);\n\n // Deserialize JSON columns\n const deserializedRows = rows.map((row) => this.deserializeRow(tableName, row));\n\n // Apply backward transformation if available\n const validationSchema = this.validationSchemas.get(tableName);\n let finalRows = deserializedRows;\n\n if (validationSchema && hasBackward(validationSchema)) {\n const biSchema = validationSchema as BiDirectionalSchema<Table, Table>;\n finalRows = deserializedRows.map((row) => biSchema.backward!(row) as JsonObject);\n }\n\n // Write back to JSONL file\n await JsonlWriter.write(tableConfig.jsonlPath, finalRows);\n }\n\n /**\n * Sync database changes back to JSONL files\n * Uses backward transformation when available\n * @param tableName Optional table name to sync. If not provided, syncs all loaded tables\n */\n async sync(tableName?: string): Promise<void> {\n if (tableName) {\n // Sync only the specified table\n if (!this.schemas.has(tableName)) {\n throw new Error(`Table '${tableName}' is not loaded`);\n }\n await this.syncTable(tableName);\n } else {\n // Sync all tables that are loaded (present in schemas map)\n for (const [name] of this.schemas) {\n await this.syncTable(name);\n }\n }\n }\n\n /**\n * Execute a function within a transaction\n * Automatically commits on success or rolls back on error\n */\n async transaction<T>(fn: (tx: LinesDB<Tables>) => Promise<T> | T): Promise<T> {\n if (this.inTransaction) {\n throw new Error('Nested transactions are not supported');\n }\n\n this.db.exec('BEGIN TRANSACTION');\n this.inTransaction = true;\n\n try {\n const result = await fn(this);\n this.db.exec('COMMIT');\n this.inTransaction = false;\n\n // Sync all tables after successful commit\n await this.sync();\n\n return result;\n } catch (error) {\n if (this.inTransaction) {\n this.db.exec('ROLLBACK');\n }\n this.inTransaction = false;\n throw error;\n }\n }\n\n /**\n * Close the database connection\n */\n async close(): Promise<void> {\n try {\n this.db.close();\n } catch (_error) {\n // Ignore errors if database is already closed\n }\n }\n\n /**\n * Get the underlying SQLite database instance\n */\n getDb(): SQLiteDatabase {\n return this.db;\n }\n}\n","import { readdir } from 'node:fs/promises';\nimport { join, relative, basename, dirname, isAbsolute } from 'node:path';\nimport { writeFile, mkdir } from 'node:fs/promises';\nimport { findSchemaFileInEntries, rewriteExtensionForImport } from './schema-extensions.js';\n\nexport interface TypeGeneratorOptions {\n dataDir: string;\n projectRoot?: string; // Default: current working directory\n output?: string; // Output file path (default: db.ts in dataDir)\n}\n\ninterface TableInfo {\n tableName: string;\n schemaFile?: string;\n}\n\nexport class TypeGenerator {\n private dataDir: string;\n private projectRoot: string;\n private outputFile: string;\n private dataDirPath: string;\n\n constructor(options: TypeGeneratorOptions) {\n // For testing: allow overriding projectRoot via environment variable\n const envProjectRoot = process.env.LINES_DB_TEST_PROJECT_ROOT;\n this.projectRoot = envProjectRoot !== undefined ? envProjectRoot : options.projectRoot || process.cwd();\n this.dataDir = options.dataDir;\n this.dataDirPath = isAbsolute(this.dataDir) ? this.dataDir : join(this.projectRoot, this.dataDir);\n this.outputFile = options.output\n ? isAbsolute(options.output)\n ? options.output\n : join(this.projectRoot, options.output)\n : join(this.dataDirPath, 'db.ts');\n }\n\n /**\n * Generate types file from JSONL files and their optional schema files.\n */\n async generate(): Promise<string> {\n // Find all JSONL files and their corresponding schema files\n const tables = await this.findTables();\n\n if (tables.length === 0) {\n throw new Error(`No JSONL files found in ${this.dataDirPath}. Place one or more *.jsonl files in the directory.`);\n }\n\n // Generate type declarations\n const content = this.generateTypeDeclarations(tables);\n\n // Ensure output directory exists\n const outputDir = dirname(this.outputFile);\n await mkdir(outputDir, { recursive: true });\n\n // Write to file\n await writeFile(this.outputFile, content, 'utf-8');\n console.log(`Generated types at ${this.outputFile}`);\n return this.outputFile;\n }\n\n /**\n * Find all *.jsonl files and check if they have corresponding *.schema.ts files\n */\n private async findTables(): Promise<TableInfo[]> {\n try {\n const entries = await readdir(this.dataDirPath, { withFileTypes: true });\n const tables: TableInfo[] = [];\n\n for (const entry of entries) {\n if (entry.isFile() && entry.name.endsWith('.jsonl')) {\n const tableName = basename(entry.name, '.jsonl');\n const schemaFilePath = findSchemaFileInEntries(this.dataDirPath, tableName, entries);\n\n tables.push({\n tableName,\n schemaFile: schemaFilePath,\n });\n }\n }\n\n return tables;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n throw new Error(`Data directory not found: ${this.dataDirPath}. Set lines-db.dataDir to the correct location.`);\n }\n throw error;\n }\n }\n\n /**\n * Generate type declaration content\n */\n private generateTypeDeclarations(tables: TableInfo[]): string {\n const imports: string[] = [];\n const tableEntries: string[] = [];\n const usedAliases = new Set<string>();\n\n for (const table of tables) {\n const tableKey = this.formatTableKey(table.tableName);\n\n if (table.schemaFile) {\n // Table has a schema file\n const schemaIdentifier = this.createSchemaIdentifier(table.tableName, usedAliases);\n usedAliases.add(schemaIdentifier);\n\n // Calculate relative path from output file to schema file\n let relativePath = rewriteExtensionForImport(\n relative(join(this.outputFile, '..'), table.schemaFile).replace(/\\\\/g, '/'), // Convert Windows paths to Unix-style\n );\n\n // Ensure relative path starts with './' or '../'\n if (!relativePath.startsWith('.')) {\n relativePath = './' + relativePath;\n }\n\n // Add import statement for schema\n imports.push(`import { schema as ${schemaIdentifier} } from '${relativePath}';`);\n\n // Add table entry with InferOutput\n tableEntries.push(` ${tableKey}: InferOutput<typeof ${schemaIdentifier}>;`);\n } else {\n // Table has no schema file, use Record<string, unknown>\n tableEntries.push(` ${tableKey}: Record<string, unknown>;`);\n }\n }\n\n // Generate full content\n const importSection = imports.length > 0 ? `${imports.join('\\n')}\\n` : '';\n const inferOutputImport = imports.length > 0 ? ', InferOutput' : '';\n\n return `// Auto-generated by lines-db\n// Do not edit this file manually\n\n${importSection}import type { DatabaseConfig${inferOutputImport} } from '@toiroakr/lines-db';\nimport { fileURLToPath } from 'node:url';\nimport { dirname } from 'node:path';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\nexport type Tables = {\n${tableEntries.join('\\n')}\n};\n\nexport const config: DatabaseConfig<Tables> = {\n dataDir: __dirname,\n};\n`;\n }\n\n private createSchemaIdentifier(tableName: string, usedAliases: Set<string>): string {\n const camel = toCamelCase(tableName);\n const sanitizedBase = sanitizeIdentifier(camel);\n let base = sanitizedBase || 'table';\n\n if (!/^[A-Za-z_$]/.test(base)) {\n base = `_${base}`;\n }\n\n let candidate = `${base}Schema`;\n let suffix = 1;\n while (usedAliases.has(candidate)) {\n candidate = `${base}${++suffix}Schema`;\n }\n\n return candidate;\n }\n\n private formatTableKey(tableName: string): string {\n const identifierPattern = /^[A-Za-z_$][A-Za-z0-9_$]*$/;\n if (identifierPattern.test(tableName)) {\n return tableName;\n }\n const escaped = tableName.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"\\\\'\");\n return `'${escaped}'`;\n }\n}\n\nfunction toCamelCase(value: string): string {\n const parts = value\n .split(/[^A-Za-z0-9]+/)\n .filter(Boolean)\n .map((part) => part.toLowerCase());\n\n if (parts.length === 0) {\n return value;\n }\n\n const [first, ...rest] = parts;\n return first + rest.map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join('');\n}\n\nfunction sanitizeIdentifier(value: string): string {\n return value.replace(/[^A-Za-z0-9_$]/g, '');\n}\n","import { join } from 'node:path';\nimport type { JsonObject } from './types.js';\nimport { JsonlReader } from './jsonl-reader.js';\nimport { LinesDB } from './database.js';\n\nexport interface TableValidationOptions {\n dataDir: string;\n tableName: string;\n rows: JsonObject[];\n}\n\n/**\n * Validate a table by temporarily supplying in-memory rows while reusing the existing LinesDB validation pipeline.\n * If validation fails, throws an error with validation details.\n */\nexport async function ensureTableRowsValid(options: TableValidationOptions): Promise<void> {\n const tablePath = join(options.dataDir, `${options.tableName}.jsonl`);\n const overrides = new Map<string, JsonObject[]>([[tablePath, options.rows]]);\n\n await JsonlReader.withOverrides(overrides, async () => {\n const db = LinesDB.create({ dataDir: options.dataDir });\n try {\n // Initialize only the target table\n const result = await db.initialize({ tableName: options.tableName });\n\n // If validation failed, throw an error with details\n if (!result.valid) {\n const errorCount = result.errors.length;\n const errorDetails = result.errors\n .map((e) => {\n const issueMessages = e.issues.map((issue) => issue.message).join(', ');\n return ` Row ${e.rowIndex}: ${issueMessages}`;\n })\n .join('\\n');\n\n throw new Error(\n `Validation failed for table '${options.tableName}' (${errorCount} error(s)):\\n${errorDetails}`,\n );\n }\n } finally {\n await db.close();\n }\n });\n}\n","import type { StandardSchemaIssue } from './types.js';\nimport { styleText } from 'node:util';\n\nexport interface ValidationErrorInfo {\n file: string;\n rowIndex: number;\n issues: ReadonlyArray<StandardSchemaIssue>;\n data?: unknown;\n originalData?: unknown;\n}\n\nexport interface ForeignKeyErrorInfo {\n file: string;\n rowIndex: number;\n column: string;\n value: unknown;\n referencedTable: string;\n referencedColumn: string;\n data?: unknown;\n}\n\nexport interface ErrorFormatterOptions {\n verbose?: boolean;\n}\n\nexport class ErrorFormatter {\n private verbose: boolean;\n\n constructor(options: ErrorFormatterOptions = {}) {\n this.verbose = options.verbose ?? false;\n }\n\n /**\n * Format validation errors\n */\n formatValidationErrors(errors: ValidationErrorInfo[]): string {\n if (this.verbose) {\n return this.formatValidationErrorsVerbose(errors);\n }\n return this.formatValidationErrorsCompact(errors);\n }\n\n /**\n * Format foreign key error\n */\n formatForeignKeyError(error: ForeignKeyErrorInfo): string {\n if (this.verbose) {\n return this.formatForeignKeyErrorVerbose(error);\n }\n return this.formatForeignKeyErrorCompact(error);\n }\n\n /**\n * Format compact (default) validation errors\n */\n private formatValidationErrorsCompact(errors: ValidationErrorInfo[]): string {\n const lines: string[] = [];\n\n for (const error of errors) {\n for (const issue of error.issues) {\n const fieldPath = this.getFieldPath(issue);\n const line = `${error.file}:${error.rowIndex + 1} • ${fieldPath}: ${issue.message}`;\n lines.push(line);\n }\n }\n\n return lines.join('\\n');\n }\n\n /**\n * Format verbose validation errors\n */\n private formatValidationErrorsVerbose(errors: ValidationErrorInfo[]): string {\n const blocks: string[] = [];\n\n for (let i = 0; i < errors.length; i++) {\n const error = errors[i];\n const isLast = i === errors.length - 1;\n const prefix = isLast ? '└─' : '├─';\n const linePrefix = isLast ? ' ' : '│ ';\n\n const lines: string[] = [`${prefix} ${error.file}:${error.rowIndex + 1}`];\n\n for (const issue of error.issues) {\n const fieldPath = this.getFieldPath(issue);\n lines.push(`${linePrefix}Field: ${fieldPath}`);\n lines.push(`${linePrefix}Error: ${issue.message}`);\n }\n\n // Show original data if available (migrate case)\n if (error.originalData !== undefined) {\n lines.push(`${linePrefix}Original data: ${JSON.stringify(error.originalData)}`);\n }\n\n // Show data\n if (error.data !== undefined) {\n const label = error.originalData !== undefined ? 'Transformed data' : 'Data';\n lines.push(`${linePrefix}${label}: ${JSON.stringify(error.data)}`);\n }\n\n blocks.push(lines.join('\\n'));\n }\n\n return blocks.join('\\n│\\n');\n }\n\n /**\n * Format compact foreign key error\n */\n private formatForeignKeyErrorCompact(error: ForeignKeyErrorInfo): string {\n return `${error.file}:${error.rowIndex + 1} • ${error.column}: Foreign key constraint failed - Referenced value ${JSON.stringify(error.value)} does not exist in ${error.referencedTable}(${error.referencedColumn})`;\n }\n\n /**\n * Format verbose foreign key error\n */\n private formatForeignKeyErrorVerbose(error: ForeignKeyErrorInfo): string {\n const lines: string[] = [\n `└─ ${error.file}:${error.rowIndex + 1}`,\n ` Type: Foreign Key Violation`,\n ` Field: ${error.column}`,\n ` Value: ${JSON.stringify(error.value)}`,\n ` References: ${error.referencedTable}(${error.referencedColumn})`,\n ` Error: Referenced value does not exist in target table`,\n ];\n\n if (error.data !== undefined) {\n lines.push(` Data: ${JSON.stringify(error.data)}`);\n }\n\n return lines.join('\\n');\n }\n\n /**\n * Get field path from issue\n */\n private getFieldPath(issue: StandardSchemaIssue): string {\n if (!issue.path || issue.path.length === 0) {\n return 'root';\n }\n\n return issue.path\n .map((segment) => {\n if (typeof segment === 'object' && segment !== null && 'key' in segment) {\n return String(segment.key);\n }\n return String(segment);\n })\n .join('.');\n }\n\n /**\n * Format error header with count\n */\n formatErrorHeader(count: number, file?: string): string {\n const fileInfo = file ? ` in ${file}` : '';\n return styleText('red', `✗ Found ${count} error(s)${fileInfo}`);\n }\n\n /**\n * Format migration failure header\n */\n formatMigrationFailureHeader(): string {\n return styleText('red', '\\n✗ Migration failed and was rolled back');\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["schema"],"sources":["../src/runtime.ts","../src/sqlite-adapter.ts","../src/jsonl-reader.ts","../src/jsonl-writer.ts","../src/schema-extensions.ts","../src/schema-loader.ts","../src/directory-scanner.ts","../src/schema.ts","../src/database.ts","../src/type-generator.ts","../src/jsonl-migration.ts","../src/error-formatter.ts"],"sourcesContent":["/**\n * Runtime detection utilities\n */\n\nexport type RuntimeEnvironment = 'node' | 'unknown';\n\nexport function detectRuntime(): RuntimeEnvironment {\n // Check for Node.js\n if (typeof process !== 'undefined' && process.versions && process.versions.node) {\n return 'node';\n }\n\n return 'unknown';\n}\n\nexport const RUNTIME = detectRuntime();\n","/**\n * SQLite adapter for Node.js\n */\n\nimport { RUNTIME } from './runtime.js';\n\n/**\n * Common interface for SQLite database\n */\nexport interface SQLiteDatabase {\n prepare(sql: string): SQLiteStatement;\n exec(sql: string): void;\n close(): void;\n}\n\nexport interface SQLiteStatement {\n run(...params: any[]): { changes: number; lastInsertRowid: number | bigint };\n get(...params: any[]): any;\n all(...params: any[]): any[];\n}\n\n/**\n * Create a SQLite database instance for Node.js\n */\nexport function createDatabase(path: string = ':memory:'): SQLiteDatabase {\n if (RUNTIME === 'node') {\n return createNodeDatabase(path);\n } else {\n throw new Error(`Unsupported runtime: ${RUNTIME}`);\n }\n}\n\n/**\n * Create a Node.js SQLite database\n */\nfunction createNodeDatabase(path: string): SQLiteDatabase {\n // Dynamic import for Node.js\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const { DatabaseSync } = require('node:sqlite');\n const db = new DatabaseSync(path);\n\n // CRITICAL: Enable foreign key constraints\n // SQLite disables foreign keys by default, which is a major data integrity issue\n db.exec('PRAGMA foreign_keys = ON');\n\n return {\n prepare(sql: string): SQLiteStatement {\n const stmt = db.prepare(sql);\n return {\n run(...params: any[]) {\n return stmt.run(...params);\n },\n get(...params: any[]) {\n return stmt.get(...params);\n },\n all(...params: any[]) {\n return stmt.all(...params);\n },\n };\n },\n exec(sql: string): void {\n db.exec(sql);\n },\n close(): void {\n db.close();\n },\n };\n}\n","import { readFile } from 'node:fs/promises';\nimport { normalize } from 'node:path';\nimport type { JsonObject, ColumnDefinition, TableSchema } from './types.js';\n\nexport class JsonlReader {\n private static overrides: Map<string, JsonObject[]> | null = null;\n\n /**\n * Temporarily override the data returned for specific JSONL files.\n * Useful for scenarios like migration validation where in-memory data should be used.\n */\n static async withOverrides<T>(overrides: Map<string, JsonObject[]>, fn: () => Promise<T>): Promise<T> {\n const normalized = new Map<string, JsonObject[]>();\n for (const [filePath, rows] of overrides) {\n normalized.set(normalize(filePath), rows);\n }\n\n const previousOverrides = this.overrides;\n this.overrides = normalized;\n\n try {\n return await fn();\n } finally {\n this.overrides = previousOverrides;\n }\n }\n\n /**\n * Read JSONL file and parse each line as JSON\n */\n static async read(filePath: string): Promise<JsonObject[]> {\n const overrideRows = this.overrides?.get(normalize(filePath));\n if (overrideRows) {\n // Return clones to avoid accidental mutations from consumers\n return overrideRows.map((row) => JSON.parse(JSON.stringify(row)) as JsonObject);\n }\n\n const content = await readFile(filePath, 'utf-8');\n const lines = content.trim().split('\\n');\n\n return lines\n .filter((line) => line.trim().length > 0)\n .map((line) => {\n try {\n return JSON.parse(line) as JsonObject;\n } catch (error) {\n throw new Error(`Failed to parse JSON line: ${line}`, { cause: error });\n }\n });\n }\n\n /**\n * Infer schema from JSONL data\n */\n static inferSchema(tableName: string, data: JsonObject[]): TableSchema {\n if (data.length === 0) {\n throw new Error('Cannot infer schema from empty data');\n }\n\n const columnTypes = new Map<string, Set<string>>();\n const booleanColumns = new Set<string>();\n const nonBooleanColumns = new Set<string>();\n\n // Collect all column names and their types\n for (const row of data) {\n for (const [key, value] of Object.entries(row)) {\n if (!columnTypes.has(key)) {\n columnTypes.set(key, new Set());\n }\n columnTypes.get(key)!.add(this.inferType(value));\n\n if (typeof value === 'boolean') {\n booleanColumns.add(key);\n } else if (value !== null) {\n nonBooleanColumns.add(key);\n }\n }\n }\n\n // Convert to column definitions\n const columns: ColumnDefinition[] = [];\n for (const [columnName, types] of columnTypes.entries()) {\n const typeArray = Array.from(types);\n\n // If multiple types exist, prefer TEXT as a safe fallback\n let sqlType: ColumnDefinition['type'] = 'TEXT';\n\n if (typeArray.length === 1) {\n sqlType = typeArray[0] as ColumnDefinition['type'];\n } else if (typeArray.every((t) => t === 'INTEGER' || t === 'REAL')) {\n sqlType = 'REAL'; // Use REAL if we have mixed numeric types\n } else if (!typeArray.includes('NULL')) {\n // If there are multiple non-null types, use TEXT\n sqlType = 'TEXT';\n } else if (typeArray.length === 2 && typeArray.includes('NULL')) {\n // If one type + NULL, use the non-null type\n sqlType = typeArray.find((t) => t !== 'NULL') as ColumnDefinition['type'];\n }\n\n const isBooleanColumn = booleanColumns.has(columnName) && !nonBooleanColumns.has(columnName);\n\n columns.push({\n name: columnName,\n type: sqlType,\n notNull: !typeArray.includes('NULL'),\n valueType: isBooleanColumn ? 'boolean' : undefined,\n });\n }\n\n // If there's an 'id' column, make it primary key\n const idColumn = columns.find((col) => col.name === 'id');\n if (idColumn) {\n idColumn.primaryKey = true;\n }\n\n return {\n name: tableName,\n columns,\n };\n }\n\n private static inferType(value: unknown): string {\n if (value === null || value === undefined) return 'NULL';\n if (typeof value === 'number') {\n return Number.isInteger(value) ? 'INTEGER' : 'REAL';\n }\n if (typeof value === 'string') return 'TEXT';\n if (typeof value === 'boolean') return 'INTEGER'; // SQLite stores booleans as integers\n if (typeof value === 'object') return 'JSON'; // Store objects/arrays as JSON\n return 'TEXT';\n }\n}\n","import { writeFile } from 'node:fs/promises';\nimport type { JsonObject } from './types.js';\n\nexport class JsonlWriter {\n /**\n * Write data to JSONL file\n */\n static async write(filePath: string, data: JsonObject[]): Promise<void> {\n const lines = data.map((obj) => JSON.stringify(obj)).join('\\n');\n await writeFile(filePath, lines + '\\n', 'utf-8');\n }\n\n /**\n * Append data to JSONL file\n */\n static async append(filePath: string, data: JsonObject[]): Promise<void> {\n const { readFile, writeFile } = await import('node:fs/promises');\n\n try {\n const existing = await readFile(filePath, 'utf-8');\n const lines = data.map((obj) => JSON.stringify(obj)).join('\\n');\n const newContent = existing.trim() + '\\n' + lines + '\\n';\n await writeFile(filePath, newContent, 'utf-8');\n } catch (error) {\n // If file doesn't exist, just write the data\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n await this.write(filePath, data);\n } else {\n throw error;\n }\n }\n }\n}\n","import { access } from 'node:fs/promises';\nimport { join } from 'node:path';\n\n/**\n * Supported schema file extensions, in priority order.\n * The first match wins when discovering schema files.\n */\nexport const SCHEMA_EXTENSIONS = ['.schema.ts', '.schema.mts', '.schema.cts'] as const;\nexport type SchemaExtension = (typeof SCHEMA_EXTENSIONS)[number];\n\n/**\n * Map from schema extensions to their JavaScript import counterparts.\n */\nconst SCHEMA_TO_JS_IMPORT_MAP: Record<string, string> = {\n '.schema.ts': '.schema.js',\n '.schema.mts': '.schema.mjs',\n '.schema.cts': '.schema.cjs',\n};\n\n/**\n * Try each supported schema extension and return the full path of the first\n * one that exists on disk. Returns undefined if none is found.\n */\nexport async function findSchemaFile(dir: string, tableName: string): Promise<string | undefined> {\n for (const ext of SCHEMA_EXTENSIONS) {\n const candidate = join(dir, `${tableName}${ext}`);\n try {\n await access(candidate);\n return candidate;\n } catch {\n // Continue to next extension\n }\n }\n return undefined;\n}\n\n/**\n * Synchronously find a schema file among directory entries.\n * Returns the full path of the first match, or undefined.\n */\nexport function findSchemaFileInEntries(\n dataDirPath: string,\n tableName: string,\n entries: { isFile(): boolean; name: string }[],\n): string | undefined {\n for (const ext of SCHEMA_EXTENSIONS) {\n const candidateName = `${tableName}${ext}`;\n if (entries.some((e) => e.isFile() && e.name === candidateName)) {\n return join(dataDirPath, candidateName);\n }\n }\n return undefined;\n}\n\n/**\n * Check if a filename matches any supported schema file pattern.\n */\nexport function isSchemaFile(fileName: string): boolean {\n return SCHEMA_EXTENSIONS.some((ext) => fileName.endsWith(ext));\n}\n\n/**\n * Extract table name from a schema filename.\n * e.g., \"users.schema.ts\" -> \"users\", \"users.schema.mts\" -> \"users\"\n */\nexport function extractTableNameFromSchemaFile(fileName: string): string | null {\n for (const ext of SCHEMA_EXTENSIONS) {\n if (fileName.endsWith(ext)) {\n return fileName.slice(0, -ext.length);\n }\n }\n return null;\n}\n\n/**\n * Rewrite a TypeScript path to its JavaScript counterpart for ESM imports.\n * \".schema.ts\" -> \".schema.js\", \".schema.mts\" -> \".schema.mjs\", \".schema.cts\" -> \".schema.cjs\"\n */\nexport function rewriteExtensionForImport(filePath: string): string {\n for (const [tsExt, jsExt] of Object.entries(SCHEMA_TO_JS_IMPORT_MAP)) {\n if (filePath.endsWith(tsExt)) {\n return filePath.slice(0, -tsExt.length) + jsExt;\n }\n }\n return filePath;\n}\n","import { pathToFileURL } from 'node:url';\nimport { dirname, basename } from 'node:path';\nimport type { StandardSchema } from './types.js';\nimport { findSchemaFile, SCHEMA_EXTENSIONS } from './schema-extensions.js';\n\nexport class SchemaLoader {\n /**\n * Check if a schema file exists for a table\n */\n static async hasSchema(jsonlPath: string): Promise<boolean> {\n const dir = dirname(jsonlPath);\n const tableName = basename(jsonlPath, '.jsonl');\n const schemaPath = await findSchemaFile(dir, tableName);\n return schemaPath !== undefined;\n }\n\n /**\n * Load a validation schema file for a table\n * Requires ${tableName}.schema.{ts,mts,cts} to exist alongside the JSONL file\n */\n static async loadSchema(jsonlPath: string): Promise<StandardSchema> {\n const dir = dirname(jsonlPath);\n const tableName = basename(jsonlPath, '.jsonl');\n const schemaPath = await findSchemaFile(dir, tableName);\n\n if (!schemaPath) {\n throw new Error(\n `Schema file not found for table '${tableName}'. Expected one of: ${SCHEMA_EXTENSIONS.map((ext) => `${tableName}${ext}`).join(', ')}`,\n );\n }\n\n try {\n const schemaUrl = pathToFileURL(schemaPath).href;\n // Add cache busting query parameter to force reload on each import\n // This ensures schema changes are picked up immediately\n const cacheBustedUrl = `${schemaUrl}?t=${Date.now()}`;\n const module = await import(cacheBustedUrl);\n const schema = module.default || module.schema;\n\n if (schema && this.isStandardSchema(schema)) {\n return schema;\n }\n\n throw new Error(`Schema file ${schemaPath} does not export a valid StandardSchema`);\n } catch (error) {\n throw new Error(\n `Failed to load schema for table '${tableName}' from ${schemaPath}: ${error instanceof Error ? error.message : String(error)}`,\n { cause: error instanceof Error ? error : undefined },\n );\n }\n }\n\n /**\n * Check if an object implements the StandardSchema interface\n */\n private static isStandardSchema(obj: unknown): obj is StandardSchema {\n if (!obj || typeof obj !== 'object') return false;\n\n const schema = obj as Record<string, unknown>;\n const standard = schema['~standard'];\n\n if (!standard || typeof standard !== 'object') return false;\n\n const standardObj = standard as Record<string, unknown>;\n\n return (\n standardObj.version === 1 && typeof standardObj.vendor === 'string' && typeof standardObj.validate === 'function'\n );\n }\n}\n","import { readdir } from 'node:fs/promises';\nimport { join, basename, extname } from 'node:path';\nimport type { TableConfig } from './types.js';\n\nexport class DirectoryScanner {\n /**\n * Scan directory for JSONL files and create table configurations\n */\n static async scanDirectory(dataDir: string): Promise<Map<string, TableConfig>> {\n const tables = new Map<string, TableConfig>();\n\n try {\n const files = await readdir(dataDir);\n\n for (const file of files) {\n if (extname(file) === '.jsonl') {\n const tableName = basename(file, '.jsonl');\n const jsonlPath = join(dataDir, file);\n\n tables.set(tableName, {\n jsonlPath,\n autoInferSchema: true,\n });\n }\n }\n\n if (tables.size === 0) {\n console.warn(`Warning: No JSONL files found in directory: ${dataDir}`);\n }\n\n return tables;\n } catch (error) {\n throw new Error(`Failed to scan directory ${dataDir}: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n}\n","import type { StandardSchema, Table, ForeignKeyDefinition, IndexDefinition } from './types.js';\n\n/**\n * Schema options for defining constraints and indexes\n * When Input and Output types differ, backward transformation is required\n */\nexport type SchemaOptions<Input extends Table, Output extends Table> = {\n /**\n * Primary key column\n */\n primaryKey?: string;\n\n /**\n * Foreign key constraints\n */\n foreignKeys?: ForeignKeyDefinition[];\n\n /**\n * Indexes to create\n */\n indexes?: IndexDefinition[];\n} & (Output extends Input\n ? {\n /**\n * Backward transformation from Output to Input (optional when output is substitutable for input)\n */\n backward?: (output: Output) => Input;\n }\n : {\n /**\n * Backward transformation from Output to Input (REQUIRED when types differ)\n */\n backward: (output: Output) => Input;\n });\n\n/**\n * BiDirectional Schema interface\n * Extends StandardSchema with optional backward transformation and schema metadata\n */\nexport interface BiDirectionalSchema<Input extends Table = Table, Output extends Table = Input> extends StandardSchema<\n Input,\n Output\n> {\n /**\n * Backward transformation from Output to Input\n * Required when Input and Output types differ (e.g., with transformations)\n */\n backward?: (output: Output) => Input;\n\n /**\n * Primary key column\n */\n primaryKey?: string;\n\n /**\n * Foreign key constraints\n */\n foreignKeys?: ForeignKeyDefinition[];\n\n /**\n * Indexes to create\n */\n indexes?: IndexDefinition[];\n}\n\n/**\n * Define a bidirectional schema with optional backward transformation\n *\n * @param schema - Standard Schema for validation\n * @param options - SchemaOptions object. When Input and Output types differ, backward transformation is required\n *\n * @example\n * // No transformation - backward not needed\n * const schema = defineSchema(\n * v.object({ id: v.number(), name: v.string() })\n * );\n *\n * @example\n * // With transformation - backward REQUIRED\n * const schema = defineSchema(\n * v.pipe(v.string(), v.transform(Number)),\n * {\n * backward: (num) => String(num) // backward: number → string (REQUIRED)\n * }\n * );\n *\n * @example\n * // With primary key and foreign key\n * const schema = defineSchema(\n * v.object({ id: v.number(), customerId: v.number() }),\n * {\n * primaryKey: 'id',\n * foreignKeys: [\n * { column: 'customerId', references: { table: 'users', column: 'id' } }\n * ]\n * }\n * );\n */\nexport function defineSchema<Input extends Table, Output extends Table>(\n schema: StandardSchema<Input, Output>,\n ...args: Output extends Input ? [options?: SchemaOptions<Input, Output>] : [options: SchemaOptions<Input, Output>]\n): BiDirectionalSchema<Input, Output> {\n const options = args[0];\n // Create a new object that extends the schema\n const bidirectionalSchema = Object.create(schema) as BiDirectionalSchema<Input, Output>;\n\n // Handle options object\n if (options) {\n if (options.backward) {\n bidirectionalSchema.backward = options.backward as (output: Output) => Input;\n }\n if (options.primaryKey) {\n bidirectionalSchema.primaryKey = options.primaryKey;\n }\n if (options.foreignKeys) {\n bidirectionalSchema.foreignKeys = options.foreignKeys;\n }\n if (options.indexes) {\n bidirectionalSchema.indexes = options.indexes;\n }\n }\n\n // Copy '~standard' property\n Object.defineProperty(bidirectionalSchema, '~standard', {\n value: schema['~standard'],\n enumerable: true,\n configurable: true,\n });\n\n return bidirectionalSchema;\n}\n\n/**\n * Check if a schema has backward transformation\n */\nexport function hasBackward<Input extends Table, Output extends Table>(\n schema: StandardSchema<Input, Output>,\n): schema is BiDirectionalSchema<Input, Output> {\n return 'backward' in schema && typeof (schema as { backward?: unknown }).backward === 'function';\n}\n","import { createDatabase, type SQLiteDatabase } from './sqlite-adapter.js';\nimport { JsonlReader } from './jsonl-reader.js';\nimport { JsonlWriter } from './jsonl-writer.js';\nimport { SchemaLoader } from './schema-loader.js';\nimport { DirectoryScanner } from './directory-scanner.js';\nimport { hasBackward } from './schema.js';\nimport { findSchemaFile } from './schema-extensions.js';\nimport { dirname, basename } from 'node:path';\nimport type {\n DatabaseConfig,\n TableSchema,\n JsonObject,\n TableConfig,\n StandardSchema,\n ValidationError,\n Table,\n TableDefs,\n WhereCondition,\n ValidationResult,\n ValidationErrorDetail,\n TableValidationResult,\n ForeignKeyDefinition,\n} from './types.js';\nimport type { BiDirectionalSchema } from './schema.js';\n\nexport class LinesDB<Tables extends TableDefs> {\n private db: SQLiteDatabase;\n private config: DatabaseConfig<Tables>;\n private schemas: Map<string, TableSchema> = new Map();\n private validationSchemas: Map<string, StandardSchema | undefined> = new Map();\n private tables: Map<string, TableConfig> = new Map();\n private inTransaction: boolean = false;\n\n private constructor(config: DatabaseConfig<Tables>, dbPath?: string) {\n this.config = config;\n this.db = createDatabase(dbPath ?? ':memory:');\n }\n\n static create<Tables extends TableDefs>(config: DatabaseConfig<Tables>, dbPath?: string): LinesDB<Tables> {\n return new LinesDB<Tables>(config, dbPath);\n }\n\n /**\n * Initialize database by loading all JSONL files or a specific table\n * Uses dependency resolution to ensure foreign key references are loaded in correct order\n * @param options Optional configuration for initialization\n * @param options.tableName Optional table name to initialize. If not provided, initializes all tables\n * @param options.detailedValidate If true, performs detailed validation by inserting rows one by one to catch constraint violations\n * @param options.transform Optional transform function to apply to rows before validation (only applied to the specified tableName)\n * @returns ValidationResult containing validation status, errors, and warnings\n */\n async initialize(options?: {\n tableName?: string;\n detailedValidate?: boolean;\n transform?: (row: JsonObject) => JsonObject;\n }): Promise<ValidationResult> {\n const allErrors: ValidationErrorDetail[] = [];\n const allWarnings: string[] = [];\n const allRowCounts = new Map<string, number>();\n const tableName = options?.tableName;\n const detailedValidate = options?.detailedValidate ?? false;\n const transform = options?.transform;\n\n // Scan directory for JSONL files\n this.tables = await DirectoryScanner.scanDirectory(this.config.dataDir);\n\n // Determine which tables to load\n const tablesToLoad = tableName ? [tableName] : Array.from(this.tables.keys());\n\n // Validate that all requested tables exist BEFORE starting to load\n for (const tableNameToLoad of tablesToLoad) {\n if (!this.tables.has(tableNameToLoad)) {\n throw new Error(`Table '${tableNameToLoad}' not found in directory '${this.config.dataDir}'`);\n }\n }\n\n // Track loaded tables and tables currently being loaded (for circular dependency detection)\n const loadedTables = new Set<string>();\n const loadingTables = new Set<string>();\n const attemptedTables = new Set<string>(); // Track all attempted tables (loaded or not)\n const allDeferredForeignKeys: Array<{\n tableName: string;\n foreignKey: ForeignKeyDefinition;\n filePath: string;\n }> = [];\n\n // Load tables with dependency resolution\n for (const tableNameToLoad of tablesToLoad) {\n if (!attemptedTables.has(tableNameToLoad)) {\n // Only apply transform to the specified table\n const tableTransform = tableNameToLoad === tableName ? transform : undefined;\n const {\n errors,\n warnings,\n rowCounts: tableRowCounts,\n deferredForeignKeys,\n } = await this.loadTableWithDependencies(\n tableNameToLoad,\n loadedTables,\n loadingTables,\n attemptedTables,\n detailedValidate,\n tableTransform,\n );\n allErrors.push(...errors);\n allWarnings.push(...warnings);\n allDeferredForeignKeys.push(...deferredForeignKeys);\n for (const [k, v] of tableRowCounts) {\n allRowCounts.set(k, v);\n }\n }\n }\n\n // Validate deferred foreign keys (from circular dependencies) now that all tables are loaded\n if (detailedValidate && allDeferredForeignKeys.length > 0) {\n for (const { tableName: tName, foreignKey: fk, filePath } of allDeferredForeignKeys) {\n // Only validate if the referenced table was actually loaded\n if (!loadedTables.has(fk.references.table)) {\n continue;\n }\n const deferredErrors = this.validateDeferredForeignKey(tName, fk, filePath);\n allErrors.push(...deferredErrors);\n }\n }\n\n // Build per-table results\n const tableResults: TableValidationResult[] = tablesToLoad.map((name) => {\n const tableErrors = allErrors.filter((e) => e.tableName === name);\n const tableWarnings = allWarnings.filter((w) => w.includes(`'${name}'`));\n return {\n tableName: name,\n valid: tableErrors.length === 0,\n rowCount: allRowCounts.get(name) ?? 0,\n errors: tableErrors,\n warnings: tableWarnings,\n };\n });\n\n return {\n valid: allErrors.length === 0,\n errors: allErrors,\n warnings: allWarnings,\n tableResults,\n };\n }\n\n /**\n * Load a table and its dependencies recursively\n */\n private async loadTableWithDependencies(\n tableName: string,\n loadedTables: Set<string>,\n loadingTables: Set<string>,\n attemptedTables: Set<string>,\n detailedValidate: boolean,\n transform?: (row: JsonObject) => JsonObject,\n ): Promise<{\n errors: ValidationErrorDetail[];\n warnings: string[];\n rowCounts: Map<string, number>;\n deferredForeignKeys: Array<{\n tableName: string;\n foreignKey: ForeignKeyDefinition;\n filePath: string;\n }>;\n }> {\n const errors: ValidationErrorDetail[] = [];\n const warnings: string[] = [];\n const rowCounts = new Map<string, number>();\n const deferredForeignKeys: Array<{\n tableName: string;\n foreignKey: ForeignKeyDefinition;\n filePath: string;\n }> = [];\n\n // Skip if already attempted (loaded or not)\n if (attemptedTables.has(tableName)) {\n return { errors, warnings, rowCounts, deferredForeignKeys };\n }\n\n // Mark as attempted\n attemptedTables.add(tableName);\n\n // Check for circular dependencies\n if (loadingTables.has(tableName)) {\n throw new Error(`Circular dependency detected for table '${tableName}'`);\n }\n\n // Get table config\n const tableConfig = this.tables.get(tableName);\n if (!tableConfig) {\n throw new Error(`Table configuration not found for '${tableName}'`);\n }\n\n // Mark as currently loading\n loadingTables.add(tableName);\n\n try {\n // Load schema module to check for foreign key dependencies\n // We need to load the entire module to access foreignKeys export\n let foreignKeys: BiDirectionalSchema['foreignKeys'];\n\n try {\n const { pathToFileURL } = await import('node:url');\n const schemaPath = await findSchemaFile(\n dirname(tableConfig.jsonlPath),\n basename(tableConfig.jsonlPath, '.jsonl'),\n );\n if (schemaPath) {\n const schemaUrl = pathToFileURL(schemaPath).href;\n const schemaModule = await import(`${schemaUrl}?t=${Date.now()}`);\n\n // Try to get foreign keys from exported 'schema' or directly from module\n const schemaExport = schemaModule.schema || schemaModule.default;\n foreignKeys = schemaExport?.foreignKeys || schemaModule.foreignKeys;\n }\n } catch {\n // Schema file not found - will continue without validation\n }\n\n // If there are foreign key dependencies, load them first\n if (foreignKeys && foreignKeys.length > 0) {\n for (const fk of foreignKeys) {\n const referencedTable = fk.references.table;\n\n // Skip self-referencing foreign keys (e.g., nullable parent_id columns)\n if (referencedTable === tableName) {\n continue;\n }\n\n if (!attemptedTables.has(referencedTable)) {\n // Check if referenced table exists in our tables map\n if (this.tables.has(referencedTable)) {\n // Dependencies should not have transform applied\n const depResult = await this.loadTableWithDependencies(\n referencedTable,\n loadedTables,\n loadingTables,\n attemptedTables,\n detailedValidate,\n undefined,\n );\n errors.push(...depResult.errors);\n warnings.push(...depResult.warnings);\n deferredForeignKeys.push(...depResult.deferredForeignKeys);\n for (const [k, v] of depResult.rowCounts) {\n rowCounts.set(k, v);\n }\n } else {\n throw new Error(\n `Foreign key reference to non-existent table '${referencedTable}' in table '${tableName}'`,\n );\n }\n }\n }\n }\n\n // Determine which FK dependencies failed or are circular (attempted but not loaded)\n const failedDependencies = new Set<string>();\n const circularDependencies = new Set<string>();\n if (foreignKeys && foreignKeys.length > 0) {\n for (const fk of foreignKeys) {\n const referencedTable = fk.references.table;\n if (referencedTable === tableName) continue;\n if (attemptedTables.has(referencedTable) && !loadedTables.has(referencedTable)) {\n if (loadingTables.has(referencedTable)) {\n // Circular dependency: table is currently being loaded\n circularDependencies.add(referencedTable);\n } else {\n // Actual failure: table attempted but not loaded\n failedDependencies.add(referencedTable);\n }\n }\n }\n if (failedDependencies.size > 0) {\n for (const dep of failedDependencies) {\n warnings.push(\n `Skipping foreign key validation for table '${tableName}': referenced table '${dep}' has validation errors`,\n );\n }\n }\n }\n\n // Combine failed and circular dependencies for table loading (both need FK skipping)\n const allSkippedDependencies = new Set([...failedDependencies, ...circularDependencies]);\n\n // Now load this table\n const {\n loaded,\n rowCount,\n errors: loadErrors,\n } = await this.loadTable(tableName, tableConfig, detailedValidate, transform, allSkippedDependencies);\n errors.push(...loadErrors);\n rowCounts.set(tableName, rowCount);\n\n if (loaded) {\n loadedTables.add(tableName);\n\n // Track circular dependency FKs for deferred validation\n if (foreignKeys && circularDependencies.size > 0) {\n for (const fk of foreignKeys) {\n if (circularDependencies.has(fk.references.table)) {\n deferredForeignKeys.push({\n tableName,\n foreignKey: fk,\n filePath: tableConfig.jsonlPath,\n });\n }\n }\n }\n } else {\n // Table was not loaded (e.g., empty data)\n warnings.push(`Table '${tableName}' was not loaded (no data or skipped)`);\n this.tables.delete(tableName);\n }\n } finally {\n // Remove from loading set\n loadingTables.delete(tableName);\n }\n\n return { errors, warnings, rowCounts, deferredForeignKeys };\n }\n\n /**\n * Load a single table from JSONL file\n * @returns Object with loaded status and validation errors\n */\n private async loadTable(\n tableName: string,\n config: TableConfig,\n detailedValidate: boolean,\n transform?: (row: JsonObject) => JsonObject,\n failedDependencies?: Set<string>,\n ): Promise<{ loaded: boolean; rowCount: number; errors: ValidationErrorDetail[] }> {\n // Read JSONL file\n let data = await JsonlReader.read(config.jsonlPath);\n\n // Apply transform if provided (before validation)\n if (transform) {\n data = data.map((row) => transform(row));\n }\n\n // Load validation schema if provided or try to auto-load\n let validationSchema = config.validationSchema;\n const schemaMetadata: {\n primaryKey?: string;\n foreignKeys?: BiDirectionalSchema['foreignKeys'];\n indexes?: BiDirectionalSchema['indexes'];\n } = {};\n\n if (!validationSchema) {\n try {\n validationSchema = await SchemaLoader.loadSchema(config.jsonlPath);\n } catch (_error) {\n // Schema file not found or failed to load - this is OK, table can still be used without validation\n }\n }\n\n // Load schema metadata (foreignKeys, primaryKey, indexes) from schema module\n // SchemaLoader.loadSchema() only returns the validation schema object, not metadata\n if (!config.validationSchema) {\n // Only load if not already provided via config\n try {\n const { pathToFileURL } = await import('node:url');\n const schemaPath = await findSchemaFile(dirname(config.jsonlPath), basename(config.jsonlPath, '.jsonl'));\n if (!schemaPath) throw new Error('Schema file not found');\n const schemaUrl = pathToFileURL(schemaPath).href;\n const schemaModule = await import(`${schemaUrl}?t=${Date.now()}`);\n\n // Try to get metadata from exported 'schema' or directly from module\n const schemaExport = schemaModule.schema || schemaModule.default;\n\n if (schemaExport?.primaryKey) {\n schemaMetadata.primaryKey = schemaExport.primaryKey;\n } else if (schemaModule.primaryKey) {\n schemaMetadata.primaryKey = schemaModule.primaryKey;\n }\n\n if (schemaExport?.foreignKeys) {\n schemaMetadata.foreignKeys = schemaExport.foreignKeys;\n } else if (schemaModule.foreignKeys) {\n schemaMetadata.foreignKeys = schemaModule.foreignKeys;\n }\n\n if (schemaExport?.indexes) {\n schemaMetadata.indexes = schemaExport.indexes;\n } else if (schemaModule.indexes) {\n schemaMetadata.indexes = schemaModule.indexes;\n }\n\n // Debug: log loaded metadata\n if (process.env.DEBUG_LINES_DB) {\n console.log(`[lines-db] Schema metadata for ${tableName}:`);\n console.log(` primaryKey: ${schemaMetadata.primaryKey}`);\n console.log(` foreignKeys: ${JSON.stringify(schemaMetadata.foreignKeys)}`);\n console.log(` indexes: ${JSON.stringify(schemaMetadata.indexes)}`);\n }\n } catch (_error) {\n // Schema file not found - this is OK\n // Debug: log error for investigation\n if (process.env.DEBUG_LINES_DB) {\n console.warn(\n `[lines-db] Failed to load schema metadata for ${tableName}:`,\n _error instanceof Error ? _error.message : String(_error),\n );\n }\n }\n }\n\n this.validationSchemas.set(tableName, validationSchema);\n\n // Validate data first and collect validated (transformed) data\n const validationErrors: Array<{\n rowIndex: number;\n rowData: JsonObject;\n error: ValidationError;\n }> = [];\n const validatedData: JsonObject[] = [];\n\n for (let rowIndex = 0; rowIndex < data.length; rowIndex++) {\n const row = data[rowIndex];\n try {\n const validatedRow = this.validateAndTransform(tableName, row);\n validatedData.push(validatedRow);\n } catch (error) {\n if (error instanceof Error && error.name === 'ValidationError') {\n validationErrors.push({\n rowIndex,\n rowData: row,\n error: error as ValidationError,\n });\n } else {\n throw error;\n }\n }\n }\n\n // Convert validation errors to ValidationErrorDetail format\n const validationErrorDetails: ValidationErrorDetail[] = validationErrors.map((ve) => ({\n file: config.jsonlPath,\n tableName,\n rowIndex: ve.rowIndex,\n issues: ve.error.issues,\n type: 'schema' as const,\n }));\n\n if (validationErrors.length > 0) {\n // Return errors instead of throwing\n return { loaded: false, rowCount: data.length, errors: validationErrorDetails };\n }\n\n // Determine schema - infer from validated data if auto-inference is enabled\n let schema: TableSchema;\n let inferredSchema: TableSchema | undefined;\n\n // Always infer schema from validated data to capture valueType information (e.g., boolean)\n if (validatedData.length > 0) {\n inferredSchema = JsonlReader.inferSchema(tableName, validatedData);\n }\n\n if (config.schema) {\n schema = config.schema;\n // Merge valueType information from inferred schema\n if (inferredSchema) {\n for (const inferredCol of inferredSchema.columns) {\n const schemaCol = schema.columns.find((c) => c.name === inferredCol.name);\n if (schemaCol && inferredCol.valueType && !schemaCol.valueType) {\n schemaCol.valueType = inferredCol.valueType;\n }\n }\n }\n } else if (config.autoInferSchema !== false) {\n if (validatedData.length === 0) {\n return { loaded: false, rowCount: 0, errors: [] };\n }\n // Use inferred schema\n schema = inferredSchema!;\n } else {\n // Critical error - throw exception\n throw new Error(`No schema provided for table ${tableName} and autoInferSchema is disabled`);\n }\n\n // Enhance schema with constraints from validation schema and schema metadata\n // Priority: config.validationSchema (as BiDirectionalSchema) > schemaMetadata\n const biSchema = validationSchema as BiDirectionalSchema;\n const primaryKey = biSchema?.primaryKey || schemaMetadata.primaryKey;\n const foreignKeys = biSchema?.foreignKeys || schemaMetadata.foreignKeys;\n const indexes = biSchema?.indexes || schemaMetadata.indexes;\n\n if (primaryKey && !schema.columns.some((col) => col.primaryKey)) {\n // Add primary key constraint to column\n const col = schema.columns.find((c) => c.name === primaryKey);\n if (col) {\n col.primaryKey = true;\n }\n } else if (!primaryKey && !schema.columns.some((col) => col.primaryKey)) {\n // If no primary key is defined, use 'id' column as primary key if it exists\n // This matches the behavior of JsonlReader.inferSchema()\n const idColumn = schema.columns.find((c) => c.name === 'id');\n if (idColumn) {\n idColumn.primaryKey = true;\n }\n }\n if (foreignKeys) {\n schema.foreignKeys =\n failedDependencies && failedDependencies.size > 0\n ? foreignKeys.filter((fk) => !failedDependencies.has(fk.references.table))\n : foreignKeys;\n }\n if (indexes) {\n schema.indexes = indexes;\n\n // Apply unique constraint from single-column unique indexes to column definitions\n // This is required for foreign key references, as SQLite requires the referenced column\n // to have a UNIQUE constraint in the table definition (not just an index)\n for (const index of indexes) {\n if (index.unique && index.columns.length === 1) {\n const col = schema.columns.find((c) => c.name === index.columns[0]);\n if (col && !col.unique && !col.primaryKey) {\n col.unique = true;\n }\n }\n }\n }\n\n this.schemas.set(tableName, schema);\n\n // Create table\n this.createTable(schema);\n\n // Insert validated data (with detailed validation if requested)\n if (detailedValidate) {\n const insertErrors = this.insertDataWithDetailedValidation(tableName, schema, validatedData, config.jsonlPath);\n if (insertErrors.length > 0) {\n return { loaded: false, rowCount: data.length, errors: insertErrors };\n }\n } else {\n this.insertData(tableName, schema, validatedData);\n }\n\n return { loaded: true, rowCount: data.length, errors: [] };\n }\n\n /**\n * Create table in SQLite with constraints and indexes\n */\n private createTable(schema: TableSchema): void {\n // Note: Foreign key constraints are enabled at database connection level (see sqlite-adapter.ts)\n // No need to enable them here for each table\n\n // Quote table name to handle special characters\n const quotedTableName = this.quoteTableName(schema.name);\n\n // Build a set of columns that should have UNIQUE constraint\n // This includes columns marked as unique in schema AND single-column unique indexes\n // The latter is required for foreign key references, as SQLite requires the referenced column\n // to have a UNIQUE constraint in the table definition (not just a separately created index)\n const uniqueColumns = new Set<string>();\n for (const col of schema.columns) {\n if (col.unique) {\n uniqueColumns.add(col.name);\n }\n }\n if (schema.indexes) {\n for (const index of schema.indexes) {\n if (index.unique && index.columns.length === 1) {\n uniqueColumns.add(index.columns[0]);\n }\n }\n }\n\n const columnDefs = schema.columns.map((col) => {\n // JSON type is stored as TEXT in SQLite\n const sqlType = col.type === 'JSON' ? 'TEXT' : col.type;\n const parts = [this.quoteIdentifier(col.name), sqlType];\n if (col.primaryKey) parts.push('PRIMARY KEY');\n if (col.notNull) parts.push('NOT NULL');\n if (uniqueColumns.has(col.name) && !col.primaryKey) parts.push('UNIQUE');\n return parts.join(' ');\n });\n\n // Add foreign key constraints\n const foreignKeyDefs: string[] = [];\n if (schema.foreignKeys && schema.foreignKeys.length > 0) {\n for (const fk of schema.foreignKeys) {\n const fkParts = [\n `FOREIGN KEY (${this.quoteIdentifier(fk.column)})`,\n `REFERENCES ${this.quoteTableName(fk.references.table)}(${this.quoteIdentifier(fk.references.column)})`,\n ];\n if (fk.onDelete) {\n fkParts.push(`ON DELETE ${fk.onDelete}`);\n }\n if (fk.onUpdate) {\n fkParts.push(`ON UPDATE ${fk.onUpdate}`);\n }\n foreignKeyDefs.push(fkParts.join(' '));\n }\n }\n\n const allDefs = [...columnDefs, ...foreignKeyDefs];\n const sql = `CREATE TABLE IF NOT EXISTS ${quotedTableName} (${allDefs.join(', ')})`;\n this.db.exec(sql);\n\n // Create indexes\n if (schema.indexes && schema.indexes.length > 0) {\n for (let i = 0; i < schema.indexes.length; i++) {\n const index = schema.indexes[i];\n // Create safe index name by replacing special characters\n const safeTableName = schema.name.replace(/[^a-zA-Z0-9]/g, '_');\n const resolvedIndexName = index.name || `idx_${safeTableName}_${index.columns.join('_')}_${i}`;\n const uniqueKeyword = index.unique ? 'UNIQUE ' : '';\n const indexSql = `CREATE ${uniqueKeyword}INDEX IF NOT EXISTS ${this.quoteIdentifier(resolvedIndexName)} ON ${quotedTableName} (${index.columns\n .map((col) => this.quoteIdentifier(col))\n .join(', ')})`;\n this.db.exec(indexSql);\n }\n }\n }\n\n /**\n * Quote table name to handle special characters in SQL\n */\n private quoteTableName(tableName: string): string {\n return this.quoteIdentifier(tableName);\n }\n\n /**\n * Quote identifier for SQL statements, escaping embedded quotes\n */\n private quoteIdentifier(identifier: string): string {\n return `\"${identifier.replace(/\"/g, '\"\"')}\"`;\n }\n\n /**\n * Insert data into table using batch insert (multiple rows per SQL)\n * SQLite has a parameter limit (default 999), so we batch rows accordingly\n * Throws exception if any constraint violation occurs\n */\n private insertData(tableName: string, schema: TableSchema, data: JsonObject[]): void {\n if (data.length === 0) return;\n\n const columnNames = schema.columns.map((col) => col.name);\n const quotedColumns = columnNames.map((name) => this.quoteIdentifier(name));\n const columnCount = columnNames.length;\n\n // Calculate batch size to stay under SQLite's parameter limit (999)\n // Leave some margin for safety\n const maxBatchSize = Math.floor(900 / columnCount);\n const batchSize = Math.max(1, Math.min(maxBatchSize, 100));\n\n // Process data in batches\n for (let i = 0; i < data.length; i += batchSize) {\n const batch = data.slice(i, i + batchSize);\n const rowPlaceholders = columnNames.map(() => '?').join(', ');\n const valuesPlaceholders = batch.map(() => `(${rowPlaceholders})`).join(', ');\n const sql = `INSERT INTO ${this.quoteTableName(tableName)} (${quotedColumns.join(', ')}) VALUES ${valuesPlaceholders}`;\n\n const values: (string | number | bigint | null | Uint8Array)[] = [];\n for (const row of batch) {\n for (const col of columnNames) {\n values.push(this.normalizeValue(row[col]));\n }\n }\n\n const stmt = this.db.prepare(sql);\n stmt.run(...values);\n }\n }\n\n /**\n * Insert data into table one row at a time with detailed error reporting\n * This is used for validation to catch constraint violations\n */\n private insertDataWithDetailedValidation(\n tableName: string,\n schema: TableSchema,\n data: JsonObject[],\n filePath: string,\n ): ValidationErrorDetail[] {\n const errors: ValidationErrorDetail[] = [];\n const columnNames = schema.columns.map((col) => col.name);\n const quotedColumns = columnNames.map((name) => this.quoteIdentifier(name));\n const placeholders = columnNames.map(() => '?').join(', ');\n const sql = `INSERT INTO ${this.quoteTableName(tableName)} (${quotedColumns.join(', ')}) VALUES (${placeholders})`;\n\n const stmt = this.db.prepare(sql);\n\n for (let rowIndex = 0; rowIndex < data.length; rowIndex++) {\n const row = data[rowIndex];\n try {\n const values = columnNames.map((col) => this.normalizeValue(row[col]));\n stmt.run(...values);\n } catch (error) {\n // Constraint violation occurred - analyze and record details\n const constraintError = this.analyzeConstraintError(\n error,\n filePath,\n tableName,\n rowIndex,\n row,\n schema.foreignKeys || [],\n );\n if (constraintError) {\n errors.push(constraintError);\n }\n }\n }\n\n return errors;\n }\n\n /**\n * Analyze constraint error and extract detailed information\n */\n private analyzeConstraintError(\n error: unknown,\n file: string,\n tableName: string,\n rowIndex: number,\n row: JsonObject,\n foreignKeys: ForeignKeyDefinition[],\n ): ValidationErrorDetail | null {\n const errorMessage = error instanceof Error ? error.message : String(error);\n\n // Foreign key constraint\n if (errorMessage.includes('FOREIGN KEY constraint failed')) {\n // Find which foreign key failed\n for (const fk of foreignKeys) {\n const fkValue = row[fk.column];\n if (fkValue === null || fkValue === undefined) continue;\n\n // Check if referenced value exists\n try {\n const result = this.query(\n `SELECT COUNT(*) as count FROM ${this.quoteIdentifier(fk.references.table)} WHERE ${this.quoteIdentifier(fk.references.column)} = ?`,\n [this.normalizeValue(fkValue)],\n );\n if (result.length > 0 && (result[0] as { count: number }).count === 0) {\n return {\n file,\n tableName,\n rowIndex,\n issues: [],\n type: 'foreignKey',\n foreignKeyError: {\n column: fk.column,\n value: fkValue,\n referencedTable: fk.references.table,\n referencedColumn: fk.references.column,\n },\n };\n }\n } catch (_) {\n // Referenced table doesn't exist yet\n }\n }\n }\n\n // Other constraint errors (primary key, unique, etc.)\n return {\n file,\n tableName,\n rowIndex,\n issues: [\n {\n message: errorMessage,\n path: [],\n },\n ],\n type: 'schema',\n };\n }\n\n /**\n * Validate a deferred foreign key constraint after all tables have been loaded.\n * Used for circular dependency FK validation.\n */\n private validateDeferredForeignKey(\n tableName: string,\n fk: ForeignKeyDefinition,\n filePath: string,\n ): ValidationErrorDetail[] {\n const errors: ValidationErrorDetail[] = [];\n const quotedTable = this.quoteTableName(tableName);\n const quotedColumn = this.quoteIdentifier(fk.column);\n const quotedRefTable = this.quoteTableName(fk.references.table);\n const quotedRefColumn = this.quoteIdentifier(fk.references.column);\n\n // Find rows where the FK value does not exist in the referenced table\n const sql = `SELECT rowid - 1 as idx, ${quotedColumn} as val FROM ${quotedTable} WHERE ${quotedColumn} IS NOT NULL AND ${quotedColumn} NOT IN (SELECT ${quotedRefColumn} FROM ${quotedRefTable})`;\n\n try {\n const rows = this.query<{ idx: number; val: string | number }>(sql);\n for (const row of rows) {\n errors.push({\n file: filePath,\n tableName,\n rowIndex: row.idx,\n issues: [],\n type: 'foreignKey',\n foreignKeyError: {\n column: fk.column,\n value: row.val,\n referencedTable: fk.references.table,\n referencedColumn: fk.references.column,\n },\n });\n }\n } catch (_) {\n // Table might not exist - skip validation\n }\n\n return errors;\n }\n\n /**\n * Execute a raw SQL query\n */\n query<T = unknown>(sql: string, params: (string | number | bigint | null | Uint8Array)[] = []): T[] {\n const stmt = this.db.prepare(sql);\n return stmt.all(...params) as T[];\n }\n\n /**\n * Execute a SQL query that returns a single row\n */\n queryOne<T = unknown>(sql: string, params: (string | number | bigint | null | Uint8Array)[] = []): T | null {\n const stmt = this.db.prepare(sql);\n const result = stmt.get(...params);\n return result === undefined ? null : (result as T);\n }\n\n /**\n * Execute a SQL statement (INSERT, UPDATE, DELETE)\n */\n execute(\n sql: string,\n params: (string | number | bigint | null | Uint8Array)[] = [],\n ): { changes: number | bigint; lastInsertRowid: number | bigint } {\n const stmt = this.db.prepare(sql);\n return stmt.run(...params);\n }\n\n /**\n * Find rows by condition (supports OR/AND with arrays and function filters)\n * If where is not provided, returns all rows\n */\n find<K extends keyof Tables & string>(tableName: K, where?: WhereCondition<Tables[K]>) {\n // If no where condition, return all rows\n if (where === undefined) {\n const rows = this.query(`SELECT * FROM ${this.quoteTableName(tableName)}`);\n return rows.map((row) => this.deserializeRow(tableName, row)) as Tables[K][];\n }\n\n // Handle empty array - should return no results\n if (Array.isArray(where) && where.length === 0) {\n return [];\n }\n\n const { sql, values, functionFilters, hasOrWithFunctionFilters } = this.buildWhereClause(where);\n\n let rows: Tables[K][];\n\n // If OR condition has function filters, get all rows and evaluate in JS\n if (hasOrWithFunctionFilters) {\n const rawRows = this.query(`SELECT * FROM ${this.quoteTableName(tableName)}`);\n rows = rawRows.map((row) => this.deserializeRow(tableName, row)) as Tables[K][];\n return this.applyOrConditionWithFilters(rows, where as WhereCondition<Tables[K]>);\n }\n\n // Normal case: use SQL WHERE clause\n if (sql) {\n const rawRows = this.query(`SELECT * FROM ${this.quoteTableName(tableName)} WHERE ${sql}`, values);\n rows = rawRows.map((row) => this.deserializeRow(tableName, row)) as Tables[K][];\n } else {\n // If only function filters (AND case), get all rows\n const rawRows = this.query(`SELECT * FROM ${this.quoteTableName(tableName)}`);\n rows = rawRows.map((row) => this.deserializeRow(tableName, row)) as Tables[K][];\n }\n\n // Apply function filters for AND conditions\n return this.applyFunctionFilters(rows, functionFilters);\n }\n\n /**\n * Find a single row by condition (supports OR/AND with arrays and function filters)\n */\n findOne<K extends keyof Tables & string>(tableName: K, where: WhereCondition<Tables[K]>) {\n const { sql, values, functionFilters } = this.buildWhereClause(where);\n\n let rows: Tables[K][];\n if (sql) {\n const rawRows = this.query(`SELECT * FROM ${this.quoteTableName(tableName)} WHERE ${sql}`, values);\n rows = rawRows.map((row) => this.deserializeRow(tableName, row)) as Tables[K][];\n } else {\n // If only function filters, get all rows\n const rawRows = this.query(`SELECT * FROM ${this.quoteTableName(tableName)}`);\n rows = rawRows.map((row) => this.deserializeRow(tableName, row)) as Tables[K][];\n }\n\n // Apply function filters and return first match\n const filtered = this.applyFunctionFilters(rows, functionFilters);\n return filtered.length > 0 ? filtered[0] : null;\n }\n\n /**\n * Deserialize JSON columns in a row\n */\n private deserializeRow<T>(tableName: string, row: T): T {\n const schema = this.schemas.get(tableName);\n if (!schema) return row;\n\n const deserializedRow = { ...row } as Record<string, unknown>;\n\n for (const column of schema.columns) {\n const colName = column.name;\n if (!(colName in deserializedRow)) continue;\n\n const value = deserializedRow[colName];\n\n if (column.type === 'JSON' && typeof value === 'string') {\n try {\n deserializedRow[colName] = JSON.parse(value);\n } catch (error) {\n // If parsing fails, keep the original value\n console.warn(`Failed to parse JSON column ${colName}:`, error);\n }\n continue;\n }\n\n if (column.valueType === 'boolean') {\n if (typeof value === 'number') {\n deserializedRow[colName] = value === 0 ? false : true;\n } else if (typeof value === 'bigint') {\n deserializedRow[colName] = value === 0n ? false : true;\n }\n }\n }\n\n return deserializedRow as T;\n }\n\n /**\n * Validate data using StandardSchema and return the transformed value\n * Note: Only synchronous validation is supported\n */\n private validateAndTransform(tableName: string, data: unknown): JsonObject {\n const schema = this.validationSchemas.get(tableName);\n if (!schema) {\n return data as JsonObject;\n }\n\n const result = schema['~standard'].validate(data);\n\n // Only synchronous validation is supported\n if (result instanceof Promise) {\n throw new Error('Asynchronous validation is not supported. Please use synchronous validation schemas.');\n }\n\n if (result.issues && result.issues.length > 0) {\n // Format detailed error message with all validation issues\n const issueMessages = result.issues\n .map((issue) => {\n // Handle path: can be array of PathSegment or undefined\n let pathStr = 'root';\n if (issue.path && issue.path.length > 0) {\n pathStr = issue.path\n .map((segment) => {\n // PathSegment can be { key: PropertyKey } or just PropertyKey\n if (typeof segment === 'object' && segment !== null && 'key' in segment) {\n return String(segment.key);\n }\n return String(segment);\n })\n .join('.');\n }\n return ` - ${pathStr}: ${issue.message}`;\n })\n .join('\\n');\n\n const errorMessage = `Validation failed for table '${tableName}':\\n${issueMessages}`;\n const error = new Error(errorMessage) as ValidationError;\n error.name = 'ValidationError';\n error.issues = result.issues;\n throw error;\n }\n\n // Return the transformed value from validation\n // When there are no issues, result.value should be present\n const transformedValue = ('value' in result ? result.value : data) as JsonObject;\n\n // Convert undefined values to null for JSON compatibility\n const normalizedValue: JsonObject = {};\n for (const [key, value] of Object.entries(transformedValue)) {\n normalizedValue[key] = value === undefined ? null : value;\n }\n\n return normalizedValue;\n }\n\n /**\n * Validate data using StandardSchema (without returning transformed value)\n * Note: Only synchronous validation is supported\n */\n private validateData(tableName: string, data: unknown): void {\n // Use validateAndTransform but discard the result\n this.validateAndTransform(tableName, data);\n }\n\n /**\n * Insert a row into a table with validation\n */\n insert<K extends keyof Tables & string>(\n tableName: K,\n data: Tables[K],\n ): { changes: number | bigint; lastInsertRowid: number | bigint } {\n // Validate if schema exists\n this.validateData(tableName, data);\n\n const schema = this.schemas.get(tableName);\n if (!schema) {\n throw new Error(`Table ${tableName} does not exist`);\n }\n\n const columnNames = Object.keys(data);\n const quotedColumns = columnNames.map((col) => this.quoteIdentifier(col));\n const placeholders = columnNames.map(() => '?').join(', ');\n const sql = `INSERT INTO ${this.quoteTableName(tableName)} (${quotedColumns.join(', ')}) VALUES (${placeholders})`;\n\n const values = Object.values(data).map((v) => this.normalizeValue(v));\n const result = this.execute(sql, values);\n\n // Auto-sync if not in transaction\n if (!this.inTransaction) {\n this.syncTable(tableName).catch((err) => {\n console.error(`Failed to sync table ${tableName}:`, err);\n });\n }\n\n return result;\n }\n\n /**\n * Batch insert rows with validation per record.\n */\n batchInsert<K extends keyof Tables & string>(\n tableName: K,\n records: Tables[K][],\n ): { changes: number | bigint; lastInsertRowid: number | bigint } {\n const schema = this.schemas.get(tableName);\n if (!schema) {\n throw new Error(`Table ${tableName} does not exist`);\n }\n\n if (records.length === 0) {\n return { changes: 0, lastInsertRowid: 0 };\n }\n\n let totalChanges = 0n;\n let lastRowid = 0n;\n\n for (const record of records) {\n this.validateData(tableName, record);\n\n const columnNames = Object.keys(record);\n const quotedColumns = columnNames.map((col) => this.quoteIdentifier(col));\n const placeholders = columnNames.map(() => '?').join(', ');\n const sql = `INSERT INTO ${this.quoteTableName(tableName)} (${quotedColumns.join(', ')}) VALUES (${placeholders})`;\n\n const values = columnNames.map((col) => this.normalizeValue(record[col as keyof Tables[K]]));\n\n const result = this.execute(sql, values);\n totalChanges += BigInt(result.changes);\n lastRowid = BigInt(result.lastInsertRowid);\n }\n\n if (!this.inTransaction) {\n this.syncTable(tableName).catch((err) => {\n console.error(`Failed to sync table ${tableName}:`, err);\n });\n }\n\n return {\n changes: totalChanges,\n lastInsertRowid: lastRowid,\n };\n }\n\n /**\n * Update rows in a table with validation (supports OR/AND with arrays)\n * Note: Function filters are not supported for update operations\n * Note: By default, validation is enabled. For partial updates, existing data is fetched\n * and merged before validation. Set options.validate = false to disable validation.\n */\n update<K extends keyof Tables & string>(\n tableName: K,\n data: Partial<Tables[K]>,\n where: WhereCondition<Tables[K]>,\n options?: { validate?: boolean },\n ): { changes: number | bigint; lastInsertRowid: number | bigint } {\n const schema = this.schemas.get(tableName);\n if (!schema) {\n throw new Error(`Table ${tableName} does not exist`);\n }\n\n // Validate by default (can be disabled with validate: false)\n const shouldValidate = options?.validate !== false;\n const hasValidationSchema = this.validationSchemas.has(tableName);\n\n if (shouldValidate && hasValidationSchema) {\n // Get existing rows to merge with partial data\n const existingRows = this.find(tableName, where);\n\n // Validate each merged row\n for (const existingRow of existingRows) {\n const mergedData = { ...existingRow, ...data };\n this.validateData(tableName, mergedData);\n }\n }\n\n const { sql: whereSql, values: whereValues, functionFilters } = this.buildWhereClause(where);\n\n if (functionFilters.length > 0) {\n throw new Error('Function filters are not supported in update operations');\n }\n\n const setClauses = Object.keys(data)\n .map((key) => `${this.quoteIdentifier(key)} = ?`)\n .join(', ');\n const sql = `UPDATE ${this.quoteTableName(tableName)} SET ${setClauses} WHERE ${whereSql}`;\n\n const values = [...Object.values(data).map((v) => this.normalizeValue(v)), ...whereValues];\n\n const result = this.execute(sql, values);\n\n // Auto-sync if not in transaction\n if (!this.inTransaction) {\n this.syncTable(tableName).catch((err) => {\n console.error(`Failed to sync table ${tableName}:`, err);\n });\n }\n\n return result;\n }\n\n /**\n * Batch update rows with record-specific values and validation.\n * Each record must include the primary key to identify the target row.\n * Validation runs once per merged record unless explicitly disabled.\n */\n batchUpdate<K extends keyof Tables & string>(\n tableName: K,\n records: Array<Partial<Tables[K]> & Record<string, unknown>>,\n options?: { validate?: boolean },\n ): { changes: number | bigint; lastInsertRowid: number | bigint } {\n const schema = this.schemas.get(tableName);\n if (!schema) {\n throw new Error(`Table ${tableName} does not exist`);\n }\n\n if (records.length === 0) {\n return { changes: 0, lastInsertRowid: 0 };\n }\n\n // Get primary key column\n const pkColumn = schema.columns.find((col) => col.primaryKey);\n if (!pkColumn) {\n throw new Error(`Table ${tableName} does not have a primary key`);\n }\n\n const pkName = pkColumn.name;\n\n // Extract primary key values from records\n const pkValues: unknown[] = [];\n for (const record of records) {\n const pkValue = record[pkName];\n if (pkValue === undefined) {\n throw new Error(`Record is missing primary key '${String(pkName)}': ${JSON.stringify(record)}`);\n }\n pkValues.push(pkValue);\n }\n\n // Validate by default (can be disabled with validate: false)\n const shouldValidate = options?.validate !== false;\n const hasValidationSchema = this.validationSchemas.has(tableName);\n\n if (shouldValidate && hasValidationSchema) {\n // Build OR condition to fetch all existing rows at once\n const orCondition = pkValues.map((pkValue) => ({\n [pkName]: pkValue,\n })) as WhereCondition<Tables[K]>;\n\n // Fetch all existing rows in one query\n const existingRows = this.find(tableName, orCondition);\n\n // Create a map for fast lookup: pkValue -> existingRow\n const existingRowsMap = new Map<unknown, Tables[K]>();\n for (const row of existingRows) {\n const pkValue = (row as Record<string, unknown>)[pkName];\n existingRowsMap.set(pkValue, row);\n }\n\n // Validate each merged record and collect all errors\n const validationErrors: Array<{\n rowIndex: number;\n rowData: unknown;\n pkValue: unknown;\n error: ValidationError;\n }> = [];\n\n for (let i = 0; i < records.length; i++) {\n const record = records[i];\n const pkValue = record[pkName];\n const existingRow = existingRowsMap.get(pkValue);\n\n if (!existingRow) {\n throw new Error(`No existing row found with ${String(pkName)}=${JSON.stringify(pkValue)}`);\n }\n\n const mergedData = { ...existingRow, ...record };\n\n try {\n this.validateData(tableName, mergedData);\n } catch (error) {\n // Collect validation errors instead of throwing immediately\n if (error instanceof Error && error.name === 'ValidationError') {\n validationErrors.push({\n rowIndex: i,\n rowData: mergedData,\n pkValue,\n error: error as ValidationError,\n });\n } else {\n throw error;\n }\n }\n }\n\n // If there are validation errors, throw with all error information\n if (validationErrors.length > 0) {\n const enhancedError = new Error(\n `Validation failed for ${validationErrors.length} row(s)`,\n ) as ValidationError & { validationErrors: typeof validationErrors };\n enhancedError.name = 'ValidationError';\n enhancedError.validationErrors = validationErrors;\n // For backward compatibility, include issues from first error\n enhancedError.issues = validationErrors[0].error.issues;\n throw enhancedError;\n }\n }\n\n // All validations passed - perform updates\n let totalChanges = 0n;\n let lastRowid = 0n;\n\n for (const record of records) {\n const pkValue = record[pkName];\n const where = { [pkName]: pkValue } as WhereCondition<Tables[K]>;\n\n // Call update without validation (already validated above)\n const result = this.update(tableName, record as Partial<Tables[K]>, where, {\n validate: false,\n });\n\n totalChanges += BigInt(result.changes);\n lastRowid = BigInt(result.lastInsertRowid);\n }\n\n return {\n changes: totalChanges,\n lastInsertRowid: lastRowid,\n };\n }\n\n /**\n * Delete rows from a table (supports OR/AND with arrays)\n * Note: Function filters are not supported for delete operations\n */\n delete<K extends keyof Tables & string>(\n tableName: K,\n where: WhereCondition<Tables[K]>,\n ): { changes: number | bigint; lastInsertRowid: number | bigint } {\n const schema = this.schemas.get(tableName);\n if (!schema) {\n throw new Error(`Table ${tableName} does not exist`);\n }\n\n const { sql: whereSql, values, functionFilters } = this.buildWhereClause(where);\n\n if (functionFilters.length > 0) {\n throw new Error('Function filters are not supported in delete operations');\n }\n\n const sql = `DELETE FROM ${this.quoteTableName(tableName)} WHERE ${whereSql}`;\n const result = this.execute(sql, values);\n\n // Auto-sync if not in transaction\n if (!this.inTransaction) {\n this.syncTable(tableName).catch((err) => {\n console.error(`Failed to sync table ${tableName}:`, err);\n });\n }\n\n return result;\n }\n\n /**\n * Batch delete rows by primary key.\n */\n batchDelete<K extends keyof Tables & string>(\n tableName: K,\n records: Array<Partial<Tables[K]> & Record<string, unknown>>,\n ): { changes: number | bigint; lastInsertRowid: number | bigint } {\n const schema = this.schemas.get(tableName);\n if (!schema) {\n throw new Error(`Table ${tableName} does not exist`);\n }\n\n if (records.length === 0) {\n return { changes: 0, lastInsertRowid: 0 };\n }\n\n const pkColumn = schema.columns.find((col) => col.primaryKey);\n if (!pkColumn) {\n throw new Error(`Table ${tableName} does not have a primary key`);\n }\n const pkName = pkColumn.name;\n\n const pkValues = records.map((record, index) => {\n const pkValue = record[pkName as keyof Tables[K]];\n if (pkValue === undefined) {\n throw new Error(`Record at index ${index} is missing primary key '${String(pkName)}'`);\n }\n return pkValue;\n });\n\n const placeholders = pkValues.map(() => '?').join(', ');\n const sql = `DELETE FROM ${this.quoteTableName(tableName)} WHERE ${this.quoteIdentifier(pkName)} IN (${placeholders})`;\n const values = pkValues.map((value) => this.normalizeValue(value));\n\n const result = this.execute(sql, values);\n\n if (!this.inTransaction) {\n this.syncTable(tableName).catch((err) => {\n console.error(`Failed to sync table ${tableName}:`, err);\n });\n }\n\n return {\n changes: BigInt(result.changes),\n lastInsertRowid: BigInt(result.lastInsertRowid),\n };\n }\n\n /**\n * Normalize value for SQLite\n */\n private normalizeValue(value: unknown): string | number | bigint | null | Uint8Array {\n if (value === null || value === undefined) return null;\n if (typeof value === 'boolean') return value ? 1 : 0;\n if (typeof value === 'string' || typeof value === 'number' || typeof value === 'bigint') return value;\n if (value instanceof Uint8Array) return value;\n // For objects, convert to JSON string\n return JSON.stringify(value);\n }\n\n /**\n * Build WHERE clause from condition (supports OR/AND with arrays and functions)\n */\n private buildWhereClause<T extends Record<string, unknown>>(\n condition: WhereCondition<T>,\n ): {\n sql: string;\n values: Array<string | number | bigint | null | Uint8Array>;\n functionFilters: Array<{\n key: string;\n fn: (value: unknown) => boolean;\n }>;\n hasOrWithFunctionFilters: boolean;\n } {\n const values: Array<string | number | bigint | null | Uint8Array> = [];\n const functionFilters: Array<{ key: string; fn: (value: unknown) => boolean }> = [];\n let hasOrWithFunctionFilters = false;\n\n const buildCondition = (cond: WhereCondition<T>, isInOr = false): string => {\n // Handle array (OR conditions)\n if (Array.isArray(cond)) {\n const clauses = cond\n .map((item) => {\n const clause = Array.isArray(item) ? buildCondition(item, true) : buildCondition(item, true);\n return clause ? `(${clause})` : '';\n })\n .filter((clause) => clause !== ''); // Filter out empty clauses\n\n return clauses.join(' OR ');\n }\n\n // Handle object (AND conditions)\n const conditions: string[] = [];\n let hasFunctionFilter = false;\n for (const [key, value] of Object.entries(cond)) {\n if (typeof value === 'function') {\n // Function filter - will be applied later\n functionFilters.push({ key, fn: value as (value: unknown) => boolean });\n hasFunctionFilter = true;\n } else {\n // Regular value\n conditions.push(`${this.quoteIdentifier(key)} = ?`);\n values.push(this.normalizeValue(value));\n }\n }\n\n if (isInOr && hasFunctionFilter) {\n hasOrWithFunctionFilters = true;\n }\n\n return conditions.join(' AND ');\n };\n\n const sql = buildCondition(condition);\n return { sql, values, functionFilters, hasOrWithFunctionFilters };\n }\n\n /**\n * Apply OR condition with function filters by evaluating each row against the condition\n */\n private applyOrConditionWithFilters<T extends Record<string, unknown>>(rows: T[], condition: WhereCondition<T>): T[] {\n return rows.filter((row) => this.matchesOrCondition(row, condition));\n }\n\n /**\n * Check if a row matches an OR/AND condition (recursively)\n */\n private matchesOrCondition<T extends Record<string, unknown>>(row: T, condition: WhereCondition<T>): boolean {\n // Handle array (OR conditions)\n if (Array.isArray(condition)) {\n return condition.some((item) => this.matchesOrCondition(row, item));\n }\n\n // Handle object (AND conditions)\n return Object.entries(condition).every(([key, value]) => {\n const rowValue = row[key as keyof T];\n if (typeof value === 'function') {\n return (value as (value: unknown) => boolean)(rowValue);\n }\n return rowValue === value;\n });\n }\n\n /**\n * Apply function filters to rows\n */\n private applyFunctionFilters<T extends Record<string, unknown>>(\n rows: T[],\n functionFilters: Array<{ key: string; fn: (value: unknown) => boolean }>,\n ): T[] {\n if (functionFilters.length === 0) return rows;\n\n return rows.filter((row) => {\n return functionFilters.every(({ key, fn }) => {\n const value = row[key as keyof T];\n return fn(value);\n });\n });\n }\n\n /**\n * Get table schema\n */\n getSchema(tableName: string): TableSchema | undefined {\n return this.schemas.get(tableName);\n }\n\n /**\n * Get all table names\n */\n getTableNames(): string[] {\n return Array.from(this.schemas.keys());\n }\n\n /**\n * Sync a specific table back to its JSONL file\n * Uses backward transformation when available\n */\n private async syncTable(tableName: string): Promise<void> {\n const tableConfig = this.tables.get(tableName);\n if (!tableConfig) {\n throw new Error(`Table ${tableName} not found`);\n }\n\n // Get all rows from the table\n const rows = this.query<JsonObject>(`SELECT * FROM ${this.quoteTableName(tableName)}`);\n\n // Deserialize JSON columns\n const deserializedRows = rows.map((row) => this.deserializeRow(tableName, row));\n\n // Apply backward transformation if available\n const validationSchema = this.validationSchemas.get(tableName);\n let finalRows = deserializedRows;\n\n if (validationSchema && hasBackward(validationSchema)) {\n const biSchema = validationSchema as BiDirectionalSchema<Table, Table>;\n finalRows = deserializedRows.map((row) => biSchema.backward!(row) as JsonObject);\n }\n\n // Write back to JSONL file\n await JsonlWriter.write(tableConfig.jsonlPath, finalRows);\n }\n\n /**\n * Sync database changes back to JSONL files\n * Uses backward transformation when available\n * @param tableName Optional table name to sync. If not provided, syncs all loaded tables\n */\n async sync(tableName?: string): Promise<void> {\n if (tableName) {\n // Sync only the specified table\n if (!this.schemas.has(tableName)) {\n throw new Error(`Table '${tableName}' is not loaded`);\n }\n await this.syncTable(tableName);\n } else {\n // Sync all tables that are loaded (present in schemas map)\n for (const [name] of this.schemas) {\n await this.syncTable(name);\n }\n }\n }\n\n /**\n * Execute a function within a transaction\n * Automatically commits on success or rolls back on error\n */\n async transaction<T>(fn: (tx: LinesDB<Tables>) => Promise<T> | T): Promise<T> {\n if (this.inTransaction) {\n throw new Error('Nested transactions are not supported');\n }\n\n this.db.exec('BEGIN TRANSACTION');\n this.inTransaction = true;\n\n try {\n const result = await fn(this);\n this.db.exec('COMMIT');\n this.inTransaction = false;\n\n // Sync all tables after successful commit\n await this.sync();\n\n return result;\n } catch (error) {\n if (this.inTransaction) {\n this.db.exec('ROLLBACK');\n }\n this.inTransaction = false;\n throw error;\n }\n }\n\n /**\n * Close the database connection\n */\n async close(): Promise<void> {\n try {\n this.db.close();\n } catch (_error) {\n // Ignore errors if database is already closed\n }\n }\n\n /**\n * Get the underlying SQLite database instance\n */\n getDb(): SQLiteDatabase {\n return this.db;\n }\n}\n","import { readdir } from 'node:fs/promises';\nimport { join, relative, basename, dirname, isAbsolute } from 'node:path';\nimport { writeFile, mkdir } from 'node:fs/promises';\nimport { findSchemaFileInEntries, rewriteExtensionForImport } from './schema-extensions.js';\n\nexport interface TypeGeneratorOptions {\n dataDir: string;\n projectRoot?: string; // Default: current working directory\n output?: string; // Output file path (default: db.ts in dataDir)\n}\n\ninterface TableInfo {\n tableName: string;\n schemaFile?: string;\n}\n\nexport class TypeGenerator {\n private dataDir: string;\n private projectRoot: string;\n private outputFile: string;\n private dataDirPath: string;\n\n constructor(options: TypeGeneratorOptions) {\n // For testing: allow overriding projectRoot via environment variable\n const envProjectRoot = process.env.LINES_DB_TEST_PROJECT_ROOT;\n this.projectRoot = envProjectRoot !== undefined ? envProjectRoot : options.projectRoot || process.cwd();\n this.dataDir = options.dataDir;\n this.dataDirPath = isAbsolute(this.dataDir) ? this.dataDir : join(this.projectRoot, this.dataDir);\n this.outputFile = options.output\n ? isAbsolute(options.output)\n ? options.output\n : join(this.projectRoot, options.output)\n : join(this.dataDirPath, 'db.ts');\n }\n\n /**\n * Generate types file from JSONL files and their optional schema files.\n */\n async generate(): Promise<string> {\n // Find all JSONL files and their corresponding schema files\n const tables = await this.findTables();\n\n if (tables.length === 0) {\n throw new Error(`No JSONL files found in ${this.dataDirPath}. Place one or more *.jsonl files in the directory.`);\n }\n\n // Generate type declarations\n const content = this.generateTypeDeclarations(tables);\n\n // Ensure output directory exists\n const outputDir = dirname(this.outputFile);\n await mkdir(outputDir, { recursive: true });\n\n // Write to file\n await writeFile(this.outputFile, content, 'utf-8');\n console.log(`Generated types at ${this.outputFile}`);\n return this.outputFile;\n }\n\n /**\n * Find all *.jsonl files and check if they have corresponding *.schema.ts files\n */\n private async findTables(): Promise<TableInfo[]> {\n try {\n const entries = await readdir(this.dataDirPath, { withFileTypes: true });\n const tables: TableInfo[] = [];\n\n for (const entry of entries) {\n if (entry.isFile() && entry.name.endsWith('.jsonl')) {\n const tableName = basename(entry.name, '.jsonl');\n const schemaFilePath = findSchemaFileInEntries(this.dataDirPath, tableName, entries);\n\n tables.push({\n tableName,\n schemaFile: schemaFilePath,\n });\n }\n }\n\n return tables;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n throw new Error(`Data directory not found: ${this.dataDirPath}. Set lines-db.dataDir to the correct location.`);\n }\n throw error;\n }\n }\n\n /**\n * Generate type declaration content\n */\n private generateTypeDeclarations(tables: TableInfo[]): string {\n const imports: string[] = [];\n const tableEntries: string[] = [];\n const usedAliases = new Set<string>();\n\n for (const table of tables) {\n const tableKey = this.formatTableKey(table.tableName);\n\n if (table.schemaFile) {\n // Table has a schema file\n const schemaIdentifier = this.createSchemaIdentifier(table.tableName, usedAliases);\n usedAliases.add(schemaIdentifier);\n\n // Calculate relative path from output file to schema file\n let relativePath = rewriteExtensionForImport(\n relative(join(this.outputFile, '..'), table.schemaFile).replace(/\\\\/g, '/'), // Convert Windows paths to Unix-style\n );\n\n // Ensure relative path starts with './' or '../'\n if (!relativePath.startsWith('.')) {\n relativePath = './' + relativePath;\n }\n\n // Add import statement for schema\n imports.push(`import { schema as ${schemaIdentifier} } from '${relativePath}';`);\n\n // Add table entry with InferOutput\n tableEntries.push(` ${tableKey}: InferOutput<typeof ${schemaIdentifier}>;`);\n } else {\n // Table has no schema file, use Record<string, unknown>\n tableEntries.push(` ${tableKey}: Record<string, unknown>;`);\n }\n }\n\n // Generate full content\n const importSection = imports.length > 0 ? `${imports.join('\\n')}\\n` : '';\n const inferOutputImport = imports.length > 0 ? ', InferOutput' : '';\n\n return `// Auto-generated by lines-db\n// Do not edit this file manually\n\n${importSection}import type { DatabaseConfig${inferOutputImport} } from '@toiroakr/lines-db';\nimport { fileURLToPath } from 'node:url';\nimport { dirname } from 'node:path';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\nexport type Tables = {\n${tableEntries.join('\\n')}\n};\n\nexport const config: DatabaseConfig<Tables> = {\n dataDir: __dirname,\n};\n`;\n }\n\n private createSchemaIdentifier(tableName: string, usedAliases: Set<string>): string {\n const camel = toCamelCase(tableName);\n const sanitizedBase = sanitizeIdentifier(camel);\n let base = sanitizedBase || 'table';\n\n if (!/^[A-Za-z_$]/.test(base)) {\n base = `_${base}`;\n }\n\n let candidate = `${base}Schema`;\n let suffix = 1;\n while (usedAliases.has(candidate)) {\n candidate = `${base}${++suffix}Schema`;\n }\n\n return candidate;\n }\n\n private formatTableKey(tableName: string): string {\n const identifierPattern = /^[A-Za-z_$][A-Za-z0-9_$]*$/;\n if (identifierPattern.test(tableName)) {\n return tableName;\n }\n const escaped = tableName.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"\\\\'\");\n return `'${escaped}'`;\n }\n}\n\nfunction toCamelCase(value: string): string {\n const parts = value\n .split(/[^A-Za-z0-9]+/)\n .filter(Boolean)\n .map((part) => part.toLowerCase());\n\n if (parts.length === 0) {\n return value;\n }\n\n const [first, ...rest] = parts;\n return first + rest.map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join('');\n}\n\nfunction sanitizeIdentifier(value: string): string {\n return value.replace(/[^A-Za-z0-9_$]/g, '');\n}\n","import { join } from 'node:path';\nimport type { JsonObject } from './types.js';\nimport { JsonlReader } from './jsonl-reader.js';\nimport { LinesDB } from './database.js';\n\nexport interface TableValidationOptions {\n dataDir: string;\n tableName: string;\n rows: JsonObject[];\n}\n\n/**\n * Validate a table by temporarily supplying in-memory rows while reusing the existing LinesDB validation pipeline.\n * If validation fails, throws an error with validation details.\n */\nexport async function ensureTableRowsValid(options: TableValidationOptions): Promise<void> {\n const tablePath = join(options.dataDir, `${options.tableName}.jsonl`);\n const overrides = new Map<string, JsonObject[]>([[tablePath, options.rows]]);\n\n await JsonlReader.withOverrides(overrides, async () => {\n const db = LinesDB.create({ dataDir: options.dataDir });\n try {\n // Initialize only the target table\n const result = await db.initialize({ tableName: options.tableName });\n\n // If validation failed, throw an error with details\n if (!result.valid) {\n const errorCount = result.errors.length;\n const errorDetails = result.errors\n .map((e) => {\n const issueMessages = e.issues.map((issue) => issue.message).join(', ');\n return ` Row ${e.rowIndex}: ${issueMessages}`;\n })\n .join('\\n');\n\n throw new Error(\n `Validation failed for table '${options.tableName}' (${errorCount} error(s)):\\n${errorDetails}`,\n );\n }\n } finally {\n await db.close();\n }\n });\n}\n","import type { StandardSchemaIssue } from './types.js';\nimport { styleText } from 'node:util';\n\nexport interface ValidationErrorInfo {\n file: string;\n rowIndex: number;\n issues: ReadonlyArray<StandardSchemaIssue>;\n data?: unknown;\n originalData?: unknown;\n}\n\nexport interface ForeignKeyErrorInfo {\n file: string;\n rowIndex: number;\n column: string;\n value: unknown;\n referencedTable: string;\n referencedColumn: string;\n data?: unknown;\n}\n\nexport interface ErrorFormatterOptions {\n verbose?: boolean;\n}\n\nexport class ErrorFormatter {\n private verbose: boolean;\n\n constructor(options: ErrorFormatterOptions = {}) {\n this.verbose = options.verbose ?? false;\n }\n\n /**\n * Format validation errors\n */\n formatValidationErrors(errors: ValidationErrorInfo[]): string {\n if (this.verbose) {\n return this.formatValidationErrorsVerbose(errors);\n }\n return this.formatValidationErrorsCompact(errors);\n }\n\n /**\n * Format foreign key error\n */\n formatForeignKeyError(error: ForeignKeyErrorInfo): string {\n if (this.verbose) {\n return this.formatForeignKeyErrorVerbose(error);\n }\n return this.formatForeignKeyErrorCompact(error);\n }\n\n /**\n * Format compact (default) validation errors\n */\n private formatValidationErrorsCompact(errors: ValidationErrorInfo[]): string {\n const lines: string[] = [];\n\n for (const error of errors) {\n for (const issue of error.issues) {\n const fieldPath = this.getFieldPath(issue);\n const line = `${error.file}:${error.rowIndex + 1} • ${fieldPath}: ${issue.message}`;\n lines.push(line);\n }\n }\n\n return lines.join('\\n');\n }\n\n /**\n * Format verbose validation errors\n */\n private formatValidationErrorsVerbose(errors: ValidationErrorInfo[]): string {\n const blocks: string[] = [];\n\n for (let i = 0; i < errors.length; i++) {\n const error = errors[i];\n const isLast = i === errors.length - 1;\n const prefix = isLast ? '└─' : '├─';\n const linePrefix = isLast ? ' ' : '│ ';\n\n const lines: string[] = [`${prefix} ${error.file}:${error.rowIndex + 1}`];\n\n for (const issue of error.issues) {\n const fieldPath = this.getFieldPath(issue);\n lines.push(`${linePrefix}Field: ${fieldPath}`);\n lines.push(`${linePrefix}Error: ${issue.message}`);\n }\n\n // Show original data if available (migrate case)\n if (error.originalData !== undefined) {\n lines.push(`${linePrefix}Original data: ${JSON.stringify(error.originalData)}`);\n }\n\n // Show data\n if (error.data !== undefined) {\n const label = error.originalData !== undefined ? 'Transformed data' : 'Data';\n lines.push(`${linePrefix}${label}: ${JSON.stringify(error.data)}`);\n }\n\n blocks.push(lines.join('\\n'));\n }\n\n return blocks.join('\\n│\\n');\n }\n\n /**\n * Format compact foreign key error\n */\n private formatForeignKeyErrorCompact(error: ForeignKeyErrorInfo): string {\n return `${error.file}:${error.rowIndex + 1} • ${error.column}: Foreign key constraint failed - Referenced value ${JSON.stringify(error.value)} does not exist in ${error.referencedTable}(${error.referencedColumn})`;\n }\n\n /**\n * Format verbose foreign key error\n */\n private formatForeignKeyErrorVerbose(error: ForeignKeyErrorInfo): string {\n const lines: string[] = [\n `└─ ${error.file}:${error.rowIndex + 1}`,\n ` Type: Foreign Key Violation`,\n ` Field: ${error.column}`,\n ` Value: ${JSON.stringify(error.value)}`,\n ` References: ${error.referencedTable}(${error.referencedColumn})`,\n ` Error: Referenced value does not exist in target table`,\n ];\n\n if (error.data !== undefined) {\n lines.push(` Data: ${JSON.stringify(error.data)}`);\n }\n\n return lines.join('\\n');\n }\n\n /**\n * Get field path from issue\n */\n private getFieldPath(issue: StandardSchemaIssue): string {\n if (!issue.path || issue.path.length === 0) {\n return 'root';\n }\n\n return issue.path\n .map((segment) => {\n if (typeof segment === 'object' && segment !== null && 'key' in segment) {\n return String(segment.key);\n }\n return String(segment);\n })\n .join('.');\n }\n\n /**\n * Format error header with count\n */\n formatErrorHeader(count: number, file?: string): string {\n const fileInfo = file ? ` in ${file}` : '';\n return styleText('red', `✗ Found ${count} error(s)${fileInfo}`);\n }\n\n /**\n * Format migration failure header\n */\n formatMigrationFailureHeader(): string {\n return styleText('red', '\\n✗ Migration failed and was rolled back');\n }\n}\n"],"mappings":"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"}
|