@fragno-dev/db 0.0.1 → 0.1.0
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/.turbo/turbo-build.log +137 -13
- package/.turbo/turbo-test.log +36 -0
- package/CHANGELOG.md +7 -0
- package/dist/adapters/adapters.d.ts +18 -0
- package/dist/adapters/adapters.d.ts.map +1 -0
- package/dist/adapters/drizzle/drizzle-adapter.d.ts +21 -0
- package/dist/adapters/drizzle/drizzle-adapter.d.ts.map +1 -0
- package/dist/adapters/drizzle/drizzle-adapter.js +62 -0
- package/dist/adapters/drizzle/drizzle-adapter.js.map +1 -0
- package/dist/adapters/drizzle/drizzle-query.d.ts +17 -0
- package/dist/adapters/drizzle/drizzle-query.d.ts.map +1 -0
- package/dist/adapters/drizzle/drizzle-query.js +139 -0
- package/dist/adapters/drizzle/drizzle-query.js.map +1 -0
- package/dist/adapters/drizzle/drizzle-uow-compiler.d.ts +9 -0
- package/dist/adapters/drizzle/drizzle-uow-compiler.d.ts.map +1 -0
- package/dist/adapters/drizzle/drizzle-uow-compiler.js +300 -0
- package/dist/adapters/drizzle/drizzle-uow-compiler.js.map +1 -0
- package/dist/adapters/drizzle/drizzle-uow-decoder.js +82 -0
- package/dist/adapters/drizzle/drizzle-uow-decoder.js.map +1 -0
- package/dist/adapters/drizzle/drizzle-uow-executor.js +125 -0
- package/dist/adapters/drizzle/drizzle-uow-executor.js.map +1 -0
- package/dist/adapters/drizzle/generate.js +273 -0
- package/dist/adapters/drizzle/generate.js.map +1 -0
- package/dist/adapters/drizzle/join-column-utils.js +28 -0
- package/dist/adapters/drizzle/join-column-utils.js.map +1 -0
- package/dist/adapters/drizzle/shared.js +11 -0
- package/dist/adapters/drizzle/shared.js.map +1 -0
- package/dist/adapters/kysely/kysely-adapter.d.ts +23 -0
- package/dist/adapters/kysely/kysely-adapter.d.ts.map +1 -0
- package/dist/adapters/kysely/kysely-adapter.js +119 -0
- package/dist/adapters/kysely/kysely-adapter.js.map +1 -0
- package/dist/adapters/kysely/kysely-query-builder.js +306 -0
- package/dist/adapters/kysely/kysely-query-builder.js.map +1 -0
- package/dist/adapters/kysely/kysely-query-compiler.js +67 -0
- package/dist/adapters/kysely/kysely-query-compiler.js.map +1 -0
- package/dist/adapters/kysely/kysely-query.js +158 -0
- package/dist/adapters/kysely/kysely-query.js.map +1 -0
- package/dist/adapters/kysely/kysely-uow-compiler.js +139 -0
- package/dist/adapters/kysely/kysely-uow-compiler.js.map +1 -0
- package/dist/adapters/kysely/kysely-uow-executor.js +89 -0
- package/dist/adapters/kysely/kysely-uow-executor.js.map +1 -0
- package/dist/adapters/kysely/migration/execute.js +176 -0
- package/dist/adapters/kysely/migration/execute.js.map +1 -0
- package/dist/fragment.d.ts +54 -0
- package/dist/fragment.d.ts.map +1 -0
- package/dist/fragment.js +92 -0
- package/dist/fragment.js.map +1 -0
- package/dist/id.d.ts +2 -0
- package/dist/migration-engine/auto-from-schema.js +116 -0
- package/dist/migration-engine/auto-from-schema.js.map +1 -0
- package/dist/migration-engine/create.d.ts +41 -0
- package/dist/migration-engine/create.d.ts.map +1 -0
- package/dist/migration-engine/create.js +58 -0
- package/dist/migration-engine/create.js.map +1 -0
- package/dist/migration-engine/shared.d.ts +90 -0
- package/dist/migration-engine/shared.d.ts.map +1 -0
- package/dist/migration-engine/shared.js +8 -0
- package/dist/migration-engine/shared.js.map +1 -0
- package/dist/mod.d.ts +55 -2
- package/dist/mod.d.ts.map +1 -1
- package/dist/mod.js +111 -2
- package/dist/mod.js.map +1 -1
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/column-builder.js +108 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/column-builder.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/column.js +55 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/column.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/entity.js +18 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/entity.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/pg-core/columns/common.js +183 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/pg-core/columns/common.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/pg-core/columns/enum.js +58 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/pg-core/columns/enum.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/pg-core/foreign-keys.js +68 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/pg-core/foreign-keys.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/pg-core/unique-constraint.js +56 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/pg-core/unique-constraint.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/pg-core/utils/array.js +65 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/pg-core/utils/array.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/sql/expressions/conditions.js +81 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/sql/expressions/conditions.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/sql/expressions/select.js +13 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/sql/expressions/select.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/sql/functions/aggregate.js +10 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/sql/functions/aggregate.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/sql/sql.js +372 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/sql/sql.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/subquery.js +23 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/subquery.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/table.js +62 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/table.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/table.utils.js +6 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/table.utils.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/tracing-utils.js +8 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/tracing-utils.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/tracing.js +8 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/tracing.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/view-common.js +6 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/view-common.js.map +1 -0
- package/dist/query/condition-builder.d.ts +41 -0
- package/dist/query/condition-builder.d.ts.map +1 -0
- package/dist/query/condition-builder.js +93 -0
- package/dist/query/condition-builder.js.map +1 -0
- package/dist/query/cursor.d.ts +88 -0
- package/dist/query/cursor.d.ts.map +1 -0
- package/dist/query/cursor.js +103 -0
- package/dist/query/cursor.js.map +1 -0
- package/dist/query/orm/orm.d.ts +18 -0
- package/dist/query/orm/orm.d.ts.map +1 -0
- package/dist/query/orm/orm.js +48 -0
- package/dist/query/orm/orm.js.map +1 -0
- package/dist/query/query.d.ts +79 -0
- package/dist/query/query.d.ts.map +1 -0
- package/dist/query/query.js +1 -0
- package/dist/query/result-transform.js +155 -0
- package/dist/query/result-transform.js.map +1 -0
- package/dist/query/unit-of-work.d.ts +435 -0
- package/dist/query/unit-of-work.d.ts.map +1 -0
- package/dist/query/unit-of-work.js +549 -0
- package/dist/query/unit-of-work.js.map +1 -0
- package/dist/schema/create.d.ts +273 -116
- package/dist/schema/create.d.ts.map +1 -1
- package/dist/schema/create.js +410 -222
- package/dist/schema/create.js.map +1 -1
- package/dist/schema/serialize.js +101 -0
- package/dist/schema/serialize.js.map +1 -0
- package/dist/schema-generator/schema-generator.d.ts +15 -0
- package/dist/schema-generator/schema-generator.d.ts.map +1 -0
- package/dist/shared/providers.d.ts +6 -0
- package/dist/shared/providers.d.ts.map +1 -0
- package/dist/util/import-generator.js +26 -0
- package/dist/util/import-generator.js.map +1 -0
- package/dist/util/parse.js +15 -0
- package/dist/util/parse.js.map +1 -0
- package/dist/util/types.d.ts +8 -0
- package/dist/util/types.d.ts.map +1 -0
- package/package.json +63 -2
- package/src/adapters/adapters.ts +22 -0
- package/src/adapters/drizzle/drizzle-adapter-pglite.test.ts +433 -0
- package/src/adapters/drizzle/drizzle-adapter.test.ts +122 -0
- package/src/adapters/drizzle/drizzle-adapter.ts +118 -0
- package/src/adapters/drizzle/drizzle-query.ts +234 -0
- package/src/adapters/drizzle/drizzle-uow-compiler.test.ts +1084 -0
- package/src/adapters/drizzle/drizzle-uow-compiler.ts +546 -0
- package/src/adapters/drizzle/drizzle-uow-decoder.ts +165 -0
- package/src/adapters/drizzle/drizzle-uow-executor.ts +213 -0
- package/src/adapters/drizzle/generate.test.ts +643 -0
- package/src/adapters/drizzle/generate.ts +481 -0
- package/src/adapters/drizzle/join-column-utils.test.ts +79 -0
- package/src/adapters/drizzle/join-column-utils.ts +39 -0
- package/src/adapters/drizzle/migrate-drizzle.test.ts +226 -0
- package/src/adapters/drizzle/shared.ts +22 -0
- package/src/adapters/drizzle/test-utils.ts +56 -0
- package/src/adapters/kysely/kysely-adapter-pglite.test.ts +789 -0
- package/src/adapters/kysely/kysely-adapter.ts +196 -0
- package/src/adapters/kysely/kysely-query-builder.test.ts +1344 -0
- package/src/adapters/kysely/kysely-query-builder.ts +611 -0
- package/src/adapters/kysely/kysely-query-compiler.ts +124 -0
- package/src/adapters/kysely/kysely-query.ts +254 -0
- package/src/adapters/kysely/kysely-uow-compiler.test.ts +916 -0
- package/src/adapters/kysely/kysely-uow-compiler.ts +271 -0
- package/src/adapters/kysely/kysely-uow-executor.ts +149 -0
- package/src/adapters/kysely/kysely-uow-joins.test.ts +811 -0
- package/src/adapters/kysely/migration/execute-mysql.test.ts +1173 -0
- package/src/adapters/kysely/migration/execute-postgres.test.ts +2657 -0
- package/src/adapters/kysely/migration/execute.ts +382 -0
- package/src/adapters/kysely/migration/kysely-migrator.test.ts +197 -0
- package/src/fragment.test.ts +287 -0
- package/src/fragment.ts +198 -0
- package/src/migration-engine/auto-from-schema.test.ts +118 -58
- package/src/migration-engine/auto-from-schema.ts +103 -32
- package/src/migration-engine/create.test.ts +34 -46
- package/src/migration-engine/create.ts +41 -26
- package/src/migration-engine/shared.ts +26 -6
- package/src/mod.ts +197 -1
- package/src/query/condition-builder.test.ts +379 -0
- package/src/query/condition-builder.ts +294 -0
- package/src/query/cursor.test.ts +296 -0
- package/src/query/cursor.ts +147 -0
- package/src/query/orm/orm.ts +92 -0
- package/src/query/query-type.test.ts +429 -0
- package/src/query/query.ts +200 -0
- package/src/query/result-transform.test.ts +795 -0
- package/src/query/result-transform.ts +247 -0
- package/src/query/unit-of-work-types.test.ts +192 -0
- package/src/query/unit-of-work.test.ts +947 -0
- package/src/query/unit-of-work.ts +1199 -0
- package/src/schema/create.test.ts +653 -110
- package/src/schema/create.ts +708 -337
- package/src/schema/serialize.test.ts +559 -0
- package/src/schema/serialize.ts +359 -0
- package/src/schema-generator/schema-generator.ts +12 -0
- package/src/shared/config.ts +0 -8
- package/src/util/import-generator.ts +28 -0
- package/src/util/parse.ts +16 -0
- package/src/util/types.ts +4 -0
- package/tsconfig.json +1 -1
- package/tsdown.config.ts +11 -1
- package/vitest.config.ts +3 -0
- /package/dist/{cuid.js → id.js} +0 -0
- /package/src/{cuid.ts → id.ts} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create.js","names":["columns: AnyColumn[]","referencedColumns: AnyColumn[]","#name","#columns","#relations","#version","#foreignKeys","#indexes","#ormName","#operations","column","name","idCol: AnyColumn | undefined","table: Table<TColumns, TRelations>","cloneColumns: Record<string, AnyColumn>","table","#tables","newOperations: SchemaOperation[]","cloneTables: Record<string, AnyTable>"],"sources":["../../src/schema/create.ts"],"sourcesContent":["import { createId } from \"../cuid\";\n\nexport type AnySchema = Schema<Record<string, AnyTable>>;\n\nexport type AnyRelation = Relation;\n\nexport type AnyTable = Table;\n\nexport type AnyColumn =\n | Column<keyof TypeMap, unknown, unknown>\n | IdColumn<IdColumnType, unknown, unknown>;\n\n/**\n * Operations that can be performed on a table during its definition.\n */\nexport type TableOperation = {\n type: \"add-index\";\n name: string;\n columns: string[];\n unique: boolean;\n};\n\n/**\n * Operations that can be performed on a schema during its definition.\n * These are tracked so we can generate migrations for specific version ranges.\n */\nexport type SchemaOperation =\n | {\n type: \"add-table\";\n tableName: string;\n table: AnyTable;\n }\n | {\n type: \"add-reference\";\n tableName: string;\n referenceName: string;\n config: {\n columns: string[];\n targetTable: string;\n targetColumns: string[];\n };\n }\n | {\n type: \"add-index\";\n tableName: string;\n name: string;\n columns: string[];\n unique: boolean;\n };\n\nexport interface ForeignKey {\n name: string;\n table: AnyTable;\n columns: AnyColumn[];\n\n referencedTable: AnyTable;\n referencedColumns: AnyColumn[];\n}\n\nclass RelationInit<\n TRelationType extends RelationType,\n TTables extends Record<string, AnyTable>,\n TTableName extends keyof TTables,\n> {\n type: TRelationType;\n referencedTable: TTables[TTableName];\n referencer: AnyTable;\n on: [string, string][] = [];\n\n constructor(type: TRelationType, referencedTable: TTables[TTableName], referencer: AnyTable) {\n this.type = type;\n this.referencedTable = referencedTable;\n this.referencer = referencer;\n }\n}\n\nexport interface Index {\n name: string;\n columns: AnyColumn[];\n unique: boolean;\n}\n\n/**\n * Helper function to add an index to a table's index array\n */\nfunction addIndexToTable(\n indexes: Index[],\n name: string,\n columns: AnyColumn[],\n unique: boolean,\n): void {\n indexes.push({\n name,\n columns,\n unique,\n });\n}\n\nexport class ExplicitRelationInit<\n TRelationType extends RelationType,\n TTables extends Record<string, AnyTable>,\n TTableName extends keyof TTables,\n> extends RelationInit<TRelationType, TTables, TTableName> {\n private foreignKeyName?: string;\n\n private initForeignKey(ormName: string): ForeignKey {\n const columns: AnyColumn[] = [];\n const referencedColumns: AnyColumn[] = [];\n\n for (const [left, right] of this.on) {\n columns.push(this.referencer.columns[left]);\n referencedColumns.push(this.referencedTable.columns[right]);\n }\n\n return {\n columns,\n referencedColumns,\n referencedTable: this.referencedTable,\n table: this.referencer,\n name:\n this.foreignKeyName ??\n `${this.referencer.ormName}_${this.referencedTable.ormName}_${ormName}_fk`,\n };\n }\n\n init(ormName: string): Relation<TRelationType, TTables[TTableName]> {\n const id = `${this.referencer.ormName}_${this.referencedTable.ormName}`;\n\n return {\n id,\n foreignKey: this.initForeignKey(ormName),\n on: this.on,\n name: ormName,\n referencer: this.referencer,\n table: this.referencedTable,\n type: this.type,\n };\n }\n\n /**\n * Define custom foreign key name.\n */\n foreignKey(name: string) {\n this.foreignKeyName = name;\n return this;\n }\n}\n\nexport interface Relation<\n TRelationType extends RelationType = RelationType,\n TTable extends AnyTable = AnyTable,\n> {\n id: string;\n name: string;\n type: TRelationType;\n\n table: TTable;\n referencer: AnyTable;\n\n on: [string, string][];\n foreignKey: ForeignKey;\n}\n\nexport interface Table<\n TColumns extends Record<string, AnyColumn> = Record<string, AnyColumn>,\n TRelations extends Record<string, AnyRelation> = Record<string, AnyRelation>,\n> {\n name: string;\n ormName: string;\n\n columns: TColumns;\n relations: TRelations;\n foreignKeys: ForeignKey[];\n indexes: Index[];\n\n /**\n * Get column by name\n */\n getColumnByName: (name: string) => AnyColumn | undefined;\n getIdColumn: () => AnyColumn;\n\n clone: () => Table<TColumns, TRelations>;\n}\n\ntype DefaultFunctionMap = {\n date: \"now\";\n timestamp: \"now\";\n string: \"auto\";\n} & Record<`varchar(${number})`, \"auto\">;\n\ntype DefaultFunction<TType extends keyof TypeMap> =\n | (TType extends keyof DefaultFunctionMap ? DefaultFunctionMap[TType] : never)\n | (() => TypeMap[TType]);\n\ntype IdColumnType = `varchar(${number})`;\n\nexport type TypeMap = {\n string: string;\n bigint: bigint;\n integer: number;\n decimal: number;\n bool: boolean;\n json: unknown;\n /**\n * this follows the same specs as Prisma `Bytes` for consistency.\n */\n binary: Uint8Array;\n date: Date;\n timestamp: Date;\n} & Record<`varchar(${number})`, string>;\n\nexport class Column<TType extends keyof TypeMap, TIn = unknown, TOut = unknown> {\n type: TType;\n name: string = \"\";\n ormName: string = \"\";\n isNullable: boolean = false;\n isUnique: boolean = false;\n isReference: boolean = false;\n default?:\n | { value: TypeMap[TType] }\n | {\n runtime: DefaultFunction<TType>;\n };\n\n table: AnyTable = undefined as unknown as AnyTable;\n\n constructor(type: TType) {\n this.type = type;\n }\n\n nullable<TNullable extends boolean = true>(nullable?: TNullable) {\n this.isNullable = nullable ?? true;\n\n return this as Column<\n TType,\n TNullable extends true ? TIn | null : Exclude<TIn, null>,\n TNullable extends true ? TOut | null : Exclude<TOut, null>\n >;\n }\n\n /**\n * Generate default value on runtime\n */\n defaultTo$(fn: DefaultFunction<TType>): Column<TType, TIn | null, TOut> {\n this.default = { runtime: fn };\n return this;\n }\n\n /**\n * Set a database-level default value\n *\n * For schemaless database, it's still generated on runtime\n */\n defaultTo(value: TypeMap[TType]): Column<TType, TIn | null, TOut> {\n this.default = { value };\n return this;\n }\n\n clone() {\n const clone = new Column(this.type);\n clone.name = this.name;\n clone.ormName = this.ormName;\n clone.isNullable = this.isNullable;\n clone.isUnique = this.isUnique;\n clone.isReference = this.isReference;\n clone.default = this.default;\n clone.table = this.table;\n return clone;\n }\n\n getUniqueConstraintName(): string {\n return `unique_c_${this.table.ormName}_${this.ormName}`;\n }\n\n /**\n * Generate default value for the column on runtime.\n */\n generateDefaultValue(): TypeMap[TType] | undefined {\n if (!this.default) {\n return;\n }\n\n if (\"value\" in this.default) {\n return this.default.value;\n }\n if (this.default.runtime === \"auto\") {\n return createId() as TypeMap[TType];\n }\n if (this.default.runtime === \"now\") {\n return new Date(Date.now()) as TypeMap[TType];\n }\n\n return this.default.runtime();\n }\n\n get $in(): TIn {\n throw new Error(\"Type inference only\");\n }\n get $out(): TOut {\n throw new Error(\"Type inference only\");\n }\n}\n\nexport class IdColumn<\n TType extends IdColumnType = IdColumnType,\n TIn = unknown,\n TOut = unknown,\n> extends Column<TType, TIn, TOut> {\n id = true;\n\n clone() {\n const clone = new IdColumn(this.type);\n clone.name = this.name;\n clone.ormName = this.ormName;\n clone.isNullable = this.isNullable;\n clone.isUnique = this.isUnique;\n clone.isReference = this.isReference;\n clone.default = this.default;\n clone.table = this.table;\n return clone;\n }\n\n override defaultTo$(fn: DefaultFunction<TType>) {\n return super.defaultTo$(fn) as IdColumn<TType, TIn | null, TOut>;\n }\n\n override defaultTo(value: TypeMap[TType]) {\n return super.defaultTo(value) as IdColumn<TType, TIn | null, TOut>;\n }\n}\n\nexport function column<TType extends keyof TypeMap>(\n type: TType,\n): Column<TType, TypeMap[TType], TypeMap[TType]> {\n return new Column(type);\n}\n\n/**\n * Create a reference column that points to another table.\n * This is used for foreign key relationships.\n */\nexport function referenceColumn<TType extends keyof TypeMap = \"varchar(30)\">(\n type?: TType,\n): Column<TType, TypeMap[TType], TypeMap[TType]> {\n const actualType = (type ?? \"varchar(30)\") as TType;\n const col = new Column<TType, TypeMap[TType], TypeMap[TType]>(actualType);\n col.isReference = true;\n return col as Column<TType, TypeMap[TType], TypeMap[TType]>;\n}\n\nexport function idColumn(): IdColumn<\"varchar(30)\", string, string> {\n const col = new IdColumn<\"varchar(30)\", string, string>(\"varchar(30)\");\n col.defaultTo$(\"auto\");\n return col as IdColumn<\"varchar(30)\", string, string>;\n}\n\ntype RelationType = \"one\";\n\nexport class TableBuilder<\n TColumns extends Record<string, AnyColumn> = Record<string, AnyColumn>,\n TRelations extends Record<string, AnyRelation> = Record<string, AnyRelation>,\n> {\n #name: string;\n #columns: TColumns;\n #relations: TRelations;\n #foreignKeys: ForeignKey[] = [];\n #indexes: Index[] = [];\n #version: number = 0;\n #ormName: string = \"\";\n #operations: TableOperation[] = [];\n\n constructor(name: string) {\n this.#name = name;\n this.#columns = {} as TColumns;\n this.#relations = {} as TRelations;\n }\n\n /**\n * Add a column to the table. Increments the version counter.\n */\n addColumn<TColumnName extends string, TColumn extends AnyColumn>(\n ormName: TColumnName,\n col: TColumn,\n ): TableBuilder<TColumns & Record<TColumnName, TColumn>, TRelations>;\n\n /**\n * Add a column to the table with simplified syntax. Increments the version counter.\n */\n addColumn<TColumnName extends string, TType extends keyof TypeMap>(\n ormName: TColumnName,\n type: TType,\n ): TableBuilder<\n TColumns & Record<TColumnName, Column<TType, TypeMap[TType], TypeMap[TType]>>,\n TRelations\n >;\n\n addColumn<TColumnName extends string, TColumn extends AnyColumn, TType extends keyof TypeMap>(\n ormName: TColumnName,\n colOrType: TColumn | TType,\n ): TableBuilder<TColumns & Record<TColumnName, TColumn>, TRelations> {\n this.#version++;\n\n // Create the column if a type string was provided\n const col = typeof colOrType === \"string\" ? column(colOrType) : colOrType;\n\n // Create a new instance to ensure immutability semantics\n const builder = new TableBuilder<TColumns & Record<TColumnName, TColumn>, TRelations>(\n this.#name,\n );\n builder.#columns = { ...this.#columns, [ormName]: col } as TColumns &\n Record<TColumnName, TColumn>;\n builder.#relations = this.#relations;\n builder.#foreignKeys = this.#foreignKeys;\n builder.#indexes = this.#indexes;\n builder.#version = this.#version;\n builder.#ormName = this.#ormName;\n builder.#operations = this.#operations;\n\n // Set column metadata\n col.ormName = ormName;\n col.name = ormName;\n\n return builder;\n }\n\n /**\n * Create an index on the specified columns. Increments the version counter.\n */\n createIndex<TColumnName extends string & keyof TColumns>(\n name: string,\n columns: TColumnName[],\n options?: { unique?: boolean },\n ): TableBuilder<TColumns, TRelations> {\n this.#version++;\n\n const cols = columns.map((name) => {\n const column = this.#columns[name];\n if (!column) {\n throw new Error(`Unknown column name ${name}`);\n }\n return column;\n });\n\n const unique = options?.unique ?? false;\n addIndexToTable(this.#indexes, name, cols, unique);\n\n // Record the operation\n this.#operations.push({\n type: \"add-index\",\n name,\n columns: columns as string[],\n unique,\n });\n\n return this;\n }\n\n /**\n * Build the final table. This should be called after all columns are added.\n */\n build(): Table<TColumns, TRelations> {\n let idCol: AnyColumn | undefined;\n\n // Use name as ormName if ormName is not set\n const ormName = this.#ormName || this.#name;\n\n const table: Table<TColumns, TRelations> = {\n name: this.#name,\n ormName,\n columns: this.#columns,\n relations: this.#relations,\n foreignKeys: this.#foreignKeys,\n indexes: this.#indexes,\n getColumnByName: (name) => {\n return Object.values(this.#columns).find((c) => c.name === name);\n },\n getIdColumn: () => {\n return idCol!;\n },\n clone: () => {\n const cloneColumns: Record<string, AnyColumn> = {};\n\n for (const [k, v] of Object.entries(this.#columns)) {\n cloneColumns[k] = v.clone();\n }\n\n const builder = new TableBuilder<TColumns, TRelations>(this.#name);\n builder.#columns = cloneColumns as TColumns;\n builder.#relations = this.#relations;\n builder.#foreignKeys = [...this.#foreignKeys];\n builder.#indexes = [...this.#indexes];\n builder.#version = this.#version;\n builder.#ormName = this.#ormName;\n builder.#operations = [...this.#operations];\n\n const cloned = builder.build();\n\n return cloned;\n },\n };\n\n // Set table reference and find id column\n for (const k in this.#columns) {\n const column = this.#columns[k];\n if (!column) {\n continue;\n }\n\n column.table = table;\n if (column instanceof IdColumn) {\n idCol = column;\n }\n }\n\n if (idCol === undefined) {\n throw new Error(`there's no id column in your table ${this.#name}`);\n }\n\n return table;\n }\n\n /**\n * Get the current version of the table builder.\n */\n getVersion(): number {\n return this.#version;\n }\n\n /**\n * Get the operations performed on this table.\n */\n getOperations(): TableOperation[] {\n return this.#operations;\n }\n}\n\n/**\n * Create a new table with callback pattern.\n */\nexport function table<\n TColumns extends Record<string, AnyColumn> = Record<string, AnyColumn>,\n TRelations extends Record<string, AnyRelation> = Record<string, AnyRelation>,\n>(\n name: string,\n callback: (\n builder: TableBuilder<Record<string, AnyColumn>, Record<string, AnyRelation>>,\n ) => TableBuilder<TColumns, TRelations>,\n): Table<TColumns, TRelations> {\n const builder = new TableBuilder(name);\n const result = callback(builder);\n return result.build();\n}\n\nexport interface Schema<TTables extends Record<string, AnyTable> = Record<string, AnyTable>> {\n /**\n * @description The version of the schema, automatically incremented on each change.\n */\n version: number;\n tables: TTables;\n /**\n * @description Operations performed on this schema, in order.\n * Used to generate migrations for specific version ranges.\n */\n operations: SchemaOperation[];\n\n clone: () => Schema<TTables>;\n}\n\nexport class SchemaBuilder<TTables extends Record<string, AnyTable> = Record<string, never>> {\n #tables: TTables;\n #version: number = 0;\n #operations: SchemaOperation[] = [];\n\n constructor() {\n this.#tables = {} as TTables;\n }\n\n /**\n * Add a table to the schema. Increments the version counter.\n */\n addTable<\n TTableName extends string,\n TColumns extends Record<string, AnyColumn>,\n TRelations extends Record<string, AnyRelation>,\n >(\n ormName: TTableName,\n callback: (\n builder: TableBuilder<Record<string, AnyColumn>, Record<string, AnyRelation>>,\n ) => TableBuilder<TColumns, TRelations>,\n ): SchemaBuilder<TTables & Record<TTableName, Table<TColumns, TRelations>>> {\n this.#version++;\n\n const tableBuilder = new TableBuilder(ormName);\n const result = callback(tableBuilder);\n const builtTable = result.build();\n\n // Set table metadata\n builtTable.ormName = ormName;\n\n const builder = new SchemaBuilder<TTables & Record<TTableName, Table<TColumns, TRelations>>>();\n builder.#tables = { ...this.#tables, [ormName]: builtTable } as TTables &\n Record<TTableName, Table<TColumns, TRelations>>;\n\n // Start with existing operations plus the add-table operation\n const newOperations: SchemaOperation[] = [\n ...this.#operations,\n {\n type: \"add-table\",\n tableName: ormName,\n table: builtTable,\n },\n ];\n\n // Promote table operations to schema operations and increment version for each\n const tableOps = result.getOperations();\n for (const tableOp of tableOps) {\n if (tableOp.type === \"add-index\") {\n this.#version++;\n newOperations.push({\n type: \"add-index\",\n tableName: ormName,\n name: tableOp.name,\n columns: tableOp.columns,\n unique: tableOp.unique,\n });\n }\n }\n\n builder.#version = this.#version;\n builder.#operations = newOperations;\n\n return builder;\n }\n\n /**\n * Add a foreign key reference from this table to another table.\n *\n * @param tableName - The table that has the foreign key column\n * @param referenceName - A name for this reference (e.g., \"author\", \"category\")\n * @param config - Configuration specifying the foreign key mapping\n *\n * @example\n * ```ts\n * // Basic foreign key: post -> user\n * schema(s => s\n * .addTable(\"users\", t => t.addColumn(\"id\", idColumn()))\n * .addTable(\"posts\", t => t\n * .addColumn(\"id\", idColumn())\n * .addColumn(\"authorId\", referenceColumn()))\n * .addReference(\"posts\", \"author\", {\n * columns: [\"authorId\"],\n * targetTable: \"users\",\n * targetColumns: [\"id\"],\n * })\n * )\n *\n * // Self-referencing foreign key\n * .addReference(\"users\", \"inviter\", {\n * columns: [\"invitedBy\"],\n * targetTable: \"users\",\n * targetColumns: [\"id\"],\n * })\n *\n * // Multiple foreign keys - call addReference multiple times\n * .addReference(\"posts\", \"author\", {\n * columns: [\"authorId\"],\n * targetTable: \"users\",\n * targetColumns: [\"id\"],\n * })\n * .addReference(\"posts\", \"category\", {\n * columns: [\"categoryId\"],\n * targetTable: \"categories\",\n * targetColumns: [\"id\"],\n * })\n * ```\n */\n addReference<\n TTableName extends string & keyof TTables,\n TReferencedTableName extends string & keyof TTables,\n >(\n tableName: TTableName,\n referenceName: string,\n config: {\n columns: (keyof TTables[TTableName][\"columns\"])[];\n targetTable: TReferencedTableName;\n targetColumns: (keyof TTables[TReferencedTableName][\"columns\"])[];\n },\n ): SchemaBuilder<TTables> {\n this.#version++;\n\n const table = this.#tables[tableName];\n const referencedTable = this.#tables[config.targetTable];\n\n if (!table) {\n throw new Error(`Table ${tableName} not found in schema`);\n }\n if (!referencedTable) {\n throw new Error(`Referenced table ${config.targetTable} not found in schema`);\n }\n\n const { columns, targetColumns } = config;\n\n if (columns.length !== targetColumns.length) {\n throw new Error(\n `Reference ${referenceName}: columns and targetColumns must have the same length`,\n );\n }\n\n // For now, only support single column foreign keys\n if (columns.length !== 1) {\n throw new Error(\n `Reference ${referenceName}: currently only single column foreign keys are supported`,\n );\n }\n\n const columnName = columns[0] as string;\n const targetColumnName = targetColumns[0] as string;\n\n const column = table.columns[columnName];\n const referencedColumn = referencedTable.columns[targetColumnName];\n\n if (!column) {\n throw new Error(`Column ${columnName} not found in table ${tableName}`);\n }\n if (!referencedColumn) {\n throw new Error(`Column ${targetColumnName} not found in table ${config.targetTable}`);\n }\n\n // Create the relation\n const init = new ExplicitRelationInit(\"one\", referencedTable, table);\n init.on.push([columnName, targetColumnName]);\n const relation = init.init(referenceName);\n\n // Add relation and foreign key to the table\n table.relations[referenceName] = relation;\n table.foreignKeys.push(relation.foreignKey);\n\n // Record the operation\n this.#operations.push({\n type: \"add-reference\",\n tableName: tableName as string,\n referenceName,\n config: {\n columns: columns as string[],\n targetTable: config.targetTable as string,\n targetColumns: targetColumns as string[],\n },\n });\n\n return this;\n }\n\n /**\n * Build the final schema. This should be called after all tables are added.\n */\n build(): Schema<TTables> {\n const operations = this.#operations;\n const version = this.#version;\n const tables = this.#tables;\n\n const schema: Schema<TTables> = {\n version,\n tables,\n operations,\n clone: () => {\n const cloneTables: Record<string, AnyTable> = {};\n\n for (const [k, v] of Object.entries(tables)) {\n cloneTables[k] = v.clone();\n }\n\n const builder = new SchemaBuilder<TTables>();\n builder.#tables = cloneTables as TTables;\n builder.#version = version;\n builder.#operations = [...operations];\n\n return builder.build();\n },\n };\n\n return schema;\n }\n\n /**\n * Get the current version of the schema builder.\n */\n getVersion(): number {\n return this.#version;\n }\n}\n\n/**\n * Create a new schema with callback pattern.\n */\nexport function schema<TTables extends Record<string, AnyTable> = Record<string, never>>(\n callback: (builder: SchemaBuilder<Record<string, never>>) => SchemaBuilder<TTables>,\n): Schema<TTables> {\n return callback(new SchemaBuilder()).build();\n}\n\nexport function compileForeignKey(key: ForeignKey) {\n return {\n name: key.name,\n table: key.table.name,\n referencedTable: key.referencedTable.name,\n referencedColumns: key.referencedColumns.map((col) => col.name),\n columns: key.columns.map((col) => col.name),\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"create.js","names":["#externalId","#internalId","#version","#name","#columns","#relations","#indexes","#columnOrder","column","idCol: AnyColumn | undefined","internalIdCol: AnyColumn | undefined","versionCol: AnyColumn | undefined","#ormName","table: Table<TColumns, TRelations, TIndexes>","#tables","#operations","schema","subOperations: TableSubOperation[]","cloneTables: Record<string, AnyTable>","clonedColumns: Record<string, AnyColumn>","clonedCol: AnyColumn"],"sources":["../../src/schema/create.ts"],"sourcesContent":["import { createId } from \"../id\";\n\nexport type AnySchema = Schema<Record<string, AnyTable>>;\n\nexport type AnyRelation = Relation;\n\nexport type AnyTable = Table;\n\nexport type AnyColumn =\n | Column<keyof TypeMap, unknown, unknown>\n | IdColumn<IdColumnType, unknown, unknown>\n | InternalIdColumn<unknown, unknown>\n | VersionColumn<unknown, unknown>;\n/**\n * Sub-operations that can be performed within table operations.\n * These are stored in order within add-table and alter-table operations.\n */\nexport type TableSubOperation =\n | { type: \"add-column\"; columnName: string; column: AnyColumn }\n | { type: \"add-index\"; name: string; columns: string[]; unique: boolean }\n | {\n type: \"add-foreign-key\";\n name: string;\n columns: string[];\n referencedTable: string;\n referencedColumns: string[];\n };\n\n/**\n * Operations that can be performed on a schema during its definition.\n * These are tracked so we can generate migrations for specific version ranges.\n */\nexport type SchemaOperation =\n | {\n type: \"add-table\";\n tableName: string;\n operations: TableSubOperation[]; // Ordered list of sub-operations\n }\n | {\n type: \"alter-table\";\n tableName: string;\n operations: TableSubOperation[]; // Ordered list of sub-operations\n }\n | {\n type: \"add-reference\";\n tableName: string; // The table that has the foreign key\n referenceName: string;\n config: {\n type: \"one\" | \"many\";\n from: { table: string; column: string };\n to: { table: string; column: string };\n };\n };\n\nexport interface ForeignKey {\n name: string;\n table: AnyTable;\n columns: AnyColumn[];\n\n referencedTable: AnyTable;\n referencedColumns: AnyColumn[];\n}\n\nclass RelationInit<\n TRelationType extends RelationType,\n TTables extends Record<string, AnyTable>,\n TTableName extends keyof TTables,\n> {\n type: TRelationType;\n referencedTable: TTables[TTableName];\n referencer: AnyTable;\n on: [string, string][] = [];\n\n constructor(type: TRelationType, referencedTable: TTables[TTableName], referencer: AnyTable) {\n this.type = type;\n this.referencedTable = referencedTable;\n this.referencer = referencer;\n }\n}\n\nexport interface Index<\n TColumns extends AnyColumn[] = AnyColumn[],\n TColumnNames extends readonly string[] = readonly string[],\n> {\n name: string;\n columns: TColumns;\n columnNames: TColumnNames;\n unique: boolean;\n}\n\nexport class ExplicitRelationInit<\n TRelationType extends RelationType,\n TTables extends Record<string, AnyTable>,\n TTableName extends keyof TTables,\n> extends RelationInit<TRelationType, TTables, TTableName> {\n init(ormName: string): Relation<TRelationType, TTables[TTableName]> {\n const id = `${this.referencer.ormName}_${this.referencedTable.ormName}`;\n\n return {\n id,\n on: this.on,\n name: ormName,\n referencer: this.referencer,\n table: this.referencedTable,\n type: this.type,\n };\n }\n}\n\nexport interface Relation<\n TRelationType extends RelationType = RelationType,\n TTable extends AnyTable = AnyTable,\n> {\n id: string;\n name: string;\n type: TRelationType;\n\n table: TTable;\n referencer: AnyTable;\n\n on: [string, string][];\n}\n\nexport interface Table<\n TColumns extends Record<string, AnyColumn> = Record<string, AnyColumn>,\n TRelations extends Record<string, AnyRelation> = Record<string, AnyRelation>,\n TIndexes extends Record<string, Index> = Record<string, Index>,\n> {\n name: string;\n ormName: string;\n\n columns: TColumns;\n relations: TRelations;\n indexes: TIndexes;\n\n /**\n * Get column by name\n */\n getColumnByName: (name: string) => AnyColumn | undefined;\n /**\n * Get the external ID column (user-facing)\n */\n getIdColumn: () => AnyColumn;\n /**\n * Get the internal ID column (database-native, used for joins)\n */\n getInternalIdColumn: () => AnyColumn;\n /**\n * Get the version column (for optimistic concurrency control)\n */\n getVersionColumn: () => AnyColumn;\n}\n\ntype DefaultFunctionMap = {\n date: \"now\";\n timestamp: \"now\";\n string: \"auto\";\n} & Record<`varchar(${number})`, \"auto\">;\n\ntype DefaultFunction<TType extends keyof TypeMap> =\n | (TType extends keyof DefaultFunctionMap ? DefaultFunctionMap[TType] : never)\n | (() => TypeMap[TType]);\n\ntype IdColumnType = `varchar(${number})`;\n\nexport type TypeMap = {\n string: string;\n bigint: bigint;\n integer: number;\n decimal: number;\n bool: boolean;\n json: unknown;\n /**\n * this follows the same specs as Prisma `Bytes` for consistency.\n */\n binary: Uint8Array;\n date: Date;\n timestamp: Date;\n} & Record<`varchar(${number})`, string>;\n\nexport class Column<TType extends keyof TypeMap, TIn = unknown, TOut = unknown> {\n type: TType;\n name: string = \"\";\n ormName: string = \"\";\n isNullable: boolean = false;\n role: \"external-id\" | \"internal-id\" | \"version\" | \"reference\" | \"regular\" = \"regular\";\n isHidden: boolean = false;\n\n default?:\n | { value: TypeMap[TType] }\n | {\n runtime: DefaultFunction<TType>;\n };\n\n tableName: string = \"\";\n\n constructor(type: TType) {\n this.type = type;\n }\n\n nullable<TNullable extends boolean = true>(nullable?: TNullable) {\n this.isNullable = nullable ?? true;\n\n return this as Column<\n TType,\n TNullable extends true ? TIn | null : Exclude<TIn, null>,\n TNullable extends true ? TOut | null : Exclude<TOut, null>\n >;\n }\n\n hidden<THidden extends boolean = true>(hidden?: THidden) {\n this.isHidden = hidden ?? true;\n return this as Column<TType, null, null>;\n }\n\n /**\n * Generate default value on runtime\n */\n defaultTo$(fn: DefaultFunction<TType>): Column<TType, TIn | null, TOut> {\n this.default = { runtime: fn };\n return this;\n }\n\n /**\n * Set a database-level default value\n *\n * For schemaless database, it's still generated on runtime\n */\n defaultTo(value: TypeMap[TType]): Column<TType, TIn | null, TOut> {\n this.default = { value };\n return this;\n }\n\n /**\n * Generate default value for the column on runtime.\n */\n generateDefaultValue(): TypeMap[TType] | undefined {\n if (!this.default) {\n return;\n }\n\n if (\"value\" in this.default) {\n return this.default.value;\n }\n if (this.default.runtime === \"auto\") {\n return createId() as TypeMap[TType];\n }\n if (this.default.runtime === \"now\") {\n return new Date(Date.now()) as TypeMap[TType];\n }\n\n return this.default.runtime();\n }\n\n /**\n * @description This is used for type inference only. Runtime value will be undefined.\n * @internal\n */\n get $in(): TIn {\n return undefined as unknown as TIn;\n }\n\n /**\n * @description This is used for type inference only. Runtime value will be undefined.\n * @internal\n */\n get $out(): TOut {\n return undefined as unknown as TOut;\n }\n}\n\nexport class IdColumn<\n TType extends IdColumnType = IdColumnType,\n TIn = unknown,\n TOut = unknown,\n> extends Column<TType, TIn, TOut> {\n id = true;\n\n override defaultTo$(fn: DefaultFunction<TType>) {\n return super.defaultTo$(fn) as IdColumn<TType, TIn | null, TOut>;\n }\n\n override defaultTo(value: TypeMap[TType]) {\n return super.defaultTo(value) as IdColumn<TType, TIn | null, TOut>;\n }\n}\n\n/**\n * Internal ID column - used for database-native joins and foreign keys.\n * Hidden from user API by default.\n */\nexport class InternalIdColumn<TIn = unknown, TOut = unknown> extends Column<\"bigint\", TIn, TOut> {\n override role = \"internal-id\" as const;\n\n constructor() {\n super(\"bigint\");\n this.hidden();\n }\n}\n\n/**\n * Version column - used for optimistic concurrency control.\n * Automatically incremented on each update.\n */\nexport class VersionColumn<TIn = unknown, TOut = unknown> extends Column<\"integer\", TIn, TOut> {\n override role = \"version\" as const;\n\n constructor() {\n super(\"integer\");\n this.defaultTo(0).hidden();\n }\n}\n\nexport function column<TType extends keyof TypeMap>(\n type: TType,\n): Column<TType, TypeMap[TType], TypeMap[TType]> {\n return new Column(type);\n}\n\n/**\n * Create a reference column that points to another table's internal ID.\n * This is used for foreign key relationships.\n * Always uses bigint to match the internal ID type.\n */\nexport function referenceColumn(): Column<\n \"bigint\",\n string | bigint | FragnoId | FragnoReference,\n FragnoReference\n> {\n const col = new Column<\"bigint\", string | bigint | FragnoId | FragnoReference, FragnoReference>(\n \"bigint\",\n );\n col.role = \"reference\";\n return col;\n}\n\n/**\n * Create an external ID column (user-facing).\n * This is a CUID string that can be auto-generated or user-provided.\n * Input accepts string | FragnoId | null, output returns FragnoId.\n */\nexport function idColumn(): IdColumn<\"varchar(30)\", string | FragnoId | null, FragnoId> {\n const col = new IdColumn<\"varchar(30)\", string | FragnoId | null, FragnoId>(\"varchar(30)\");\n col.role = \"external-id\";\n col.defaultTo$(\"auto\");\n return col;\n}\n\n/**\n * Create an internal ID column (database-native, hidden from user API).\n * Used for joins and foreign keys.\n * @internal\n */\nexport function internalIdColumn(): InternalIdColumn<null, bigint> {\n const col = new InternalIdColumn<null, bigint>();\n col.role = \"internal-id\";\n col.hidden();\n return col;\n}\n\n/**\n * Create a version column for optimistic concurrency control.\n * @internal\n */\nexport function versionColumn(): VersionColumn<null, number> {\n const col = new VersionColumn<null, number>();\n col.role = \"version\";\n col.hidden();\n return col;\n}\n\n/**\n * FragnoId represents a unified ID object that can contain external ID, internal ID, or both.\n * @internal\n *\n * For query inputs: externalId is sufficient (internalId is optional)\n * For query results: both externalId and internalId are provided\n */\nexport class FragnoId {\n readonly #externalId: string;\n readonly #internalId?: bigint;\n readonly #version: number;\n\n constructor({\n externalId,\n internalId,\n version,\n }: {\n externalId: string;\n internalId?: bigint;\n version: number;\n }) {\n this.#externalId = externalId;\n this.#internalId = internalId;\n this.#version = version;\n }\n\n /**\n * Create a FragnoId from just an external ID (for inputs)\n */\n static fromExternal(externalId: string, version: number): FragnoId {\n return new FragnoId({ externalId, version });\n }\n\n get version(): number {\n return this.#version;\n }\n\n get externalId(): string {\n return this.#externalId;\n }\n\n get internalId(): bigint | undefined {\n return this.#internalId;\n }\n\n /**\n * Get the appropriate ID for database operations\n * Prefers internal ID if available, falls back to external ID\n */\n get databaseId(): string | bigint {\n return this.#internalId ?? this.#externalId;\n }\n\n /**\n * Convert to a plain object for serialization\n */\n toJSON(): { externalId: string; internalId?: string } {\n return {\n externalId: this.#externalId,\n internalId: this.#internalId?.toString(),\n };\n }\n\n toString(): string {\n return this.#externalId;\n }\n\n valueOf(): string {\n return this.#externalId;\n }\n}\n\n/**\n * FragnoReference represents a foreign key reference to another table's internal ID.\n * Unlike FragnoId, it only contains the internal ID (bigint) of the referenced record.\n * This is used for reference columns in query results.\n * @internal\n */\nexport class FragnoReference {\n readonly #internalId: bigint;\n\n constructor(internalId: bigint) {\n this.#internalId = internalId;\n }\n\n /**\n * Create a FragnoReference from an internal ID\n */\n static fromInternal(internalId: bigint): FragnoReference {\n return new FragnoReference(internalId);\n }\n\n /**\n * Get the internal ID for database operations\n */\n get internalId(): bigint {\n return this.#internalId;\n }\n}\n\ntype RelationType = \"one\" | \"many\";\n\nexport class TableBuilder<\n TColumns extends Record<string, AnyColumn> = Record<string, AnyColumn>,\n TRelations extends Record<string, AnyRelation> = Record<string, AnyRelation>,\n TIndexes extends Record<string, Index> = Record<string, Index>,\n> {\n #name: string;\n #columns: TColumns;\n #relations: TRelations;\n #indexes: TIndexes;\n #ormName: string = \"\";\n #columnOrder: string[] = [];\n\n constructor(name: string) {\n this.#name = name;\n this.#columns = {} as TColumns;\n this.#relations = {} as TRelations;\n this.#indexes = {} as TIndexes;\n }\n\n // For alterTable to set existing state\n setColumns(columns: TColumns): void {\n this.#columns = { ...columns };\n }\n\n setRelations(relations: TRelations): void {\n this.#relations = { ...relations };\n }\n\n setIndexes(indexes: TIndexes): void {\n this.#indexes = { ...indexes };\n }\n\n // For SchemaBuilder to read collected indexes\n getIndexes(): Index[] {\n return Object.values(this.#indexes) as Index[];\n }\n\n getColumnOrder(): string[] {\n return this.#columnOrder;\n }\n\n /**\n * Add a column to the table.\n */\n addColumn<TColumnName extends string, TColumn extends AnyColumn>(\n ormName: TColumnName,\n col: TColumn,\n ): TableBuilder<TColumns & Record<TColumnName, TColumn>, TRelations, TIndexes>;\n\n /**\n * Add a column to the table with simplified syntax.\n */\n addColumn<TColumnName extends string, TType extends keyof TypeMap>(\n ormName: TColumnName,\n type: TType,\n ): TableBuilder<\n TColumns & Record<TColumnName, Column<TType, TypeMap[TType], TypeMap[TType]>>,\n TRelations,\n TIndexes\n >;\n\n addColumn<TColumnName extends string, TColumn extends AnyColumn, TType extends keyof TypeMap>(\n ormName: TColumnName,\n colOrType: TColumn | TType,\n ): TableBuilder<TColumns & Record<TColumnName, TColumn>, TRelations, TIndexes> {\n // Create the column if a type string was provided\n const col = typeof colOrType === \"string\" ? column(colOrType) : colOrType;\n\n // Set column metadata\n col.ormName = ormName;\n col.name = ormName;\n\n // Add column directly to this builder\n this.#columns[ormName] = col as unknown as TColumns[TColumnName];\n this.#columnOrder.push(ormName);\n\n return this as unknown as TableBuilder<\n TColumns & Record<TColumnName, TColumn>,\n TRelations,\n TIndexes\n >;\n }\n\n /**\n * Create an index on the specified columns.\n */\n createIndex<\n TIndexName extends string,\n const TColumnNames extends readonly (string & keyof TColumns)[],\n >(\n name: TIndexName,\n columns: TColumnNames,\n options?: { unique?: boolean },\n ): TableBuilder<\n TColumns,\n TRelations,\n TIndexes & Record<TIndexName, Index<ColumnsToTuple<TColumns, TColumnNames>, TColumnNames>>\n > {\n const cols = columns.map((colName) => {\n const column = this.#columns[colName];\n if (!column) {\n throw new Error(`Unknown column name ${colName}`);\n }\n return column;\n });\n\n const unique = options?.unique ?? false;\n // Safe: we're adding the index to the internal indexes object\n this.#indexes[name] = {\n name,\n columns: cols,\n columnNames: columns,\n unique,\n } as unknown as TIndexes[TIndexName];\n\n return this as unknown as TableBuilder<\n TColumns,\n TRelations,\n TIndexes & Record<TIndexName, Index<ColumnsToTuple<TColumns, TColumnNames>, TColumnNames>>\n >;\n }\n\n /**\n * Build the final table. This should be called after all columns are added.\n */\n build(): Table<TColumns, TRelations, TIndexes> {\n let idCol: AnyColumn | undefined;\n let internalIdCol: AnyColumn | undefined;\n let versionCol: AnyColumn | undefined;\n\n // TODO: Throw if user manually added version/internalId columns\n\n // Auto-add _internalId and _version columns if not already present\n if (!this.#columns[\"_internalId\"]) {\n const col = internalIdColumn();\n col.ormName = \"_internalId\";\n col.name = \"_internalId\";\n // Safe: we're adding system columns to the internal columns object\n (this.#columns as Record<string, AnyColumn>)[\"_internalId\"] = col;\n }\n\n if (!this.#columns[\"_version\"]) {\n const col = versionColumn();\n col.ormName = \"_version\";\n col.name = \"_version\";\n // Safe: we're adding system columns to the internal columns object\n (this.#columns as Record<string, AnyColumn>)[\"_version\"] = col;\n }\n\n // Use name as ormName if ormName is not set\n const ormName = this.#ormName || this.#name;\n\n const table: Table<TColumns, TRelations, TIndexes> = {\n name: this.#name,\n ormName,\n columns: this.#columns,\n relations: this.#relations,\n indexes: this.#indexes,\n getColumnByName: (name) => {\n return Object.values(this.#columns).find((c) => c.name === name);\n },\n getIdColumn: () => {\n return idCol!;\n },\n getInternalIdColumn: () => {\n return internalIdCol!;\n },\n getVersionColumn: () => {\n return versionCol!;\n },\n };\n\n // Set table reference and find special columns\n for (const k in this.#columns) {\n const column = this.#columns[k];\n if (!column) {\n continue;\n }\n\n column.tableName = table.name;\n if (column instanceof IdColumn || column.role === \"external-id\") {\n idCol = column;\n }\n if (column instanceof InternalIdColumn || column.role === \"internal-id\") {\n internalIdCol = column;\n }\n if (column instanceof VersionColumn || column.role === \"version\") {\n versionCol = column;\n }\n }\n\n if (idCol === undefined) {\n throw new Error(`there's no id column in your table ${this.#name}`);\n }\n if (internalIdCol === undefined) {\n throw new Error(`there's no internal id column in your table ${this.#name}`);\n }\n if (versionCol === undefined) {\n throw new Error(`there's no version column in your table ${this.#name}`);\n }\n\n return table;\n }\n}\n\nexport interface Schema<TTables extends Record<string, AnyTable> = Record<string, AnyTable>> {\n /**\n * @description The version of the schema, automatically incremented on each change.\n */\n version: number;\n tables: TTables;\n /**\n * @description Operations performed on this schema, in order.\n * Used to generate migrations for specific version ranges.\n */\n operations: SchemaOperation[];\n\n clone: () => Schema<TTables>;\n}\n\n/**\n * Utility type for updating a single table's relations in a schema.\n * Used to properly type the return value of addReference.\n */\ntype UpdateTableRelations<\n TTables extends Record<string, AnyTable>,\n TTableName extends keyof TTables,\n TReferenceName extends string,\n TReferencedTableName extends keyof TTables,\n TRelationType extends RelationType = RelationType,\n> = {\n [K in keyof TTables]: K extends TTableName\n ? Table<\n TTables[TTableName][\"columns\"],\n TTables[TTableName][\"relations\"] &\n Record<TReferenceName, Relation<TRelationType, TTables[TReferencedTableName]>>,\n TTables[TTableName][\"indexes\"]\n >\n : TTables[K];\n};\n\n/**\n * Utility type for updating a single table in a schema.\n * Used to properly type the return value of alterTable.\n */\ntype UpdateTable<\n TTables extends Record<string, AnyTable>,\n TTableName extends keyof TTables,\n TNewColumns extends Record<string, AnyColumn>,\n TNewRelations extends Record<string, AnyRelation>,\n TNewIndexes extends Record<string, Index>,\n> = {\n [K in keyof TTables]: K extends TTableName\n ? Table<TNewColumns, TNewRelations, TNewIndexes>\n : TTables[K];\n};\n\n/**\n * Map an array of column names to a tuple of their actual column types\n */\ntype ColumnsToTuple<\n TColumns extends Record<string, AnyColumn>,\n TColumnNames extends readonly (keyof TColumns)[],\n> = {\n [K in keyof TColumnNames]: TColumnNames[K] extends keyof TColumns\n ? TColumns[TColumnNames[K]]\n : never;\n} & AnyColumn[];\n\nexport class SchemaBuilder<TTables extends Record<string, AnyTable> = {}> {\n #tables: TTables;\n #version: number = 0;\n #operations: SchemaOperation[] = [];\n\n constructor(existingSchema?: Schema<TTables>) {\n if (existingSchema) {\n this.#tables = existingSchema.tables;\n this.#version = existingSchema.version;\n this.#operations = [...existingSchema.operations];\n } else {\n this.#tables = {} as TTables;\n }\n }\n\n /**\n * Add an existing schema to this builder.\n * Merges tables and operations from the provided schema.\n *\n * @example\n * ```ts\n * const builder = new SchemaBuilder()\n * .add(userSchema)\n * .add(postSchema)\n * .addTable(\"comments\", ...);\n * ```\n */\n mergeWithExistingSchema<TNewTables extends Record<string, AnyTable>>(\n schema: Schema<TNewTables>,\n ): SchemaBuilder<TTables & TNewTables> {\n this.#tables = { ...this.#tables, ...schema.tables } as TTables & TNewTables;\n this.#operations = [...this.#operations, ...schema.operations];\n this.#version += schema.version;\n\n return this as unknown as SchemaBuilder<TTables & TNewTables>;\n }\n\n /**\n * Add a table to the schema. Increments the version counter.\n */\n addTable<\n TTableName extends string,\n TColumns extends Record<string, AnyColumn>,\n TRelations extends Record<string, AnyRelation>,\n TIndexes extends Record<string, Index> = Record<string, Index>,\n >(\n ormName: TTableName,\n callback: (\n builder: TableBuilder<\n Record<string, AnyColumn>,\n Record<string, AnyRelation>,\n Record<string, Index>\n >,\n ) => TableBuilder<TColumns, TRelations, TIndexes>,\n ): SchemaBuilder<TTables & Record<TTableName, Table<TColumns, TRelations, TIndexes>>> {\n this.#version++;\n\n const tableBuilder = new TableBuilder(ormName);\n const result = callback(tableBuilder);\n const builtTable = result.build();\n builtTable.ormName = ormName;\n\n // Collect sub-operations in order\n const subOperations: TableSubOperation[] = [];\n\n // Add user-defined columns first\n const columnOrder = result.getColumnOrder();\n for (const colName of columnOrder) {\n const col = builtTable.columns[colName];\n subOperations.push({\n type: \"add-column\",\n columnName: colName,\n column: col,\n });\n }\n\n // Add system columns (_internalId and _version) that were auto-added\n if (builtTable.columns[\"_internalId\"]) {\n subOperations.push({\n type: \"add-column\",\n columnName: \"_internalId\",\n column: builtTable.columns[\"_internalId\"],\n });\n }\n if (builtTable.columns[\"_version\"]) {\n subOperations.push({\n type: \"add-column\",\n columnName: \"_version\",\n column: builtTable.columns[\"_version\"],\n });\n }\n\n // Add indexes from builder\n for (const idx of result.getIndexes()) {\n subOperations.push({\n type: \"add-index\",\n name: idx.name,\n columns: idx.columns.map((c) => c.ormName),\n unique: idx.unique,\n });\n }\n\n // Add the add-table operation\n this.#operations.push({\n type: \"add-table\",\n tableName: ormName,\n operations: subOperations,\n });\n\n // Update tables map\n this.#tables = { ...this.#tables, [ormName]: builtTable } as TTables &\n Record<TTableName, Table<TColumns, TRelations, TIndexes>>;\n\n return this as unknown as SchemaBuilder<\n TTables & Record<TTableName, Table<TColumns, TRelations, TIndexes>>\n >;\n }\n\n /**\n * Add a relation between two tables.\n *\n * @param referenceName - A name for this relation (e.g., \"author\", \"posts\")\n * @param config - Configuration specifying the relation type and foreign key mapping\n *\n * @example\n * ```ts\n * // One-to-one or many-to-one: post -> user\n * schema(s => s\n * .addTable(\"users\", t => t.addColumn(\"id\", idColumn()))\n * .addTable(\"posts\", t => t\n * .addColumn(\"id\", idColumn())\n * .addColumn(\"userId\", referenceColumn()))\n * .addReference(\"author\", {\n * type: \"one\",\n * from: { table: \"posts\", column: \"userId\" },\n * to: { table: \"users\", column: \"id\" },\n * })\n * )\n *\n * // One-to-many (inverse relation): user -> posts\n * .addReference(\"posts\", {\n * type: \"many\",\n * from: { table: \"users\", column: \"id\" },\n * to: { table: \"posts\", column: \"userId\" },\n * })\n *\n * // Self-referencing foreign key\n * .addReference(\"inviter\", {\n * type: \"one\",\n * from: { table: \"users\", column: \"invitedBy\" },\n * to: { table: \"users\", column: \"id\" },\n * })\n * ```\n */\n addReference<\n TFromTableName extends string & keyof TTables,\n TToTableName extends string & keyof TTables,\n TReferenceName extends string,\n TRelationType extends RelationType,\n >(\n referenceName: TReferenceName,\n config: {\n type: TRelationType;\n from: {\n table: TFromTableName;\n column: keyof TTables[TFromTableName][\"columns\"];\n };\n to: {\n table: TToTableName;\n column: keyof TTables[TToTableName][\"columns\"];\n };\n },\n ): SchemaBuilder<\n UpdateTableRelations<TTables, TFromTableName, TReferenceName, TToTableName, TRelationType>\n > {\n this.#version++;\n\n const table = this.#tables[config.from.table];\n const referencedTable = this.#tables[config.to.table];\n\n if (!table) {\n throw new Error(`Table ${config.from.table} not found in schema`);\n }\n if (!referencedTable) {\n throw new Error(`Referenced table ${config.to.table} not found in schema`);\n }\n\n const columnName = config.from.column as string;\n const targetColumnName = config.to.column as string;\n\n // Foreign keys always reference internal IDs, not external IDs\n // If user specifies \"id\", translate to \"_internalId\" for the actual FK\n const actualTargetColumnName = targetColumnName === \"id\" ? \"_internalId\" : targetColumnName;\n\n const column = table.columns[columnName];\n const referencedColumn = referencedTable.columns[actualTargetColumnName];\n\n if (!column) {\n throw new Error(`Column ${columnName} not found in table ${config.from.table}`);\n }\n if (!referencedColumn) {\n throw new Error(`Column ${actualTargetColumnName} not found in table ${config.to.table}`);\n }\n\n // Verify that reference columns are bigint (matching internal ID type)\n if (column.role === \"reference\" && column.type !== \"bigint\") {\n throw new Error(\n `Reference column ${columnName} must be of type bigint to match internal ID type`,\n );\n }\n\n // Create the relation (use the user-facing column name for the relation)\n const init = new ExplicitRelationInit(config.type, referencedTable, table);\n init.on.push([columnName, targetColumnName]);\n const relation = init.init(referenceName);\n\n // Add relation to the table\n table.relations[referenceName] = relation;\n\n // Record the operation\n this.#operations.push({\n type: \"add-reference\",\n tableName: config.from.table,\n referenceName,\n config: {\n type: config.type,\n from: { table: config.from.table, column: columnName },\n to: { table: config.to.table, column: actualTargetColumnName },\n },\n });\n\n // Return this with updated type\n // Safe: The relation was added to the table in place and now has the updated relations\n return this as unknown as SchemaBuilder<\n UpdateTableRelations<TTables, TFromTableName, TReferenceName, TToTableName, TRelationType>\n >;\n }\n\n /**\n * Alter an existing table by adding columns or indexes.\n * This is used for append-only schema modifications.\n *\n * @param tableName - The name of the table to modify\n * @param callback - A callback that receives a table builder for adding columns/indexes\n *\n * @example\n * ```ts\n * // Add a new column to an existing table\n * schema(s => s\n * .addTable(\"users\", t => t\n * .addColumn(\"id\", idColumn())\n * .addColumn(\"name\", column(\"string\")))\n * .alterTable(\"users\", t => t\n * .addColumn(\"email\", column(\"string\"))\n * .addColumn(\"age\", column(\"integer\").nullable())\n * .createIndex(\"idx_email\", [\"email\"]))\n * )\n * ```\n */\n alterTable<\n TTableName extends string & keyof TTables,\n TNewColumns extends Record<string, AnyColumn>,\n TNewRelations extends Record<string, AnyRelation>,\n TNewIndexes extends Record<string, Index> = Record<string, Index>,\n >(\n tableName: TTableName,\n callback: (\n builder: TableBuilder<\n TTables[TTableName][\"columns\"],\n TTables[TTableName][\"relations\"],\n Record<string, Index>\n >,\n ) => TableBuilder<TNewColumns, TNewRelations, TNewIndexes>,\n ): SchemaBuilder<UpdateTable<TTables, TTableName, TNewColumns, TNewRelations, TNewIndexes>> {\n const table = this.#tables[tableName];\n\n if (!table) {\n throw new Error(`Table ${tableName} not found in schema`);\n }\n\n // Create builder with existing table state\n const tableBuilder = new TableBuilder(tableName);\n tableBuilder.setColumns(table.columns);\n tableBuilder.setRelations(table.relations);\n tableBuilder.setIndexes(table.indexes);\n\n // Track existing columns and indexes\n const existingColumns = new Set(Object.keys(table.columns));\n const existingIndexes = new Set(Object.keys(table.indexes));\n\n // Apply modifications\n const resultBuilder = callback(\n tableBuilder as TableBuilder<\n TTables[TTableName][\"columns\"],\n TTables[TTableName][\"relations\"],\n Record<string, Index>\n >,\n );\n const newTable = resultBuilder.build();\n\n // Collect sub-operations\n const subOperations: TableSubOperation[] = [];\n\n // Find new columns (preserve order from builder)\n const columnOrder = resultBuilder.getColumnOrder();\n for (const colName of columnOrder) {\n if (!existingColumns.has(colName)) {\n subOperations.push({\n type: \"add-column\",\n columnName: colName,\n column: newTable.columns[colName],\n });\n }\n }\n\n // Add only new indexes\n for (const idx of resultBuilder.getIndexes()) {\n if (!existingIndexes.has(idx.name)) {\n subOperations.push({\n type: \"add-index\",\n name: idx.name,\n columns: idx.columns.map((c) => c.ormName),\n unique: idx.unique,\n });\n }\n }\n\n if (subOperations.length > 0) {\n this.#version++;\n this.#operations.push({\n type: \"alter-table\",\n tableName,\n operations: subOperations,\n });\n }\n\n // Update table reference in schema\n this.#tables[tableName] = newTable as unknown as TTables[TTableName];\n\n // Set table name for all columns\n for (const col of Object.values(newTable.columns)) {\n col.tableName = newTable.name;\n }\n\n return this as unknown as SchemaBuilder<\n UpdateTable<TTables, TTableName, TNewColumns, TNewRelations, TNewIndexes>\n >;\n }\n\n /**\n * Build the final schema. This should be called after all tables are added.\n */\n build(): Schema<TTables> {\n const operations = this.#operations;\n const version = this.#version;\n const tables = this.#tables;\n\n const schema: Schema<TTables> = {\n version,\n tables,\n operations,\n clone: () => {\n const cloneTables: Record<string, AnyTable> = {};\n\n for (const [k, v] of Object.entries(tables)) {\n // Create a new table with cloned columns\n const clonedColumns: Record<string, AnyColumn> = {};\n for (const [colName, col] of Object.entries(v.columns)) {\n // Create a new column with the same properties, preserving the column type\n let clonedCol: AnyColumn;\n if (col instanceof InternalIdColumn) {\n clonedCol = new InternalIdColumn();\n } else if (col instanceof VersionColumn) {\n clonedCol = new VersionColumn();\n } else if (col instanceof IdColumn) {\n clonedCol = new IdColumn(col.type);\n } else {\n clonedCol = new Column(col.type);\n }\n\n clonedCol.name = col.name;\n clonedCol.ormName = col.ormName;\n clonedCol.isNullable = col.isNullable;\n clonedCol.role = col.role;\n clonedCol.isHidden = col.isHidden;\n clonedCol.default = col.default;\n clonedCol.tableName = col.tableName;\n clonedColumns[colName] = clonedCol;\n }\n\n cloneTables[k] = {\n ...v,\n columns: clonedColumns,\n };\n }\n\n return new SchemaBuilder<TTables>({\n version,\n tables: cloneTables as TTables,\n operations: [...operations],\n clone: () => {\n throw new Error(\"Cannot clone during clone\");\n },\n }).build();\n },\n };\n\n return schema;\n }\n\n /**\n * Get the current version of the schema builder.\n */\n getVersion(): number {\n return this.#version;\n }\n}\n\n/**\n * Create a new schema with callback pattern.\n */\nexport function schema<const TTables extends Record<string, AnyTable> = {}>(\n callback: (builder: SchemaBuilder<{}>) => SchemaBuilder<TTables>,\n): Schema<TTables> {\n return callback(new SchemaBuilder()).build();\n}\n\nexport function compileForeignKey(key: ForeignKey, nameType: \"sql\" | \"orm\" = \"orm\") {\n return {\n name: key.name,\n table: nameType === \"sql\" ? key.table.name : key.table.ormName,\n referencedTable: nameType === \"sql\" ? key.referencedTable.name : key.referencedTable.ormName,\n referencedColumns: key.referencedColumns.map((col) =>\n nameType === \"sql\" ? col.name : col.ormName,\n ),\n columns: key.columns.map((col) => (nameType === \"sql\" ? col.name : col.ormName)),\n };\n}\n"],"mappings":";;;AA+DA,IAAM,eAAN,MAIE;CACA;CACA;CACA;CACA,KAAyB,EAAE;CAE3B,YAAY,MAAqB,iBAAsC,YAAsB;AAC3F,OAAK,OAAO;AACZ,OAAK,kBAAkB;AACvB,OAAK,aAAa;;;AActB,IAAa,uBAAb,cAIU,aAAiD;CACzD,KAAK,SAA+D;AAGlE,SAAO;GACL,IAHS,GAAG,KAAK,WAAW,QAAQ,GAAG,KAAK,gBAAgB;GAI5D,IAAI,KAAK;GACT,MAAM;GACN,YAAY,KAAK;GACjB,OAAO,KAAK;GACZ,MAAM,KAAK;GACZ;;;AA2EL,IAAa,SAAb,MAAgF;CAC9E;CACA,OAAe;CACf,UAAkB;CAClB,aAAsB;CACtB,OAA4E;CAC5E,WAAoB;CAEpB;CAMA,YAAoB;CAEpB,YAAY,MAAa;AACvB,OAAK,OAAO;;CAGd,SAA2C,UAAsB;AAC/D,OAAK,aAAa,YAAY;AAE9B,SAAO;;CAOT,OAAuC,QAAkB;AACvD,OAAK,WAAW,UAAU;AAC1B,SAAO;;;;;CAMT,WAAW,IAA6D;AACtE,OAAK,UAAU,EAAE,SAAS,IAAI;AAC9B,SAAO;;;;;;;CAQT,UAAU,OAAwD;AAChE,OAAK,UAAU,EAAE,OAAO;AACxB,SAAO;;;;;CAMT,uBAAmD;AACjD,MAAI,CAAC,KAAK,QACR;AAGF,MAAI,WAAW,KAAK,QAClB,QAAO,KAAK,QAAQ;AAEtB,MAAI,KAAK,QAAQ,YAAY,OAC3B,QAAO,UAAU;AAEnB,MAAI,KAAK,QAAQ,YAAY,MAC3B,QAAO,IAAI,KAAK,KAAK,KAAK,CAAC;AAG7B,SAAO,KAAK,QAAQ,SAAS;;;;;;CAO/B,IAAI,MAAW;;;;;CAQf,IAAI,OAAa;;AAKnB,IAAa,WAAb,cAIU,OAAyB;CACjC,KAAK;CAEL,AAAS,WAAW,IAA4B;AAC9C,SAAO,MAAM,WAAW,GAAG;;CAG7B,AAAS,UAAU,OAAuB;AACxC,SAAO,MAAM,UAAU,MAAM;;;;;;;AAQjC,IAAa,mBAAb,cAAqE,OAA4B;CAC/F,AAAS,OAAO;CAEhB,cAAc;AACZ,QAAM,SAAS;AACf,OAAK,QAAQ;;;;;;;AAQjB,IAAa,gBAAb,cAAkE,OAA6B;CAC7F,AAAS,OAAO;CAEhB,cAAc;AACZ,QAAM,UAAU;AAChB,OAAK,UAAU,EAAE,CAAC,QAAQ;;;AAI9B,SAAgB,OACd,MAC+C;AAC/C,QAAO,IAAI,OAAO,KAAK;;;;;;;AAQzB,SAAgB,kBAId;CACA,MAAM,MAAM,IAAI,OACd,SACD;AACD,KAAI,OAAO;AACX,QAAO;;;;;;;AAQT,SAAgB,WAAwE;CACtF,MAAM,MAAM,IAAI,SAA4D,cAAc;AAC1F,KAAI,OAAO;AACX,KAAI,WAAW,OAAO;AACtB,QAAO;;;;;;;AAQT,SAAgB,mBAAmD;CACjE,MAAM,MAAM,IAAI,kBAAgC;AAChD,KAAI,OAAO;AACX,KAAI,QAAQ;AACZ,QAAO;;;;;;AAOT,SAAgB,gBAA6C;CAC3D,MAAM,MAAM,IAAI,eAA6B;AAC7C,KAAI,OAAO;AACX,KAAI,QAAQ;AACZ,QAAO;;;;;;;;;AAUT,IAAa,WAAb,MAAa,SAAS;CACpB,CAASA;CACT,CAASC;CACT,CAASC;CAET,YAAY,EACV,YACA,YACA,WAKC;AACD,QAAKF,aAAc;AACnB,QAAKC,aAAc;AACnB,QAAKC,UAAW;;;;;CAMlB,OAAO,aAAa,YAAoB,SAA2B;AACjE,SAAO,IAAI,SAAS;GAAE;GAAY;GAAS,CAAC;;CAG9C,IAAI,UAAkB;AACpB,SAAO,MAAKA;;CAGd,IAAI,aAAqB;AACvB,SAAO,MAAKF;;CAGd,IAAI,aAAiC;AACnC,SAAO,MAAKC;;;;;;CAOd,IAAI,aAA8B;AAChC,SAAO,MAAKA,cAAe,MAAKD;;;;;CAMlC,SAAsD;AACpD,SAAO;GACL,YAAY,MAAKA;GACjB,YAAY,MAAKC,YAAa,UAAU;GACzC;;CAGH,WAAmB;AACjB,SAAO,MAAKD;;CAGd,UAAkB;AAChB,SAAO,MAAKA;;;;;;;;;AAUhB,IAAa,kBAAb,MAAa,gBAAgB;CAC3B,CAASC;CAET,YAAY,YAAoB;AAC9B,QAAKA,aAAc;;;;;CAMrB,OAAO,aAAa,YAAqC;AACvD,SAAO,IAAI,gBAAgB,WAAW;;;;;CAMxC,IAAI,aAAqB;AACvB,SAAO,MAAKA;;;AAMhB,IAAa,eAAb,MAIE;CACA;CACA;CACA;CACA;CACA,WAAmB;CACnB,eAAyB,EAAE;CAE3B,YAAY,MAAc;AACxB,QAAKE,OAAQ;AACb,QAAKC,UAAW,EAAE;AAClB,QAAKC,YAAa,EAAE;AACpB,QAAKC,UAAW,EAAE;;CAIpB,WAAW,SAAyB;AAClC,QAAKF,UAAW,EAAE,GAAG,SAAS;;CAGhC,aAAa,WAA6B;AACxC,QAAKC,YAAa,EAAE,GAAG,WAAW;;CAGpC,WAAW,SAAyB;AAClC,QAAKC,UAAW,EAAE,GAAG,SAAS;;CAIhC,aAAsB;AACpB,SAAO,OAAO,OAAO,MAAKA,QAAS;;CAGrC,iBAA2B;AACzB,SAAO,MAAKC;;CAuBd,UACE,SACA,WAC6E;EAE7E,MAAM,MAAM,OAAO,cAAc,WAAW,OAAO,UAAU,GAAG;AAGhE,MAAI,UAAU;AACd,MAAI,OAAO;AAGX,QAAKH,QAAS,WAAW;AACzB,QAAKG,YAAa,KAAK,QAAQ;AAE/B,SAAO;;;;;CAUT,YAIE,MACA,SACA,SAKA;EACA,MAAM,OAAO,QAAQ,KAAK,YAAY;GACpC,MAAMC,WAAS,MAAKJ,QAAS;AAC7B,OAAI,CAACI,SACH,OAAM,IAAI,MAAM,uBAAuB,UAAU;AAEnD,UAAOA;IACP;EAEF,MAAM,SAAS,SAAS,UAAU;AAElC,QAAKF,QAAS,QAAQ;GACpB;GACA,SAAS;GACT,aAAa;GACb;GACD;AAED,SAAO;;;;;CAUT,QAA+C;EAC7C,IAAIG;EACJ,IAAIC;EACJ,IAAIC;AAKJ,MAAI,CAAC,MAAKP,QAAS,gBAAgB;GACjC,MAAM,MAAM,kBAAkB;AAC9B,OAAI,UAAU;AACd,OAAI,OAAO;AAEX,GAAC,MAAKA,QAAuC,iBAAiB;;AAGhE,MAAI,CAAC,MAAKA,QAAS,aAAa;GAC9B,MAAM,MAAM,eAAe;AAC3B,OAAI,UAAU;AACd,OAAI,OAAO;AAEX,GAAC,MAAKA,QAAuC,cAAc;;EAI7D,MAAM,UAAU,MAAKQ,WAAY,MAAKT;EAEtC,MAAMU,QAA+C;GACnD,MAAM,MAAKV;GACX;GACA,SAAS,MAAKC;GACd,WAAW,MAAKC;GAChB,SAAS,MAAKC;GACd,kBAAkB,SAAS;AACzB,WAAO,OAAO,OAAO,MAAKF,QAAS,CAAC,MAAM,MAAM,EAAE,SAAS,KAAK;;GAElE,mBAAmB;AACjB,WAAO;;GAET,2BAA2B;AACzB,WAAO;;GAET,wBAAwB;AACtB,WAAO;;GAEV;AAGD,OAAK,MAAM,KAAK,MAAKA,SAAU;GAC7B,MAAMI,WAAS,MAAKJ,QAAS;AAC7B,OAAI,CAACI,SACH;AAGF,YAAO,YAAY,MAAM;AACzB,OAAIA,oBAAkB,YAAYA,SAAO,SAAS,cAChD,SAAQA;AAEV,OAAIA,oBAAkB,oBAAoBA,SAAO,SAAS,cACxD,iBAAgBA;AAElB,OAAIA,oBAAkB,iBAAiBA,SAAO,SAAS,UACrD,cAAaA;;AAIjB,MAAI,UAAU,OACZ,OAAM,IAAI,MAAM,sCAAsC,MAAKL,OAAQ;AAErE,MAAI,kBAAkB,OACpB,OAAM,IAAI,MAAM,+CAA+C,MAAKA,OAAQ;AAE9E,MAAI,eAAe,OACjB,OAAM,IAAI,MAAM,2CAA2C,MAAKA,OAAQ;AAG1E,SAAO;;;AAoEX,IAAa,gBAAb,MAAa,cAA6D;CACxE;CACA,WAAmB;CACnB,cAAiC,EAAE;CAEnC,YAAY,gBAAkC;AAC5C,MAAI,gBAAgB;AAClB,SAAKW,SAAU,eAAe;AAC9B,SAAKZ,UAAW,eAAe;AAC/B,SAAKa,aAAc,CAAC,GAAG,eAAe,WAAW;QAEjD,OAAKD,SAAU,EAAE;;;;;;;;;;;;;;CAgBrB,wBACE,UACqC;AACrC,QAAKA,SAAU;GAAE,GAAG,MAAKA;GAAS,GAAGE,SAAO;GAAQ;AACpD,QAAKD,aAAc,CAAC,GAAG,MAAKA,YAAa,GAAGC,SAAO,WAAW;AAC9D,QAAKd,WAAYc,SAAO;AAExB,SAAO;;;;;CAMT,SAME,SACA,UAOoF;AACpF,QAAKd;EAGL,MAAM,SAAS,SADM,IAAI,aAAa,QAAQ,CACT;EACrC,MAAM,aAAa,OAAO,OAAO;AACjC,aAAW,UAAU;EAGrB,MAAMe,gBAAqC,EAAE;EAG7C,MAAM,cAAc,OAAO,gBAAgB;AAC3C,OAAK,MAAM,WAAW,aAAa;GACjC,MAAM,MAAM,WAAW,QAAQ;AAC/B,iBAAc,KAAK;IACjB,MAAM;IACN,YAAY;IACZ,QAAQ;IACT,CAAC;;AAIJ,MAAI,WAAW,QAAQ,eACrB,eAAc,KAAK;GACjB,MAAM;GACN,YAAY;GACZ,QAAQ,WAAW,QAAQ;GAC5B,CAAC;AAEJ,MAAI,WAAW,QAAQ,YACrB,eAAc,KAAK;GACjB,MAAM;GACN,YAAY;GACZ,QAAQ,WAAW,QAAQ;GAC5B,CAAC;AAIJ,OAAK,MAAM,OAAO,OAAO,YAAY,CACnC,eAAc,KAAK;GACjB,MAAM;GACN,MAAM,IAAI;GACV,SAAS,IAAI,QAAQ,KAAK,MAAM,EAAE,QAAQ;GAC1C,QAAQ,IAAI;GACb,CAAC;AAIJ,QAAKF,WAAY,KAAK;GACpB,MAAM;GACN,WAAW;GACX,YAAY;GACb,CAAC;AAGF,QAAKD,SAAU;GAAE,GAAG,MAAKA;IAAU,UAAU;GAAY;AAGzD,SAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyCT,aAME,eACA,QAaA;AACA,QAAKZ;EAEL,MAAM,QAAQ,MAAKY,OAAQ,OAAO,KAAK;EACvC,MAAM,kBAAkB,MAAKA,OAAQ,OAAO,GAAG;AAE/C,MAAI,CAAC,MACH,OAAM,IAAI,MAAM,SAAS,OAAO,KAAK,MAAM,sBAAsB;AAEnE,MAAI,CAAC,gBACH,OAAM,IAAI,MAAM,oBAAoB,OAAO,GAAG,MAAM,sBAAsB;EAG5E,MAAM,aAAa,OAAO,KAAK;EAC/B,MAAM,mBAAmB,OAAO,GAAG;EAInC,MAAM,yBAAyB,qBAAqB,OAAO,gBAAgB;EAE3E,MAAMN,WAAS,MAAM,QAAQ;EAC7B,MAAM,mBAAmB,gBAAgB,QAAQ;AAEjD,MAAI,CAACA,SACH,OAAM,IAAI,MAAM,UAAU,WAAW,sBAAsB,OAAO,KAAK,QAAQ;AAEjF,MAAI,CAAC,iBACH,OAAM,IAAI,MAAM,UAAU,uBAAuB,sBAAsB,OAAO,GAAG,QAAQ;AAI3F,MAAIA,SAAO,SAAS,eAAeA,SAAO,SAAS,SACjD,OAAM,IAAI,MACR,oBAAoB,WAAW,mDAChC;EAIH,MAAM,OAAO,IAAI,qBAAqB,OAAO,MAAM,iBAAiB,MAAM;AAC1E,OAAK,GAAG,KAAK,CAAC,YAAY,iBAAiB,CAAC;EAC5C,MAAM,WAAW,KAAK,KAAK,cAAc;AAGzC,QAAM,UAAU,iBAAiB;AAGjC,QAAKO,WAAY,KAAK;GACpB,MAAM;GACN,WAAW,OAAO,KAAK;GACvB;GACA,QAAQ;IACN,MAAM,OAAO;IACb,MAAM;KAAE,OAAO,OAAO,KAAK;KAAO,QAAQ;KAAY;IACtD,IAAI;KAAE,OAAO,OAAO,GAAG;KAAO,QAAQ;KAAwB;IAC/D;GACF,CAAC;AAIF,SAAO;;;;;;;;;;;;;;;;;;;;;;;CA0BT,WAME,WACA,UAO0F;EAC1F,MAAM,QAAQ,MAAKD,OAAQ;AAE3B,MAAI,CAAC,MACH,OAAM,IAAI,MAAM,SAAS,UAAU,sBAAsB;EAI3D,MAAM,eAAe,IAAI,aAAa,UAAU;AAChD,eAAa,WAAW,MAAM,QAAQ;AACtC,eAAa,aAAa,MAAM,UAAU;AAC1C,eAAa,WAAW,MAAM,QAAQ;EAGtC,MAAM,kBAAkB,IAAI,IAAI,OAAO,KAAK,MAAM,QAAQ,CAAC;EAC3D,MAAM,kBAAkB,IAAI,IAAI,OAAO,KAAK,MAAM,QAAQ,CAAC;EAG3D,MAAM,gBAAgB,SACpB,aAKD;EACD,MAAM,WAAW,cAAc,OAAO;EAGtC,MAAMG,gBAAqC,EAAE;EAG7C,MAAM,cAAc,cAAc,gBAAgB;AAClD,OAAK,MAAM,WAAW,YACpB,KAAI,CAAC,gBAAgB,IAAI,QAAQ,CAC/B,eAAc,KAAK;GACjB,MAAM;GACN,YAAY;GACZ,QAAQ,SAAS,QAAQ;GAC1B,CAAC;AAKN,OAAK,MAAM,OAAO,cAAc,YAAY,CAC1C,KAAI,CAAC,gBAAgB,IAAI,IAAI,KAAK,CAChC,eAAc,KAAK;GACjB,MAAM;GACN,MAAM,IAAI;GACV,SAAS,IAAI,QAAQ,KAAK,MAAM,EAAE,QAAQ;GAC1C,QAAQ,IAAI;GACb,CAAC;AAIN,MAAI,cAAc,SAAS,GAAG;AAC5B,SAAKf;AACL,SAAKa,WAAY,KAAK;IACpB,MAAM;IACN;IACA,YAAY;IACb,CAAC;;AAIJ,QAAKD,OAAQ,aAAa;AAG1B,OAAK,MAAM,OAAO,OAAO,OAAO,SAAS,QAAQ,CAC/C,KAAI,YAAY,SAAS;AAG3B,SAAO;;;;;CAQT,QAAyB;EACvB,MAAM,aAAa,MAAKC;EACxB,MAAM,UAAU,MAAKb;EACrB,MAAM,SAAS,MAAKY;AAoDpB,SAlDgC;GAC9B;GACA;GACA;GACA,aAAa;IACX,MAAMI,cAAwC,EAAE;AAEhD,SAAK,MAAM,CAAC,GAAG,MAAM,OAAO,QAAQ,OAAO,EAAE;KAE3C,MAAMC,gBAA2C,EAAE;AACnD,UAAK,MAAM,CAAC,SAAS,QAAQ,OAAO,QAAQ,EAAE,QAAQ,EAAE;MAEtD,IAAIC;AACJ,UAAI,eAAe,iBACjB,aAAY,IAAI,kBAAkB;eACzB,eAAe,cACxB,aAAY,IAAI,eAAe;eACtB,eAAe,SACxB,aAAY,IAAI,SAAS,IAAI,KAAK;UAElC,aAAY,IAAI,OAAO,IAAI,KAAK;AAGlC,gBAAU,OAAO,IAAI;AACrB,gBAAU,UAAU,IAAI;AACxB,gBAAU,aAAa,IAAI;AAC3B,gBAAU,OAAO,IAAI;AACrB,gBAAU,WAAW,IAAI;AACzB,gBAAU,UAAU,IAAI;AACxB,gBAAU,YAAY,IAAI;AAC1B,oBAAc,WAAW;;AAG3B,iBAAY,KAAK;MACf,GAAG;MACH,SAAS;MACV;;AAGH,WAAO,IAAI,cAAuB;KAChC;KACA,QAAQ;KACR,YAAY,CAAC,GAAG,WAAW;KAC3B,aAAa;AACX,YAAM,IAAI,MAAM,4BAA4B;;KAE/C,CAAC,CAAC,OAAO;;GAEb;;;;;CAQH,aAAqB;AACnB,SAAO,MAAKlB;;;;;;AAOhB,SAAgB,OACd,UACiB;AACjB,QAAO,SAAS,IAAI,eAAe,CAAC,CAAC,OAAO;;AAG9C,SAAgB,kBAAkB,KAAiB,WAA0B,OAAO;AAClF,QAAO;EACL,MAAM,IAAI;EACV,OAAO,aAAa,QAAQ,IAAI,MAAM,OAAO,IAAI,MAAM;EACvD,iBAAiB,aAAa,QAAQ,IAAI,gBAAgB,OAAO,IAAI,gBAAgB;EACrF,mBAAmB,IAAI,kBAAkB,KAAK,QAC5C,aAAa,QAAQ,IAAI,OAAO,IAAI,QACrC;EACD,SAAS,IAAI,QAAQ,KAAK,QAAS,aAAa,QAAQ,IAAI,OAAO,IAAI,QAAS;EACjF"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { FragnoId, FragnoReference } from "./create.js";
|
|
2
|
+
|
|
3
|
+
//#region src/schema/serialize.ts
|
|
4
|
+
function schemaToDBType(column, provider) {
|
|
5
|
+
const { type } = column;
|
|
6
|
+
if ("role" in column && column.role === "internal-id") {
|
|
7
|
+
if (provider === "postgresql" || provider === "cockroachdb") return "bigserial";
|
|
8
|
+
if (provider === "mysql") return "bigint";
|
|
9
|
+
if (provider === "sqlite") return "integer";
|
|
10
|
+
if (provider === "mssql") return "bigint";
|
|
11
|
+
}
|
|
12
|
+
if (provider === "sqlite") switch (type) {
|
|
13
|
+
case "integer":
|
|
14
|
+
case "timestamp":
|
|
15
|
+
case "date":
|
|
16
|
+
case "bool": return "integer";
|
|
17
|
+
case "binary":
|
|
18
|
+
case "bigint": return "blob";
|
|
19
|
+
case "json":
|
|
20
|
+
case "string": return "text";
|
|
21
|
+
case "decimal": return "real";
|
|
22
|
+
default: if (type.startsWith("varchar")) return "text";
|
|
23
|
+
}
|
|
24
|
+
if (provider === "mssql") switch (type) {
|
|
25
|
+
case "bool": return "bit";
|
|
26
|
+
case "timestamp": return "datetime";
|
|
27
|
+
case "integer": return "int";
|
|
28
|
+
case "string": return "varchar(max)";
|
|
29
|
+
case "binary": return "varbinary(max)";
|
|
30
|
+
case "json": return "varchar(max)";
|
|
31
|
+
default:
|
|
32
|
+
if (type.startsWith("varchar")) return type;
|
|
33
|
+
return type;
|
|
34
|
+
}
|
|
35
|
+
if (provider === "postgresql" || provider === "cockroachdb") switch (type) {
|
|
36
|
+
case "bool": return "boolean";
|
|
37
|
+
case "json": return "json";
|
|
38
|
+
case "string": return "text";
|
|
39
|
+
case "binary": return "bytea";
|
|
40
|
+
default:
|
|
41
|
+
if (type.startsWith("varchar")) return type;
|
|
42
|
+
return type;
|
|
43
|
+
}
|
|
44
|
+
if (provider === "mysql") switch (type) {
|
|
45
|
+
case "bool": return "boolean";
|
|
46
|
+
case "string": return "text";
|
|
47
|
+
case "binary": return "longblob";
|
|
48
|
+
default:
|
|
49
|
+
if (type.startsWith("varchar")) return type;
|
|
50
|
+
return type;
|
|
51
|
+
}
|
|
52
|
+
throw new Error(`cannot handle ${provider} ${type}`);
|
|
53
|
+
}
|
|
54
|
+
const supportJson = [
|
|
55
|
+
"postgresql",
|
|
56
|
+
"cockroachdb",
|
|
57
|
+
"mysql"
|
|
58
|
+
];
|
|
59
|
+
/**
|
|
60
|
+
* Parse from driver value
|
|
61
|
+
*/
|
|
62
|
+
function deserialize(value, col, provider) {
|
|
63
|
+
if (value === null) return null;
|
|
64
|
+
if (!supportJson.includes(provider) && col.type === "json" && typeof value === "string") return JSON.parse(value);
|
|
65
|
+
if (provider === "sqlite" && (col.type === "timestamp" || col.type === "date") && (typeof value === "number" || typeof value === "string")) return new Date(value);
|
|
66
|
+
if (col.type === "bool" && typeof value === "number") return value === 1;
|
|
67
|
+
if (col.type === "bigint" && value instanceof Buffer) return value.readBigInt64BE(0);
|
|
68
|
+
if (col.type === "bigint" && typeof value === "string") return BigInt(value);
|
|
69
|
+
if (col.type === "binary" && value instanceof Buffer) return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
|
|
70
|
+
return value;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Encode to driver value
|
|
74
|
+
*/
|
|
75
|
+
function serialize(value, col, provider) {
|
|
76
|
+
if (value === null) return null;
|
|
77
|
+
if (value instanceof FragnoReference) return value.internalId;
|
|
78
|
+
if (value instanceof FragnoId) {
|
|
79
|
+
if (col.role === "external-id") return value.externalId;
|
|
80
|
+
if (col.role === "internal-id") {
|
|
81
|
+
if (!value.internalId) throw new Error(`FragnoId must have internalId for internal-id column ${col.name}`);
|
|
82
|
+
return value.internalId;
|
|
83
|
+
}
|
|
84
|
+
if (col.role === "reference") return value.databaseId;
|
|
85
|
+
return value.externalId;
|
|
86
|
+
}
|
|
87
|
+
if (!supportJson.includes(provider) && col.type === "json") return JSON.stringify(value);
|
|
88
|
+
if (provider === "sqlite" && value instanceof Date) return value.getTime();
|
|
89
|
+
if (provider === "sqlite" && typeof value === "boolean") return value ? 1 : 0;
|
|
90
|
+
if (provider === "sqlite" && typeof value === "bigint") {
|
|
91
|
+
const buf = Buffer.alloc(8);
|
|
92
|
+
buf.writeBigInt64BE(value);
|
|
93
|
+
return buf;
|
|
94
|
+
}
|
|
95
|
+
if (col.type === "binary" && value instanceof Uint8Array) return Buffer.from(value);
|
|
96
|
+
return value;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
//#endregion
|
|
100
|
+
export { deserialize, schemaToDBType, serialize };
|
|
101
|
+
//# sourceMappingURL=serialize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serialize.js","names":["supportJson: SQLProvider[]"],"sources":["../../src/schema/serialize.ts"],"sourcesContent":["import type { SQLProvider } from \"../shared/providers\";\nimport type { AnyColumn } from \"./create\";\nimport { FragnoId, FragnoReference } from \"./create\";\n\nexport interface AdditionalColumnMetadata {\n length?: number;\n precision?: number;\n scale?: number;\n}\n\n/**\n * Get the possible column types that the raw DB type can map to.\n */\nexport function dbToSchemaType(\n dbType: string,\n provider: SQLProvider,\n additional: AdditionalColumnMetadata,\n): (AnyColumn[\"type\"] | \"varchar(n)\")[] {\n dbType = dbType.toLowerCase();\n if (provider === \"sqlite\") {\n switch (dbType) {\n case \"integer\":\n return [\"bool\", \"date\", \"timestamp\", \"bigint\", \"integer\"];\n case \"text\":\n return [\"json\", \"string\", \"bigint\", \"varchar(n)\"];\n case \"real\":\n case \"numeric\":\n return [\"decimal\"];\n case \"blob\":\n return [\"bigint\", \"binary\"];\n default:\n return [dbType as AnyColumn[\"type\"]];\n }\n }\n\n if (provider === \"postgresql\" || provider === \"cockroachdb\") {\n switch (dbType) {\n case \"decimal\":\n case \"real\":\n case \"numeric\":\n case \"double precision\":\n return [\"decimal\"];\n case \"timestamp\":\n case \"timestamptz\":\n return [\"timestamp\"];\n case \"varchar\": {\n const len = additional.length;\n if (len != null) {\n return [`varchar(${len})`];\n }\n return [\"string\"];\n }\n case \"text\":\n return [\"string\"];\n case \"boolean\":\n case \"bool\":\n return [\"bool\"];\n case \"bytea\":\n return [\"binary\"];\n default:\n return [dbType as AnyColumn[\"type\"]];\n }\n }\n\n if (provider === \"mysql\") {\n switch (dbType) {\n case \"bool\":\n case \"boolean\":\n return [\"bool\"];\n case \"integer\":\n case \"int\":\n return [\"integer\"];\n case \"decimal\":\n case \"numeric\":\n case \"float\":\n case \"double\":\n return [\"decimal\"];\n case \"datetime\":\n return [\"timestamp\"];\n case \"varchar\": {\n const len = additional.length;\n if (len != null) {\n return [`varchar(${len})`];\n }\n return [\"string\"];\n }\n case \"text\":\n return [\"string\"];\n case \"longblob\":\n case \"blob\":\n case \"mediumblob\":\n case \"tinyblob\":\n return [\"binary\"];\n default:\n return [dbType as AnyColumn[\"type\"]];\n }\n }\n\n if (provider === \"mssql\") {\n switch (dbType) {\n case \"int\":\n return [\"integer\"];\n case \"decimal\":\n case \"float\":\n case \"real\":\n case \"numeric\":\n return [\"decimal\"];\n case \"bit\":\n return [\"bool\"];\n case \"datetime\":\n case \"datetime2\":\n return [\"timestamp\"];\n case \"nvarchar\":\n case \"varchar\": {\n const len = additional.length;\n if (len != null) {\n return [`varchar(${len})`];\n }\n return [\"string\", \"json\"];\n }\n case \"ntext\":\n case \"text\":\n case \"varchar(max)\":\n case \"nvarchar(max)\":\n return [\"string\", \"json\"];\n case \"binary\":\n case \"varbinary\":\n return [\"binary\"];\n default:\n return [dbType as AnyColumn[\"type\"]];\n }\n }\n\n throw new Error(`unhandled database provider: ${provider}`);\n}\n\n/**\n * Database type literals that can be returned by schemaToDBType\n */\nexport type DBTypeLiteral =\n // PostgreSQL/CockroachDB types\n | \"bigserial\"\n | \"serial\"\n | \"boolean\"\n | \"bool\"\n | \"json\"\n | \"text\"\n | \"bytea\"\n | \"timestamp\"\n | \"timestamptz\"\n | \"bigint\"\n | \"integer\"\n | \"decimal\"\n | \"date\"\n // MySQL types\n | \"longblob\"\n | \"datetime\"\n // SQLite types\n | \"blob\"\n | \"real\"\n // MSSQL types\n | \"bit\"\n | \"int\"\n | \"varbinary(max)\"\n | \"varchar(max)\"\n // varchar with length parameter\n | `varchar(${number})`;\n\nexport function schemaToDBType(\n column: AnyColumn | Pick<AnyColumn, \"type\">,\n provider: SQLProvider,\n): DBTypeLiteral {\n const { type } = column;\n\n // Handle internal ID columns with auto-increment\n if (\"role\" in column && column.role === \"internal-id\") {\n if (provider === \"postgresql\" || provider === \"cockroachdb\") {\n return \"bigserial\";\n }\n if (provider === \"mysql\") {\n return \"bigint\";\n }\n if (provider === \"sqlite\") {\n return \"integer\"; // SQLite uses INTEGER for auto-increment\n }\n if (provider === \"mssql\") {\n return \"bigint\";\n }\n }\n\n if (provider === \"sqlite\") {\n switch (type) {\n case \"integer\":\n case \"timestamp\":\n case \"date\":\n case \"bool\":\n return \"integer\";\n case \"binary\":\n case \"bigint\":\n return \"blob\";\n case \"json\":\n case \"string\":\n return \"text\";\n case \"decimal\":\n return \"real\";\n default:\n // sqlite doesn't support varchar\n if (type.startsWith(\"varchar\")) return \"text\";\n }\n }\n\n if (provider === \"mssql\") {\n switch (type) {\n case \"bool\":\n return \"bit\";\n case \"timestamp\":\n return \"datetime\";\n case \"integer\":\n return \"int\";\n case \"string\":\n return \"varchar(max)\";\n case \"binary\":\n return \"varbinary(max)\";\n // only 2025 preview supports JSON natively\n case \"json\":\n return \"varchar(max)\";\n default:\n if (type.startsWith(\"varchar\")) return type as `varchar(${number})`;\n return type;\n }\n }\n\n if (provider === \"postgresql\" || provider === \"cockroachdb\") {\n switch (type) {\n case \"bool\":\n return \"boolean\";\n case \"json\":\n return \"json\";\n case \"string\":\n return \"text\";\n case \"binary\":\n return \"bytea\";\n default:\n if (type.startsWith(\"varchar\")) return type as `varchar(${number})`;\n return type;\n }\n }\n\n if (provider === \"mysql\") {\n switch (type) {\n case \"bool\":\n return \"boolean\";\n case \"string\":\n return \"text\";\n case \"binary\":\n return \"longblob\";\n default:\n if (type.startsWith(\"varchar\")) return type as `varchar(${number})`;\n return type;\n }\n }\n\n throw new Error(`cannot handle ${provider} ${type}`);\n}\n\nconst supportJson: SQLProvider[] = [\"postgresql\", \"cockroachdb\", \"mysql\"];\n\n/**\n * Parse from driver value\n */\nexport function deserialize(value: unknown, col: AnyColumn, provider: SQLProvider) {\n if (value === null) return null;\n\n if (!supportJson.includes(provider) && col.type === \"json\" && typeof value === \"string\") {\n return JSON.parse(value);\n }\n\n if (\n provider === \"sqlite\" &&\n (col.type === \"timestamp\" || col.type === \"date\") &&\n (typeof value === \"number\" || typeof value === \"string\")\n ) {\n return new Date(value);\n }\n\n if (col.type === \"bool\" && typeof value === \"number\") return value === 1;\n\n if (col.type === \"bigint\" && value instanceof Buffer) {\n return value.readBigInt64BE(0);\n }\n\n if (col.type === \"bigint\" && typeof value === \"string\") {\n return BigInt(value);\n }\n\n if (col.type === \"binary\" && value instanceof Buffer) {\n return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);\n }\n\n return value;\n}\n\n/**\n * Encode to driver value\n */\nexport function serialize(value: unknown, col: AnyColumn, provider: SQLProvider) {\n if (value === null) {\n return null;\n }\n\n // Handle FragnoReference objects (for reference columns)\n if (value instanceof FragnoReference) {\n return value.internalId;\n }\n\n // Handle FragnoId objects\n if (value instanceof FragnoId) {\n // For external ID columns, use the external ID\n if (col.role === \"external-id\") {\n return value.externalId;\n }\n // For internal ID columns, use the internal ID (must be present)\n if (col.role === \"internal-id\") {\n if (!value.internalId) {\n throw new Error(`FragnoId must have internalId for internal-id column ${col.name}`);\n }\n return value.internalId;\n }\n // For reference columns, prefer internal ID if available\n if (col.role === \"reference\") {\n return value.databaseId;\n }\n // Default to external ID for other columns\n return value.externalId;\n }\n\n if (!supportJson.includes(provider) && col.type === \"json\") {\n return JSON.stringify(value);\n }\n\n if (provider === \"sqlite\" && value instanceof Date) {\n return value.getTime();\n }\n\n if (provider === \"sqlite\" && typeof value === \"boolean\") return value ? 1 : 0;\n\n if (provider === \"sqlite\" && typeof value === \"bigint\") {\n const buf = Buffer.alloc(8);\n buf.writeBigInt64BE(value);\n return buf;\n }\n\n // most drivers accept Buffer\n if (col.type === \"binary\" && value instanceof Uint8Array) {\n return Buffer.from(value);\n }\n\n return value;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
//#region src/schema-generator/schema-generator.d.ts
|
|
2
|
+
interface GenerateSchemaOptions {
|
|
3
|
+
path: string;
|
|
4
|
+
toVersion?: number;
|
|
5
|
+
fromVersion?: number;
|
|
6
|
+
}
|
|
7
|
+
interface SchemaGenerator {
|
|
8
|
+
generateSchema: (options?: GenerateSchemaOptions) => {
|
|
9
|
+
schema: string;
|
|
10
|
+
path: string;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
//#endregion
|
|
14
|
+
export { SchemaGenerator };
|
|
15
|
+
//# sourceMappingURL=schema-generator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-generator.d.ts","names":[],"sources":["../../src/schema-generator/schema-generator.ts"],"sourcesContent":[],"mappings":";UAAiB,qBAAA;EAAA,IAAA,EAAA,MAAA;EAMA,SAAA,CAAA,EAAA,MAAe;;;UAAf,eAAA;6BACY"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"providers.d.ts","names":[],"sources":["../../src/shared/providers.ts"],"sourcesContent":[],"mappings":";cAAa;KAQD,WAAA,WAAsB"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
//#region src/util/import-generator.ts
|
|
2
|
+
function importGenerator() {
|
|
3
|
+
const names = /* @__PURE__ */ new Set();
|
|
4
|
+
const map = /* @__PURE__ */ new Map();
|
|
5
|
+
return {
|
|
6
|
+
addImport(name, specifier) {
|
|
7
|
+
if (names.has(name)) return;
|
|
8
|
+
names.add(name);
|
|
9
|
+
const list = map.get(specifier) ?? [];
|
|
10
|
+
list.push(name);
|
|
11
|
+
map.set(specifier, list);
|
|
12
|
+
},
|
|
13
|
+
format() {
|
|
14
|
+
const v = [];
|
|
15
|
+
for (const [specifier, names$1] of map) {
|
|
16
|
+
if (names$1.length === 0) continue;
|
|
17
|
+
v.push(`import { ${names$1.join(", ")} } from "${specifier}"`);
|
|
18
|
+
}
|
|
19
|
+
return v.join("\n");
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
//#endregion
|
|
25
|
+
export { importGenerator };
|
|
26
|
+
//# sourceMappingURL=import-generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"import-generator.js","names":["v: string[]","names"],"sources":["../../src/util/import-generator.ts"],"sourcesContent":["export function importGenerator() {\n const names = new Set<string>();\n // specifier -> import name\n const map = new Map<string, string[]>();\n\n return {\n addImport(name: string, specifier: string) {\n if (names.has(name)) {\n return;\n }\n\n names.add(name);\n const list = map.get(specifier) ?? [];\n list.push(name);\n map.set(specifier, list);\n },\n format(): string {\n const v: string[] = [];\n for (const [specifier, names] of map) {\n if (names.length === 0) continue;\n\n v.push(`import { ${names.join(\", \")} } from \"${specifier}\"`);\n }\n\n return v.join(\"\\n\");\n },\n };\n}\n"],"mappings":";AAAA,SAAgB,kBAAkB;CAChC,MAAM,wBAAQ,IAAI,KAAa;CAE/B,MAAM,sBAAM,IAAI,KAAuB;AAEvC,QAAO;EACL,UAAU,MAAc,WAAmB;AACzC,OAAI,MAAM,IAAI,KAAK,CACjB;AAGF,SAAM,IAAI,KAAK;GACf,MAAM,OAAO,IAAI,IAAI,UAAU,IAAI,EAAE;AACrC,QAAK,KAAK,KAAK;AACf,OAAI,IAAI,WAAW,KAAK;;EAE1B,SAAiB;GACf,MAAMA,IAAc,EAAE;AACtB,QAAK,MAAM,CAAC,WAAWC,YAAU,KAAK;AACpC,QAAIA,QAAM,WAAW,EAAG;AAExB,MAAE,KAAK,YAAYA,QAAM,KAAK,KAAK,CAAC,WAAW,UAAU,GAAG;;AAG9D,UAAO,EAAE,KAAK,KAAK;;EAEtB"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
//#region src/util/parse.ts
|
|
2
|
+
const RegexVarchar = /^varchar\((\d+)\)$/;
|
|
3
|
+
function parseVarchar(template) {
|
|
4
|
+
const match = RegexVarchar.exec(template);
|
|
5
|
+
if (!match) throw new Error("Failed to match varchar(n)");
|
|
6
|
+
return Number(match[1]);
|
|
7
|
+
}
|
|
8
|
+
function ident(s, identation = 2) {
|
|
9
|
+
const tab = " ".repeat(identation);
|
|
10
|
+
return s.split("\n").map((v) => tab + v).join("\n");
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
//#endregion
|
|
14
|
+
export { ident, parseVarchar };
|
|
15
|
+
//# sourceMappingURL=parse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.js","names":[],"sources":["../../src/util/parse.ts"],"sourcesContent":["const RegexVarchar = /^varchar\\((\\d+)\\)$/;\n\nexport function parseVarchar(template: string): number {\n const match = RegexVarchar.exec(template);\n if (!match) throw new Error(\"Failed to match varchar(n)\");\n return Number(match[1]);\n}\n\nexport function ident(s: string, identation = 2): string {\n const tab = \" \".repeat(identation);\n\n return s\n .split(\"\\n\")\n .map((v) => tab + v)\n .join(\"\\n\");\n}\n"],"mappings":";AAAA,MAAM,eAAe;AAErB,SAAgB,aAAa,UAA0B;CACrD,MAAM,QAAQ,aAAa,KAAK,SAAS;AACzC,KAAI,CAAC,MAAO,OAAM,IAAI,MAAM,6BAA6B;AACzD,QAAO,OAAO,MAAM,GAAG;;AAGzB,SAAgB,MAAM,GAAW,aAAa,GAAW;CACvD,MAAM,MAAM,IAAI,OAAO,WAAW;AAElC,QAAO,EACJ,MAAM,KAAK,CACX,KAAK,MAAM,MAAM,EAAE,CACnB,KAAK,KAAK"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
//#region src/util/types.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Forces TypeScript to simplify/flatten complex intersection types for better display in IDE hovers
|
|
4
|
+
*/
|
|
5
|
+
type Prettify<T> = { [K in keyof T]: T[K] } & {};
|
|
6
|
+
//#endregion
|
|
7
|
+
export { Prettify };
|
|
8
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","names":[],"sources":["../../src/util/types.ts"],"sourcesContent":[],"mappings":";;AAGA;;AAA4C,KAAhC,QAAgC,CAAA,CAAA,CAAA,GAAA,QAAE,MAAN,CAAM,GAAF,CAAE,CAAA,CAAA,CAAA,EAAC,GAAA,CAAA,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,25 +1,86 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fragno-dev/db",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
|
+
".": {
|
|
7
|
+
"bun": "./src/mod.ts",
|
|
8
|
+
"development": "./src/mod.ts",
|
|
9
|
+
"types": "./dist/mod.d.ts",
|
|
10
|
+
"default": "./dist/mod.js"
|
|
11
|
+
},
|
|
12
|
+
"./id": {
|
|
13
|
+
"bun": "./src/id.ts",
|
|
14
|
+
"development": "./src/id.ts",
|
|
15
|
+
"types": "./dist/id.d.ts",
|
|
16
|
+
"default": "./dist/id.js"
|
|
17
|
+
},
|
|
6
18
|
"./schema": {
|
|
7
19
|
"bun": "./src/schema/create.ts",
|
|
8
20
|
"development": "./src/schema/create.ts",
|
|
9
21
|
"types": "./dist/schema/create.d.ts",
|
|
10
22
|
"default": "./dist/schema/create.js"
|
|
23
|
+
},
|
|
24
|
+
"./query": {
|
|
25
|
+
"bun": "./src/query/query.ts",
|
|
26
|
+
"development": "./src/query/query.ts",
|
|
27
|
+
"types": "./dist/query/query.d.ts",
|
|
28
|
+
"default": "./dist/query/query.js"
|
|
29
|
+
},
|
|
30
|
+
"./adapters/kysely": {
|
|
31
|
+
"bun": "./src/adapters/kysely/kysely-adapter.ts",
|
|
32
|
+
"development": "./src/adapters/kysely/kysely-adapter.ts",
|
|
33
|
+
"types": "./dist/adapters/kysely/kysely-adapter.d.ts",
|
|
34
|
+
"default": "./dist/adapters/kysely/kysely-adapter.js"
|
|
35
|
+
},
|
|
36
|
+
"./adapters/drizzle": {
|
|
37
|
+
"bun": "./src/adapters/drizzle/drizzle-adapter.ts",
|
|
38
|
+
"development": "./src/adapters/drizzle/drizzle-adapter.ts",
|
|
39
|
+
"types": "./dist/adapters/drizzle/drizzle-adapter.d.ts",
|
|
40
|
+
"default": "./dist/adapters/drizzle/drizzle-adapter.js"
|
|
41
|
+
},
|
|
42
|
+
"./unit-of-work": {
|
|
43
|
+
"bun": "./src/query/unit-of-work.ts",
|
|
44
|
+
"development": "./src/query/unit-of-work.ts",
|
|
45
|
+
"types": "./dist/query/unit-of-work.d.ts",
|
|
46
|
+
"default": "./dist/query/unit-of-work.js"
|
|
47
|
+
},
|
|
48
|
+
"./cursor": {
|
|
49
|
+
"bun": "./src/query/cursor.ts",
|
|
50
|
+
"development": "./src/query/cursor.ts",
|
|
51
|
+
"types": "./dist/query/cursor.d.ts",
|
|
52
|
+
"default": "./dist/query/cursor.js"
|
|
53
|
+
},
|
|
54
|
+
"./fragment": {
|
|
55
|
+
"bun": "./src/fragment.ts",
|
|
56
|
+
"development": "./src/fragment.ts",
|
|
57
|
+
"types": "./dist/fragment.d.ts",
|
|
58
|
+
"default": "./dist/fragment.js"
|
|
11
59
|
}
|
|
12
60
|
},
|
|
13
61
|
"scripts": {
|
|
14
62
|
"build": "tsdown",
|
|
15
63
|
"build:watch": "tsdown --watch",
|
|
16
|
-
"types:check": "tsc --noEmit"
|
|
64
|
+
"types:check": "tsc --noEmit",
|
|
65
|
+
"test": "vitest run",
|
|
66
|
+
"test:watch": "vitest --watch"
|
|
17
67
|
},
|
|
18
68
|
"devDependencies": {
|
|
69
|
+
"@electric-sql/pglite": "^0.3.10",
|
|
19
70
|
"@fragno-private/typescript-config": "0.0.1",
|
|
71
|
+
"@fragno-private/vitest-config": "0.0.0",
|
|
72
|
+
"@fragno-dev/core": "0.0.7",
|
|
73
|
+
"@types/bun": "^1.2.23",
|
|
20
74
|
"@types/node": "^22",
|
|
75
|
+
"@vitest/coverage-istanbul": "^3.2.4",
|
|
76
|
+
"drizzle-kit": "^0.31.5",
|
|
77
|
+
"drizzle-orm": "^0.44.6",
|
|
78
|
+
"kysely-pglite": "^0.6.1",
|
|
21
79
|
"vitest": "^3.2.4"
|
|
22
80
|
},
|
|
81
|
+
"peerDependencies": {
|
|
82
|
+
"@fragno-dev/core": "0.0.7"
|
|
83
|
+
},
|
|
23
84
|
"repository": {
|
|
24
85
|
"type": "git",
|
|
25
86
|
"url": "https://github.com/rejot-dev/fragno.git",
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Migrator } from "../migration-engine/create";
|
|
2
|
+
import type { AbstractQuery } from "../query/query";
|
|
3
|
+
import type { SchemaGenerator } from "../schema-generator/schema-generator";
|
|
4
|
+
import type { AnySchema } from "../schema/create";
|
|
5
|
+
|
|
6
|
+
export interface DatabaseAdapter<TUOWConfig = void> {
|
|
7
|
+
/**
|
|
8
|
+
* Get current schema version, undefined if not initialized.
|
|
9
|
+
*/
|
|
10
|
+
getSchemaVersion(namespace: string): Promise<string | undefined>;
|
|
11
|
+
|
|
12
|
+
createQueryEngine: <const T extends AnySchema>(
|
|
13
|
+
schema: T,
|
|
14
|
+
namespace: string,
|
|
15
|
+
) => AbstractQuery<T, TUOWConfig>;
|
|
16
|
+
|
|
17
|
+
createMigrationEngine?: <const T extends AnySchema>(schema: T, namespace: string) => Migrator;
|
|
18
|
+
createSchemaGenerator?: <const T extends AnySchema>(
|
|
19
|
+
schema: T,
|
|
20
|
+
namespace: string,
|
|
21
|
+
) => SchemaGenerator;
|
|
22
|
+
}
|