drizzle-orm 1.0.0-beta.1-bd417c1 → 1.0.0-beta.1-03aea0b

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/gel-core/columns/common.cjs +8 -0
  2. package/gel-core/columns/common.cjs.map +1 -1
  3. package/gel-core/columns/common.d.cts +2 -0
  4. package/gel-core/columns/common.d.ts +2 -0
  5. package/gel-core/columns/common.js +8 -0
  6. package/gel-core/columns/common.js.map +1 -1
  7. package/gel-core/columns/custom.cjs +12 -0
  8. package/gel-core/columns/custom.cjs.map +1 -1
  9. package/gel-core/columns/custom.d.cts +116 -4
  10. package/gel-core/columns/custom.d.ts +116 -4
  11. package/gel-core/columns/custom.js +12 -0
  12. package/gel-core/columns/custom.js.map +1 -1
  13. package/gel-core/dialect.cjs +21 -2
  14. package/gel-core/dialect.cjs.map +1 -1
  15. package/gel-core/dialect.js +22 -3
  16. package/gel-core/dialect.js.map +1 -1
  17. package/mysql-core/columns/custom.cjs +28 -0
  18. package/mysql-core/columns/custom.cjs.map +1 -1
  19. package/mysql-core/columns/custom.d.cts +119 -4
  20. package/mysql-core/columns/custom.d.ts +119 -4
  21. package/mysql-core/columns/custom.js +28 -0
  22. package/mysql-core/columns/custom.js.map +1 -1
  23. package/mysql-core/dialect.cjs +3 -0
  24. package/mysql-core/dialect.cjs.map +1 -1
  25. package/mysql-core/dialect.js +3 -0
  26. package/mysql-core/dialect.js.map +1 -1
  27. package/package.json +37 -37
  28. package/pg-core/columns/common.cjs +8 -0
  29. package/pg-core/columns/common.cjs.map +1 -1
  30. package/pg-core/columns/common.d.cts +1 -0
  31. package/pg-core/columns/common.d.ts +1 -0
  32. package/pg-core/columns/common.js +8 -0
  33. package/pg-core/columns/common.js.map +1 -1
  34. package/pg-core/columns/custom.cjs +27 -0
  35. package/pg-core/columns/custom.cjs.map +1 -1
  36. package/pg-core/columns/custom.d.cts +118 -4
  37. package/pg-core/columns/custom.d.ts +118 -4
  38. package/pg-core/columns/custom.js +27 -0
  39. package/pg-core/columns/custom.js.map +1 -1
  40. package/pg-core/dialect.cjs +7 -3
  41. package/pg-core/dialect.cjs.map +1 -1
  42. package/pg-core/dialect.js +7 -3
  43. package/pg-core/dialect.js.map +1 -1
  44. package/relations.cjs +1 -1
  45. package/relations.cjs.map +1 -1
  46. package/relations.js +1 -1
  47. package/relations.js.map +1 -1
  48. package/singlestore-core/columns/custom.cjs +28 -0
  49. package/singlestore-core/columns/custom.cjs.map +1 -1
  50. package/singlestore-core/columns/custom.d.cts +119 -4
  51. package/singlestore-core/columns/custom.d.ts +119 -4
  52. package/singlestore-core/columns/custom.js +28 -0
  53. package/singlestore-core/columns/custom.js.map +1 -1
  54. package/sql/sql.cjs.map +1 -1
  55. package/sql/sql.d.cts +1 -0
  56. package/sql/sql.d.ts +1 -0
  57. package/sql/sql.js.map +1 -1
  58. package/sqlite-core/columns/custom.cjs +27 -0
  59. package/sqlite-core/columns/custom.cjs.map +1 -1
  60. package/sqlite-core/columns/custom.d.cts +119 -4
  61. package/sqlite-core/columns/custom.d.ts +119 -4
  62. package/sqlite-core/columns/custom.js +27 -0
  63. package/sqlite-core/columns/custom.js.map +1 -1
  64. package/sqlite-core/dialect.cjs +3 -0
  65. package/sqlite-core/dialect.cjs.map +1 -1
  66. package/sqlite-core/dialect.js +3 -0
  67. package/sqlite-core/dialect.js.map +1 -1
  68. package/version.cjs +1 -1
  69. package/version.d.cts +1 -1
  70. package/version.d.ts +1 -1
  71. package/version.js +1 -1
@@ -46,11 +46,15 @@ class SQLiteCustomColumn extends import_common.SQLiteColumn {
46
46
  sqlName;
47
47
  mapTo;
48
48
  mapFrom;
49
+ mapJson;
50
+ forJsonSelect;
49
51
  constructor(table, config) {
50
52
  super(table, config);
51
53
  this.sqlName = config.customTypeParams.dataType(config.fieldConfig);
52
54
  this.mapTo = config.customTypeParams.toDriver;
53
55
  this.mapFrom = config.customTypeParams.fromDriver;
56
+ this.mapJson = config.customTypeParams.fromJson;
57
+ this.forJsonSelect = config.customTypeParams.forJsonSelect;
54
58
  }
55
59
  getSQLType() {
56
60
  return this.sqlName;
@@ -58,6 +62,29 @@ class SQLiteCustomColumn extends import_common.SQLiteColumn {
58
62
  mapFromDriverValue(value) {
59
63
  return typeof this.mapFrom === "function" ? this.mapFrom(value) : value;
60
64
  }
65
+ mapFromJsonValue(value) {
66
+ return typeof this.mapJson === "function" ? this.mapJson(value) : this.mapFromDriverValue(value);
67
+ }
68
+ jsonSelectIdentifier(identifier, sql) {
69
+ if (typeof this.forJsonSelect === "function")
70
+ return this.forJsonSelect(identifier, sql);
71
+ const rawType = this.getSQLType().toLowerCase();
72
+ const parenPos = rawType.indexOf("(");
73
+ const type = parenPos + 1 ? rawType.slice(0, parenPos) : rawType;
74
+ switch (type) {
75
+ case "numeric":
76
+ case "decimal":
77
+ case "bigint": {
78
+ return sql`cast(${identifier} as text)`;
79
+ }
80
+ case "blob": {
81
+ return sql`hex(${identifier})`;
82
+ }
83
+ default: {
84
+ return identifier;
85
+ }
86
+ }
87
+ }
61
88
  mapToDriverValue(value) {
62
89
  return typeof this.mapTo === "function" ? this.mapTo(value) : value;
63
90
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/sqlite-core/columns/custom.ts"],"sourcesContent":["import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts';\nimport type { ColumnBaseConfig } from '~/column.ts';\nimport { entityKind } from '~/entity.ts';\nimport type { SQL } from '~/sql/sql.ts';\nimport type { AnySQLiteTable } from '~/sqlite-core/table.ts';\nimport { type Equal, getColumnNameAndConfig } from '~/utils.ts';\nimport { SQLiteColumn, SQLiteColumnBuilder } from './common.ts';\n\nexport type ConvertCustomConfig<TName extends string, T extends Partial<CustomTypeValues>> =\n\t& {\n\t\tname: TName;\n\t\tdataType: 'custom';\n\t\tcolumnType: 'SQLiteCustomColumn';\n\t\tdata: T['data'];\n\t\tdriverParam: T['driverData'];\n\t\tenumValues: undefined;\n\t}\n\t& (T['notNull'] extends true ? { notNull: true } : {})\n\t& (T['default'] extends true ? { hasDefault: true } : {});\n\nexport interface SQLiteCustomColumnInnerConfig {\n\tcustomTypeValues: CustomTypeValues;\n}\n\nexport class SQLiteCustomColumnBuilder<T extends ColumnBuilderBaseConfig<'custom', 'SQLiteCustomColumn'>>\n\textends SQLiteColumnBuilder<\n\t\tT,\n\t\t{\n\t\t\tfieldConfig: CustomTypeValues['config'];\n\t\t\tcustomTypeParams: CustomTypeParams<any>;\n\t\t},\n\t\t{\n\t\t\tsqliteColumnBuilderBrand: 'SQLiteCustomColumnBuilderBrand';\n\t\t}\n\t>\n{\n\tstatic override readonly [entityKind]: string = 'SQLiteCustomColumnBuilder';\n\n\tconstructor(\n\t\tname: T['name'],\n\t\tfieldConfig: CustomTypeValues['config'],\n\t\tcustomTypeParams: CustomTypeParams<any>,\n\t) {\n\t\tsuper(name, 'custom', 'SQLiteCustomColumn');\n\t\tthis.config.fieldConfig = fieldConfig;\n\t\tthis.config.customTypeParams = customTypeParams;\n\t}\n\n\t/** @internal */\n\tbuild<TTableName extends string>(\n\t\ttable: AnySQLiteTable<{ name: TTableName }>,\n\t): SQLiteCustomColumn<MakeColumnConfig<T, TTableName>> {\n\t\treturn new SQLiteCustomColumn<MakeColumnConfig<T, TTableName>>(\n\t\t\ttable,\n\t\t\tthis.config as ColumnBuilderRuntimeConfig<any, any>,\n\t\t);\n\t}\n}\n\nexport class SQLiteCustomColumn<T extends ColumnBaseConfig<'custom', 'SQLiteCustomColumn'>> extends SQLiteColumn<T> {\n\tstatic override readonly [entityKind]: string = 'SQLiteCustomColumn';\n\n\tprivate sqlName: string;\n\tprivate mapTo?: (value: T['data']) => T['driverParam'];\n\tprivate mapFrom?: (value: T['driverParam']) => T['data'];\n\n\tconstructor(\n\t\ttable: AnySQLiteTable<{ name: T['tableName'] }>,\n\t\tconfig: SQLiteCustomColumnBuilder<T>['config'],\n\t) {\n\t\tsuper(table, config);\n\t\tthis.sqlName = config.customTypeParams.dataType(config.fieldConfig);\n\t\tthis.mapTo = config.customTypeParams.toDriver;\n\t\tthis.mapFrom = config.customTypeParams.fromDriver;\n\t}\n\n\tgetSQLType(): string {\n\t\treturn this.sqlName;\n\t}\n\n\toverride mapFromDriverValue(value: T['driverParam']): T['data'] {\n\t\treturn typeof this.mapFrom === 'function' ? this.mapFrom(value) : value as T['data'];\n\t}\n\n\toverride mapToDriverValue(value: T['data']): T['driverParam'] {\n\t\treturn typeof this.mapTo === 'function' ? this.mapTo(value) : value as T['data'];\n\t}\n}\n\nexport type CustomTypeValues = {\n\t/**\n\t * Required type for custom column, that will infer proper type model\n\t *\n\t * Examples:\n\t *\n\t * If you want your column to be `string` type after selecting/or on inserting - use `data: string`. Like `text`, `varchar`\n\t *\n\t * If you want your column to be `number` type after selecting/or on inserting - use `data: number`. Like `integer`\n\t */\n\tdata: unknown;\n\n\t/**\n\t * Type helper, that represents what type database driver is accepting for specific database data type\n\t */\n\tdriverData?: unknown;\n\n\t/**\n\t * What config type should be used for {@link CustomTypeParams} `dataType` generation\n\t */\n\tconfig?: Record<string, any>;\n\n\t/**\n\t * Whether the config argument should be required or not\n\t * @default false\n\t */\n\tconfigRequired?: boolean;\n\n\t/**\n\t * If your custom data type should be notNull by default you can use `notNull: true`\n\t *\n\t * @example\n\t * const customSerial = customType<{ data: number, notNull: true, default: true }>({\n\t * \t dataType() {\n\t * \t return 'serial';\n\t * },\n\t * });\n\t */\n\tnotNull?: boolean;\n\n\t/**\n\t * If your custom data type has default you can use `default: true`\n\t *\n\t * @example\n\t * const customSerial = customType<{ data: number, notNull: true, default: true }>({\n\t * \t dataType() {\n\t * \t return 'serial';\n\t * },\n\t * });\n\t */\n\tdefault?: boolean;\n};\n\nexport interface CustomTypeParams<T extends CustomTypeValues> {\n\t/**\n\t * Database data type string representation, that is used for migrations\n\t * @example\n\t * ```\n\t * `jsonb`, `text`\n\t * ```\n\t *\n\t * If database data type needs additional params you can use them from `config` param\n\t * @example\n\t * ```\n\t * `varchar(256)`, `numeric(2,3)`\n\t * ```\n\t *\n\t * To make `config` be of specific type please use config generic in {@link CustomTypeValues}\n\t *\n\t * @example\n\t * Usage example\n\t * ```\n\t * dataType() {\n\t * return 'boolean';\n\t * },\n\t * ```\n\t * Or\n\t * ```\n\t * dataType(config) {\n\t * \t return typeof config.length !== 'undefined' ? `varchar(${config.length})` : `varchar`;\n\t * \t }\n\t * ```\n\t */\n\tdataType: (config: T['config'] | (Equal<T['configRequired'], true> extends true ? never : undefined)) => string;\n\n\t/**\n\t * Optional mapping function, between user input and driver\n\t * @example\n\t * For example, when using jsonb we need to map JS/TS object to string before writing to database\n\t * ```\n\t * toDriver(value: TData): string {\n\t * \t return JSON.stringify(value);\n\t * }\n\t * ```\n\t */\n\ttoDriver?: (value: T['data']) => T['driverData'] | SQL;\n\n\t/**\n\t * Optional mapping function, that is responsible for data mapping from database to JS/TS code\n\t * @example\n\t * For example, when using timestamp we need to map string Date representation to JS Date\n\t * ```\n\t * fromDriver(value: string): Date {\n\t * \treturn new Date(value);\n\t * },\n\t * ```\n\t */\n\tfromDriver?: (value: T['driverData']) => T['data'];\n}\n\n/**\n * Custom sqlite database data type generator\n */\nexport function customType<T extends CustomTypeValues = CustomTypeValues>(\n\tcustomTypeParams: CustomTypeParams<T>,\n): Equal<T['configRequired'], true> extends true ? {\n\t\t<TConfig extends Record<string, any> & T['config']>(\n\t\t\tfieldConfig: TConfig,\n\t\t): SQLiteCustomColumnBuilder<ConvertCustomConfig<'', T>>;\n\t\t<TName extends string>(\n\t\t\tdbName: TName,\n\t\t\tfieldConfig: T['config'],\n\t\t): SQLiteCustomColumnBuilder<ConvertCustomConfig<TName, T>>;\n\t}\n\t: {\n\t\t(): SQLiteCustomColumnBuilder<ConvertCustomConfig<'', T>>;\n\t\t<TConfig extends Record<string, any> & T['config']>(\n\t\t\tfieldConfig?: TConfig,\n\t\t): SQLiteCustomColumnBuilder<ConvertCustomConfig<'', T>>;\n\t\t<TName extends string>(\n\t\t\tdbName: TName,\n\t\t\tfieldConfig?: T['config'],\n\t\t): SQLiteCustomColumnBuilder<ConvertCustomConfig<TName, T>>;\n\t}\n{\n\treturn <TName extends string>(\n\t\ta?: TName | T['config'],\n\t\tb?: T['config'],\n\t): SQLiteCustomColumnBuilder<ConvertCustomConfig<TName, T>> => {\n\t\tconst { name, config } = getColumnNameAndConfig<T['config']>(a, b);\n\t\treturn new SQLiteCustomColumnBuilder(\n\t\t\tname as ConvertCustomConfig<TName, T>['name'],\n\t\t\tconfig,\n\t\t\tcustomTypeParams,\n\t\t);\n\t};\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,oBAA2B;AAG3B,mBAAmD;AACnD,oBAAkD;AAkB3C,MAAM,kCACJ,kCAUT;AAAA,EACC,QAA0B,wBAAU,IAAY;AAAA,EAEhD,YACC,MACA,aACA,kBACC;AACD,UAAM,MAAM,UAAU,oBAAoB;AAC1C,SAAK,OAAO,cAAc;AAC1B,SAAK,OAAO,mBAAmB;AAAA,EAChC;AAAA;AAAA,EAGA,MACC,OACsD;AACtD,WAAO,IAAI;AAAA,MACV;AAAA,MACA,KAAK;AAAA,IACN;AAAA,EACD;AACD;AAEO,MAAM,2BAAuF,2BAAgB;AAAA,EACnH,QAA0B,wBAAU,IAAY;AAAA,EAExC;AAAA,EACA;AAAA,EACA;AAAA,EAER,YACC,OACA,QACC;AACD,UAAM,OAAO,MAAM;AACnB,SAAK,UAAU,OAAO,iBAAiB,SAAS,OAAO,WAAW;AAClE,SAAK,QAAQ,OAAO,iBAAiB;AACrC,SAAK,UAAU,OAAO,iBAAiB;AAAA,EACxC;AAAA,EAEA,aAAqB;AACpB,WAAO,KAAK;AAAA,EACb;AAAA,EAES,mBAAmB,OAAoC;AAC/D,WAAO,OAAO,KAAK,YAAY,aAAa,KAAK,QAAQ,KAAK,IAAI;AAAA,EACnE;AAAA,EAES,iBAAiB,OAAoC;AAC7D,WAAO,OAAO,KAAK,UAAU,aAAa,KAAK,MAAM,KAAK,IAAI;AAAA,EAC/D;AACD;AAmHO,SAAS,WACf,kBAoBD;AACC,SAAO,CACN,GACA,MAC8D;AAC9D,UAAM,EAAE,MAAM,OAAO,QAAI,qCAAoC,GAAG,CAAC;AACjE,WAAO,IAAI;AAAA,MACV;AAAA,MACA;AAAA,MACA;AAAA,IACD;AAAA,EACD;AACD;","names":[]}
1
+ {"version":3,"sources":["../../../src/sqlite-core/columns/custom.ts"],"sourcesContent":["import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts';\nimport type { ColumnBaseConfig } from '~/column.ts';\nimport { entityKind } from '~/entity.ts';\nimport type { SQL, SQLGenerator } from '~/sql/sql.ts';\nimport type { AnySQLiteTable } from '~/sqlite-core/table.ts';\nimport { type Equal, getColumnNameAndConfig } from '~/utils.ts';\nimport { SQLiteColumn, SQLiteColumnBuilder } from './common.ts';\n\nexport type ConvertCustomConfig<TName extends string, T extends Partial<CustomTypeValues>> =\n\t& {\n\t\tname: TName;\n\t\tdataType: 'custom';\n\t\tcolumnType: 'SQLiteCustomColumn';\n\t\tdata: T['data'];\n\t\tdriverParam: T['driverData'];\n\t\tenumValues: undefined;\n\t}\n\t& (T['notNull'] extends true ? { notNull: true } : {})\n\t& (T['default'] extends true ? { hasDefault: true } : {});\n\nexport interface SQLiteCustomColumnInnerConfig {\n\tcustomTypeValues: CustomTypeValues;\n}\n\nexport class SQLiteCustomColumnBuilder<T extends ColumnBuilderBaseConfig<'custom', 'SQLiteCustomColumn'>>\n\textends SQLiteColumnBuilder<\n\t\tT,\n\t\t{\n\t\t\tfieldConfig: CustomTypeValues['config'];\n\t\t\tcustomTypeParams: CustomTypeParams<any>;\n\t\t},\n\t\t{\n\t\t\tsqliteColumnBuilderBrand: 'SQLiteCustomColumnBuilderBrand';\n\t\t}\n\t>\n{\n\tstatic override readonly [entityKind]: string = 'SQLiteCustomColumnBuilder';\n\n\tconstructor(\n\t\tname: T['name'],\n\t\tfieldConfig: CustomTypeValues['config'],\n\t\tcustomTypeParams: CustomTypeParams<any>,\n\t) {\n\t\tsuper(name, 'custom', 'SQLiteCustomColumn');\n\t\tthis.config.fieldConfig = fieldConfig;\n\t\tthis.config.customTypeParams = customTypeParams;\n\t}\n\n\t/** @internal */\n\tbuild<TTableName extends string>(\n\t\ttable: AnySQLiteTable<{ name: TTableName }>,\n\t): SQLiteCustomColumn<MakeColumnConfig<T, TTableName>> {\n\t\treturn new SQLiteCustomColumn<MakeColumnConfig<T, TTableName>>(\n\t\t\ttable,\n\t\t\tthis.config as ColumnBuilderRuntimeConfig<any, any>,\n\t\t);\n\t}\n}\n\nexport class SQLiteCustomColumn<T extends ColumnBaseConfig<'custom', 'SQLiteCustomColumn'>> extends SQLiteColumn<T> {\n\tstatic override readonly [entityKind]: string = 'SQLiteCustomColumn';\n\n\tprivate sqlName: string;\n\tprivate mapTo?: (value: T['data']) => T['driverParam'];\n\tprivate mapFrom?: (value: T['driverParam']) => T['data'];\n\tprivate mapJson?: (value: unknown) => T['data'];\n\tprivate forJsonSelect?: (name: SQL, sql: SQLGenerator) => SQL;\n\n\tconstructor(\n\t\ttable: AnySQLiteTable<{ name: T['tableName'] }>,\n\t\tconfig: SQLiteCustomColumnBuilder<T>['config'],\n\t) {\n\t\tsuper(table, config);\n\t\tthis.sqlName = config.customTypeParams.dataType(config.fieldConfig);\n\t\tthis.mapTo = config.customTypeParams.toDriver;\n\t\tthis.mapFrom = config.customTypeParams.fromDriver;\n\t\tthis.mapJson = config.customTypeParams.fromJson;\n\t\tthis.forJsonSelect = config.customTypeParams.forJsonSelect;\n\t}\n\n\tgetSQLType(): string {\n\t\treturn this.sqlName;\n\t}\n\n\toverride mapFromDriverValue(value: T['driverParam']): T['data'] {\n\t\treturn typeof this.mapFrom === 'function' ? this.mapFrom(value) : value as T['data'];\n\t}\n\n\tmapFromJsonValue(value: unknown): T['data'] {\n\t\treturn typeof this.mapJson === 'function' ? this.mapJson(value) : this.mapFromDriverValue(value) as T['data'];\n\t}\n\n\tjsonSelectIdentifier(identifier: SQL, sql: SQLGenerator): SQL {\n\t\tif (typeof this.forJsonSelect === 'function') return this.forJsonSelect(identifier, sql);\n\n\t\tconst rawType = this.getSQLType().toLowerCase();\n\t\tconst parenPos = rawType.indexOf('(');\n\t\tconst type = (parenPos + 1) ? rawType.slice(0, parenPos) : rawType;\n\n\t\tswitch (type) {\n\t\t\tcase 'numeric':\n\t\t\tcase 'decimal':\n\t\t\tcase 'bigint': {\n\t\t\t\treturn sql`cast(${identifier} as text)`;\n\t\t\t}\n\t\t\tcase 'blob': {\n\t\t\t\treturn sql`hex(${identifier})`;\n\t\t\t}\n\t\t\tdefault: {\n\t\t\t\treturn identifier;\n\t\t\t}\n\t\t}\n\t}\n\n\toverride mapToDriverValue(value: T['data']): T['driverParam'] {\n\t\treturn typeof this.mapTo === 'function' ? this.mapTo(value) : value as T['data'];\n\t}\n}\n\nexport type CustomTypeValues = {\n\t/**\n\t * Required type for custom column, that will infer proper type model\n\t *\n\t * Examples:\n\t *\n\t * If you want your column to be `string` type after selecting/or on inserting - use `data: string`. Like `text`, `varchar`\n\t *\n\t * If you want your column to be `number` type after selecting/or on inserting - use `data: number`. Like `integer`\n\t */\n\tdata: unknown;\n\n\t/**\n\t * Type helper, that represents what type database driver is accepting for specific database data type\n\t */\n\tdriverData?: unknown;\n\n\t/**\n\t * Type helper, that represents what type database driver is returning for specific database data type\n\t *\n\t * Needed only in case driver's output and input for type differ\n\t *\n\t * @default\n\t * Defaults to `driverData`\n\t */\n\tdriverOutput?: unknown;\n\n\t/**\n\t * Type helper, that represents what type field returns after being aggregated to JSON\n\t */\n\tjsonData?: unknown;\n\n\t/**\n\t * What config type should be used for {@link CustomTypeParams} `dataType` generation\n\t */\n\tconfig?: Record<string, any>;\n\n\t/**\n\t * Whether the config argument should be required or not\n\t * @default false\n\t */\n\tconfigRequired?: boolean;\n\n\t/**\n\t * If your custom data type should be notNull by default you can use `notNull: true`\n\t *\n\t * @example\n\t * const customSerial = customType<{ data: number, notNull: true, default: true }>({\n\t * \t dataType() {\n\t * \t return 'serial';\n\t * },\n\t * });\n\t */\n\tnotNull?: boolean;\n\n\t/**\n\t * If your custom data type has default you can use `default: true`\n\t *\n\t * @example\n\t * const customSerial = customType<{ data: number, notNull: true, default: true }>({\n\t * \t dataType() {\n\t * \t return 'serial';\n\t * },\n\t * });\n\t */\n\tdefault?: boolean;\n};\n\nexport interface CustomTypeParams<T extends CustomTypeValues> {\n\t/**\n\t * Database data type string representation, that is used for migrations\n\t * @example\n\t * ```\n\t * `jsonb`, `text`\n\t * ```\n\t *\n\t * If database data type needs additional params you can use them from `config` param\n\t * @example\n\t * ```\n\t * `varchar(256)`, `numeric(2,3)`\n\t * ```\n\t *\n\t * To make `config` be of specific type please use config generic in {@link CustomTypeValues}\n\t *\n\t * @example\n\t * Usage example\n\t * ```\n\t * dataType() {\n\t * return 'boolean';\n\t * },\n\t * ```\n\t * Or\n\t * ```\n\t * dataType(config) {\n\t * \t return typeof config.length !== 'undefined' ? `varchar(${config.length})` : `varchar`;\n\t * \t }\n\t * ```\n\t */\n\tdataType: (config: T['config'] | (Equal<T['configRequired'], true> extends true ? never : undefined)) => string;\n\n\t/**\n\t * Optional mapping function, that is used to transform inputs from desired to be used in code format to one suitable for driver\n\t * @example\n\t * For example, when using jsonb we need to map JS/TS object to string before writing to database\n\t * ```\n\t * toDriver(value: TData): string {\n\t * \t return JSON.stringify(value);\n\t * }\n\t * ```\n\t */\n\ttoDriver?: (value: T['data']) => T['driverData'] | SQL;\n\n\t/**\n\t * Optional mapping function, that is used for transforming data returned by driver to desired column's output format\n\t * @example\n\t * For example, when using timestamp we need to map string Date representation to JS Date\n\t * ```\n\t * fromDriver(value: string): Date {\n\t * \treturn new Date(value);\n\t * }\n\t * ```\n\t *\n\t * It'll cause the returned data to change from:\n\t * ```\n\t * {\n\t * \tcustomField: \"2025-04-07T03:25:16.635Z\";\n\t * }\n\t * ```\n\t * to:\n\t * ```\n\t * {\n\t * \tcustomField: new Date(\"2025-04-07T03:25:16.635Z\");\n\t * }\n\t * ```\n\t */\n\tfromDriver?: (value: 'driverOutput' extends keyof T ? T['driverOutput'] : T['driverData']) => T['data'];\n\n\t/**\n\t * Optional mapping function, that is used for transforming data returned by transofmed to JSON in database data to desired format\n\t *\n\t * Used by relational queries\n\t * @example\n\t * For example, when querying blob column via RQB or JSON funcitons, the result field will be returned as it's hex string representation, as opposed to Buffer from regular query\n\t * To handle that, we need a separate function to handle such field's mapping:\n\t * ```\n\t * fromJson(value: string): Buffer {\n\t * \treturn Buffer.from(value, 'hex');\n\t * },\n\t * ```\n\t *\n\t * It'll cause the returned data to change from:\n\t * ```\n\t * {\n\t * \tcustomField: \"04A8...\";\n\t * }\n\t * ```\n\t * to:\n\t * ```\n\t * {\n\t * \tcustomField: Buffer([...]);\n\t * }\n\t * ```\n\t * @default\n\t * Defaults to {@link fromDriver} function\n\t */\n\tfromJson?: (value: T['jsonData']) => T['data'];\n\n\t/**\n\t * Optional selection modifier function, that is used for modifying selection of column inside JSON functions\n\t *\n\t * Additional mapping that could be required for such scenarios can be handled using {@link fromJson} function\n\t *\n\t * Used by relational queries\n\t * @example\n\t * For example, when using numeric field for bigint storage we need to cast field to text to preserve data integrity\n\t * ```\n\t * forJsonSelect(identifier: SQL, sql: SQLGenerator): SQL {\n\t * \treturn sql`cast(${identifier} as text)`\n\t * },\n\t * ```\n\t *\n\t * This will change query from:\n\t * ```\n\t * SELECT\n\t * \tjson_object('bigint', `t`.`bigint`)\n\t * \tFROM\n\t * \t(\n\t * \t\tSELECT\n\t * \t\t`table`.`custom_bigint` AS \"bigint\"\n\t * \t\tFROM\n\t * \t\t`table`\n\t * \t) AS `t`\n\t * ```\n\t * to:\n\t * ```\n\t * SELECT\n\t * \tjson_object('bigint', `t`.`bigint`)\n\t * \tFROM\n\t * \t(\n\t * \t\tSELECT\n\t * \t\tcast(`table`.`custom_bigint` as text) AS `bigint`\n\t * \t\tFROM\n\t * \t\t`table`\n\t * \t) AS `t`\n\t * ```\n\t *\n\t * Returned by query object will change from:\n\t * ```\n\t * {\n\t * \tbigint: 5044565289845416000; // Partial data loss due to direct conversion to JSON format\n\t * }\n\t * ```\n\t * to:\n\t * ```\n\t * {\n\t * \tbigint: \"5044565289845416380\"; // Data is preserved due to conversion of field to text before JSON-ification\n\t * }\n\t * ```\n\t *\n\t * @default\n\t * Following types are being casted to text by default: `numeric`, `decimal`, `bigint`, `blob` (via `hex()` function)\n\t */\n\tforJsonSelect?: (identifier: SQL, sql: SQLGenerator) => SQL;\n}\n\n/**\n * Custom sqlite database data type generator\n */\nexport function customType<T extends CustomTypeValues = CustomTypeValues>(\n\tcustomTypeParams: CustomTypeParams<T>,\n): Equal<T['configRequired'], true> extends true ? {\n\t\t<TConfig extends Record<string, any> & T['config']>(\n\t\t\tfieldConfig: TConfig,\n\t\t): SQLiteCustomColumnBuilder<ConvertCustomConfig<'', T>>;\n\t\t<TName extends string>(\n\t\t\tdbName: TName,\n\t\t\tfieldConfig: T['config'],\n\t\t): SQLiteCustomColumnBuilder<ConvertCustomConfig<TName, T>>;\n\t}\n\t: {\n\t\t(): SQLiteCustomColumnBuilder<ConvertCustomConfig<'', T>>;\n\t\t<TConfig extends Record<string, any> & T['config']>(\n\t\t\tfieldConfig?: TConfig,\n\t\t): SQLiteCustomColumnBuilder<ConvertCustomConfig<'', T>>;\n\t\t<TName extends string>(\n\t\t\tdbName: TName,\n\t\t\tfieldConfig?: T['config'],\n\t\t): SQLiteCustomColumnBuilder<ConvertCustomConfig<TName, T>>;\n\t}\n{\n\treturn <TName extends string>(\n\t\ta?: TName | T['config'],\n\t\tb?: T['config'],\n\t): SQLiteCustomColumnBuilder<ConvertCustomConfig<TName, T>> => {\n\t\tconst { name, config } = getColumnNameAndConfig<T['config']>(a, b);\n\t\treturn new SQLiteCustomColumnBuilder(\n\t\t\tname as ConvertCustomConfig<TName, T>['name'],\n\t\t\tconfig,\n\t\t\tcustomTypeParams,\n\t\t);\n\t};\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,oBAA2B;AAG3B,mBAAmD;AACnD,oBAAkD;AAkB3C,MAAM,kCACJ,kCAUT;AAAA,EACC,QAA0B,wBAAU,IAAY;AAAA,EAEhD,YACC,MACA,aACA,kBACC;AACD,UAAM,MAAM,UAAU,oBAAoB;AAC1C,SAAK,OAAO,cAAc;AAC1B,SAAK,OAAO,mBAAmB;AAAA,EAChC;AAAA;AAAA,EAGA,MACC,OACsD;AACtD,WAAO,IAAI;AAAA,MACV;AAAA,MACA,KAAK;AAAA,IACN;AAAA,EACD;AACD;AAEO,MAAM,2BAAuF,2BAAgB;AAAA,EACnH,QAA0B,wBAAU,IAAY;AAAA,EAExC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAER,YACC,OACA,QACC;AACD,UAAM,OAAO,MAAM;AACnB,SAAK,UAAU,OAAO,iBAAiB,SAAS,OAAO,WAAW;AAClE,SAAK,QAAQ,OAAO,iBAAiB;AACrC,SAAK,UAAU,OAAO,iBAAiB;AACvC,SAAK,UAAU,OAAO,iBAAiB;AACvC,SAAK,gBAAgB,OAAO,iBAAiB;AAAA,EAC9C;AAAA,EAEA,aAAqB;AACpB,WAAO,KAAK;AAAA,EACb;AAAA,EAES,mBAAmB,OAAoC;AAC/D,WAAO,OAAO,KAAK,YAAY,aAAa,KAAK,QAAQ,KAAK,IAAI;AAAA,EACnE;AAAA,EAEA,iBAAiB,OAA2B;AAC3C,WAAO,OAAO,KAAK,YAAY,aAAa,KAAK,QAAQ,KAAK,IAAI,KAAK,mBAAmB,KAAK;AAAA,EAChG;AAAA,EAEA,qBAAqB,YAAiB,KAAwB;AAC7D,QAAI,OAAO,KAAK,kBAAkB;AAAY,aAAO,KAAK,cAAc,YAAY,GAAG;AAEvF,UAAM,UAAU,KAAK,WAAW,EAAE,YAAY;AAC9C,UAAM,WAAW,QAAQ,QAAQ,GAAG;AACpC,UAAM,OAAQ,WAAW,IAAK,QAAQ,MAAM,GAAG,QAAQ,IAAI;AAE3D,YAAQ,MAAM;AAAA,MACb,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK,UAAU;AACd,eAAO,WAAW,UAAU;AAAA,MAC7B;AAAA,MACA,KAAK,QAAQ;AACZ,eAAO,UAAU,UAAU;AAAA,MAC5B;AAAA,MACA,SAAS;AACR,eAAO;AAAA,MACR;AAAA,IACD;AAAA,EACD;AAAA,EAES,iBAAiB,OAAoC;AAC7D,WAAO,OAAO,KAAK,UAAU,aAAa,KAAK,MAAM,KAAK,IAAI;AAAA,EAC/D;AACD;AAsOO,SAAS,WACf,kBAoBD;AACC,SAAO,CACN,GACA,MAC8D;AAC9D,UAAM,EAAE,MAAM,OAAO,QAAI,qCAAoC,GAAG,CAAC;AACjE,WAAO,IAAI;AAAA,MACV;AAAA,MACA;AAAA,MACA;AAAA,IACD;AAAA,EACD;AACD;","names":[]}
@@ -1,7 +1,7 @@
1
1
  import type { ColumnBuilderBaseConfig } from "../../column-builder.cjs";
2
2
  import type { ColumnBaseConfig } from "../../column.cjs";
3
3
  import { entityKind } from "../../entity.cjs";
4
- import type { SQL } from "../../sql/sql.cjs";
4
+ import type { SQL, SQLGenerator } from "../../sql/sql.cjs";
5
5
  import type { AnySQLiteTable } from "../table.cjs";
6
6
  import { type Equal } from "../../utils.cjs";
7
7
  import { SQLiteColumn, SQLiteColumnBuilder } from "./common.cjs";
@@ -34,11 +34,15 @@ export declare class SQLiteCustomColumn<T extends ColumnBaseConfig<'custom', 'SQ
34
34
  private sqlName;
35
35
  private mapTo?;
36
36
  private mapFrom?;
37
+ private mapJson?;
38
+ private forJsonSelect?;
37
39
  constructor(table: AnySQLiteTable<{
38
40
  name: T['tableName'];
39
41
  }>, config: SQLiteCustomColumnBuilder<T>['config']);
40
42
  getSQLType(): string;
41
43
  mapFromDriverValue(value: T['driverParam']): T['data'];
44
+ mapFromJsonValue(value: unknown): T['data'];
45
+ jsonSelectIdentifier(identifier: SQL, sql: SQLGenerator): SQL;
42
46
  mapToDriverValue(value: T['data']): T['driverParam'];
43
47
  }
44
48
  export type CustomTypeValues = {
@@ -56,6 +60,19 @@ export type CustomTypeValues = {
56
60
  * Type helper, that represents what type database driver is accepting for specific database data type
57
61
  */
58
62
  driverData?: unknown;
63
+ /**
64
+ * Type helper, that represents what type database driver is returning for specific database data type
65
+ *
66
+ * Needed only in case driver's output and input for type differ
67
+ *
68
+ * @default
69
+ * Defaults to `driverData`
70
+ */
71
+ driverOutput?: unknown;
72
+ /**
73
+ * Type helper, that represents what type field returns after being aggregated to JSON
74
+ */
75
+ jsonData?: unknown;
59
76
  /**
60
77
  * What config type should be used for {@link CustomTypeParams} `dataType` generation
61
78
  */
@@ -120,7 +137,7 @@ export interface CustomTypeParams<T extends CustomTypeValues> {
120
137
  */
121
138
  dataType: (config: T['config'] | (Equal<T['configRequired'], true> extends true ? never : undefined)) => string;
122
139
  /**
123
- * Optional mapping function, between user input and driver
140
+ * Optional mapping function, that is used to transform inputs from desired to be used in code format to one suitable for driver
124
141
  * @example
125
142
  * For example, when using jsonb we need to map JS/TS object to string before writing to database
126
143
  * ```
@@ -131,16 +148,114 @@ export interface CustomTypeParams<T extends CustomTypeValues> {
131
148
  */
132
149
  toDriver?: (value: T['data']) => T['driverData'] | SQL;
133
150
  /**
134
- * Optional mapping function, that is responsible for data mapping from database to JS/TS code
151
+ * Optional mapping function, that is used for transforming data returned by driver to desired column's output format
135
152
  * @example
136
153
  * For example, when using timestamp we need to map string Date representation to JS Date
137
154
  * ```
138
155
  * fromDriver(value: string): Date {
139
156
  * return new Date(value);
157
+ * }
158
+ * ```
159
+ *
160
+ * It'll cause the returned data to change from:
161
+ * ```
162
+ * {
163
+ * customField: "2025-04-07T03:25:16.635Z";
164
+ * }
165
+ * ```
166
+ * to:
167
+ * ```
168
+ * {
169
+ * customField: new Date("2025-04-07T03:25:16.635Z");
170
+ * }
171
+ * ```
172
+ */
173
+ fromDriver?: (value: 'driverOutput' extends keyof T ? T['driverOutput'] : T['driverData']) => T['data'];
174
+ /**
175
+ * Optional mapping function, that is used for transforming data returned by transofmed to JSON in database data to desired format
176
+ *
177
+ * Used by relational queries
178
+ * @example
179
+ * For example, when querying blob column via RQB or JSON funcitons, the result field will be returned as it's hex string representation, as opposed to Buffer from regular query
180
+ * To handle that, we need a separate function to handle such field's mapping:
181
+ * ```
182
+ * fromJson(value: string): Buffer {
183
+ * return Buffer.from(value, 'hex');
184
+ * },
185
+ * ```
186
+ *
187
+ * It'll cause the returned data to change from:
188
+ * ```
189
+ * {
190
+ * customField: "04A8...";
191
+ * }
192
+ * ```
193
+ * to:
194
+ * ```
195
+ * {
196
+ * customField: Buffer([...]);
197
+ * }
198
+ * ```
199
+ * @default
200
+ * Defaults to {@link fromDriver} function
201
+ */
202
+ fromJson?: (value: T['jsonData']) => T['data'];
203
+ /**
204
+ * Optional selection modifier function, that is used for modifying selection of column inside JSON functions
205
+ *
206
+ * Additional mapping that could be required for such scenarios can be handled using {@link fromJson} function
207
+ *
208
+ * Used by relational queries
209
+ * @example
210
+ * For example, when using numeric field for bigint storage we need to cast field to text to preserve data integrity
211
+ * ```
212
+ * forJsonSelect(identifier: SQL, sql: SQLGenerator): SQL {
213
+ * return sql`cast(${identifier} as text)`
140
214
  * },
141
215
  * ```
216
+ *
217
+ * This will change query from:
218
+ * ```
219
+ * SELECT
220
+ * json_object('bigint', `t`.`bigint`)
221
+ * FROM
222
+ * (
223
+ * SELECT
224
+ * `table`.`custom_bigint` AS "bigint"
225
+ * FROM
226
+ * `table`
227
+ * ) AS `t`
228
+ * ```
229
+ * to:
230
+ * ```
231
+ * SELECT
232
+ * json_object('bigint', `t`.`bigint`)
233
+ * FROM
234
+ * (
235
+ * SELECT
236
+ * cast(`table`.`custom_bigint` as text) AS `bigint`
237
+ * FROM
238
+ * `table`
239
+ * ) AS `t`
240
+ * ```
241
+ *
242
+ * Returned by query object will change from:
243
+ * ```
244
+ * {
245
+ * bigint: 5044565289845416000; // Partial data loss due to direct conversion to JSON format
246
+ * }
247
+ * ```
248
+ * to:
249
+ * ```
250
+ * {
251
+ * bigint: "5044565289845416380"; // Data is preserved due to conversion of field to text before JSON-ification
252
+ * }
253
+ * ```
254
+ *
255
+ * @default
256
+ * Following types are being casted to text by default: `numeric`, `decimal`, `bigint`, `blob` (via `hex()` function)
142
257
  */
143
- fromDriver?: (value: T['driverData']) => T['data'];
258
+ forJsonSelect?: (identifier: SQL, sql: SQLGenerator) => SQL;
144
259
  }
145
260
  /**
146
261
  * Custom sqlite database data type generator
@@ -1,7 +1,7 @@
1
1
  import type { ColumnBuilderBaseConfig } from "../../column-builder.js";
2
2
  import type { ColumnBaseConfig } from "../../column.js";
3
3
  import { entityKind } from "../../entity.js";
4
- import type { SQL } from "../../sql/sql.js";
4
+ import type { SQL, SQLGenerator } from "../../sql/sql.js";
5
5
  import type { AnySQLiteTable } from "../table.js";
6
6
  import { type Equal } from "../../utils.js";
7
7
  import { SQLiteColumn, SQLiteColumnBuilder } from "./common.js";
@@ -34,11 +34,15 @@ export declare class SQLiteCustomColumn<T extends ColumnBaseConfig<'custom', 'SQ
34
34
  private sqlName;
35
35
  private mapTo?;
36
36
  private mapFrom?;
37
+ private mapJson?;
38
+ private forJsonSelect?;
37
39
  constructor(table: AnySQLiteTable<{
38
40
  name: T['tableName'];
39
41
  }>, config: SQLiteCustomColumnBuilder<T>['config']);
40
42
  getSQLType(): string;
41
43
  mapFromDriverValue(value: T['driverParam']): T['data'];
44
+ mapFromJsonValue(value: unknown): T['data'];
45
+ jsonSelectIdentifier(identifier: SQL, sql: SQLGenerator): SQL;
42
46
  mapToDriverValue(value: T['data']): T['driverParam'];
43
47
  }
44
48
  export type CustomTypeValues = {
@@ -56,6 +60,19 @@ export type CustomTypeValues = {
56
60
  * Type helper, that represents what type database driver is accepting for specific database data type
57
61
  */
58
62
  driverData?: unknown;
63
+ /**
64
+ * Type helper, that represents what type database driver is returning for specific database data type
65
+ *
66
+ * Needed only in case driver's output and input for type differ
67
+ *
68
+ * @default
69
+ * Defaults to `driverData`
70
+ */
71
+ driverOutput?: unknown;
72
+ /**
73
+ * Type helper, that represents what type field returns after being aggregated to JSON
74
+ */
75
+ jsonData?: unknown;
59
76
  /**
60
77
  * What config type should be used for {@link CustomTypeParams} `dataType` generation
61
78
  */
@@ -120,7 +137,7 @@ export interface CustomTypeParams<T extends CustomTypeValues> {
120
137
  */
121
138
  dataType: (config: T['config'] | (Equal<T['configRequired'], true> extends true ? never : undefined)) => string;
122
139
  /**
123
- * Optional mapping function, between user input and driver
140
+ * Optional mapping function, that is used to transform inputs from desired to be used in code format to one suitable for driver
124
141
  * @example
125
142
  * For example, when using jsonb we need to map JS/TS object to string before writing to database
126
143
  * ```
@@ -131,16 +148,114 @@ export interface CustomTypeParams<T extends CustomTypeValues> {
131
148
  */
132
149
  toDriver?: (value: T['data']) => T['driverData'] | SQL;
133
150
  /**
134
- * Optional mapping function, that is responsible for data mapping from database to JS/TS code
151
+ * Optional mapping function, that is used for transforming data returned by driver to desired column's output format
135
152
  * @example
136
153
  * For example, when using timestamp we need to map string Date representation to JS Date
137
154
  * ```
138
155
  * fromDriver(value: string): Date {
139
156
  * return new Date(value);
157
+ * }
158
+ * ```
159
+ *
160
+ * It'll cause the returned data to change from:
161
+ * ```
162
+ * {
163
+ * customField: "2025-04-07T03:25:16.635Z";
164
+ * }
165
+ * ```
166
+ * to:
167
+ * ```
168
+ * {
169
+ * customField: new Date("2025-04-07T03:25:16.635Z");
170
+ * }
171
+ * ```
172
+ */
173
+ fromDriver?: (value: 'driverOutput' extends keyof T ? T['driverOutput'] : T['driverData']) => T['data'];
174
+ /**
175
+ * Optional mapping function, that is used for transforming data returned by transofmed to JSON in database data to desired format
176
+ *
177
+ * Used by relational queries
178
+ * @example
179
+ * For example, when querying blob column via RQB or JSON funcitons, the result field will be returned as it's hex string representation, as opposed to Buffer from regular query
180
+ * To handle that, we need a separate function to handle such field's mapping:
181
+ * ```
182
+ * fromJson(value: string): Buffer {
183
+ * return Buffer.from(value, 'hex');
184
+ * },
185
+ * ```
186
+ *
187
+ * It'll cause the returned data to change from:
188
+ * ```
189
+ * {
190
+ * customField: "04A8...";
191
+ * }
192
+ * ```
193
+ * to:
194
+ * ```
195
+ * {
196
+ * customField: Buffer([...]);
197
+ * }
198
+ * ```
199
+ * @default
200
+ * Defaults to {@link fromDriver} function
201
+ */
202
+ fromJson?: (value: T['jsonData']) => T['data'];
203
+ /**
204
+ * Optional selection modifier function, that is used for modifying selection of column inside JSON functions
205
+ *
206
+ * Additional mapping that could be required for such scenarios can be handled using {@link fromJson} function
207
+ *
208
+ * Used by relational queries
209
+ * @example
210
+ * For example, when using numeric field for bigint storage we need to cast field to text to preserve data integrity
211
+ * ```
212
+ * forJsonSelect(identifier: SQL, sql: SQLGenerator): SQL {
213
+ * return sql`cast(${identifier} as text)`
140
214
  * },
141
215
  * ```
216
+ *
217
+ * This will change query from:
218
+ * ```
219
+ * SELECT
220
+ * json_object('bigint', `t`.`bigint`)
221
+ * FROM
222
+ * (
223
+ * SELECT
224
+ * `table`.`custom_bigint` AS "bigint"
225
+ * FROM
226
+ * `table`
227
+ * ) AS `t`
228
+ * ```
229
+ * to:
230
+ * ```
231
+ * SELECT
232
+ * json_object('bigint', `t`.`bigint`)
233
+ * FROM
234
+ * (
235
+ * SELECT
236
+ * cast(`table`.`custom_bigint` as text) AS `bigint`
237
+ * FROM
238
+ * `table`
239
+ * ) AS `t`
240
+ * ```
241
+ *
242
+ * Returned by query object will change from:
243
+ * ```
244
+ * {
245
+ * bigint: 5044565289845416000; // Partial data loss due to direct conversion to JSON format
246
+ * }
247
+ * ```
248
+ * to:
249
+ * ```
250
+ * {
251
+ * bigint: "5044565289845416380"; // Data is preserved due to conversion of field to text before JSON-ification
252
+ * }
253
+ * ```
254
+ *
255
+ * @default
256
+ * Following types are being casted to text by default: `numeric`, `decimal`, `bigint`, `blob` (via `hex()` function)
142
257
  */
143
- fromDriver?: (value: T['driverData']) => T['data'];
258
+ forJsonSelect?: (identifier: SQL, sql: SQLGenerator) => SQL;
144
259
  }
145
260
  /**
146
261
  * Custom sqlite database data type generator
@@ -21,11 +21,15 @@ class SQLiteCustomColumn extends SQLiteColumn {
21
21
  sqlName;
22
22
  mapTo;
23
23
  mapFrom;
24
+ mapJson;
25
+ forJsonSelect;
24
26
  constructor(table, config) {
25
27
  super(table, config);
26
28
  this.sqlName = config.customTypeParams.dataType(config.fieldConfig);
27
29
  this.mapTo = config.customTypeParams.toDriver;
28
30
  this.mapFrom = config.customTypeParams.fromDriver;
31
+ this.mapJson = config.customTypeParams.fromJson;
32
+ this.forJsonSelect = config.customTypeParams.forJsonSelect;
29
33
  }
30
34
  getSQLType() {
31
35
  return this.sqlName;
@@ -33,6 +37,29 @@ class SQLiteCustomColumn extends SQLiteColumn {
33
37
  mapFromDriverValue(value) {
34
38
  return typeof this.mapFrom === "function" ? this.mapFrom(value) : value;
35
39
  }
40
+ mapFromJsonValue(value) {
41
+ return typeof this.mapJson === "function" ? this.mapJson(value) : this.mapFromDriverValue(value);
42
+ }
43
+ jsonSelectIdentifier(identifier, sql) {
44
+ if (typeof this.forJsonSelect === "function")
45
+ return this.forJsonSelect(identifier, sql);
46
+ const rawType = this.getSQLType().toLowerCase();
47
+ const parenPos = rawType.indexOf("(");
48
+ const type = parenPos + 1 ? rawType.slice(0, parenPos) : rawType;
49
+ switch (type) {
50
+ case "numeric":
51
+ case "decimal":
52
+ case "bigint": {
53
+ return sql`cast(${identifier} as text)`;
54
+ }
55
+ case "blob": {
56
+ return sql`hex(${identifier})`;
57
+ }
58
+ default: {
59
+ return identifier;
60
+ }
61
+ }
62
+ }
36
63
  mapToDriverValue(value) {
37
64
  return typeof this.mapTo === "function" ? this.mapTo(value) : value;
38
65
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/sqlite-core/columns/custom.ts"],"sourcesContent":["import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts';\nimport type { ColumnBaseConfig } from '~/column.ts';\nimport { entityKind } from '~/entity.ts';\nimport type { SQL } from '~/sql/sql.ts';\nimport type { AnySQLiteTable } from '~/sqlite-core/table.ts';\nimport { type Equal, getColumnNameAndConfig } from '~/utils.ts';\nimport { SQLiteColumn, SQLiteColumnBuilder } from './common.ts';\n\nexport type ConvertCustomConfig<TName extends string, T extends Partial<CustomTypeValues>> =\n\t& {\n\t\tname: TName;\n\t\tdataType: 'custom';\n\t\tcolumnType: 'SQLiteCustomColumn';\n\t\tdata: T['data'];\n\t\tdriverParam: T['driverData'];\n\t\tenumValues: undefined;\n\t}\n\t& (T['notNull'] extends true ? { notNull: true } : {})\n\t& (T['default'] extends true ? { hasDefault: true } : {});\n\nexport interface SQLiteCustomColumnInnerConfig {\n\tcustomTypeValues: CustomTypeValues;\n}\n\nexport class SQLiteCustomColumnBuilder<T extends ColumnBuilderBaseConfig<'custom', 'SQLiteCustomColumn'>>\n\textends SQLiteColumnBuilder<\n\t\tT,\n\t\t{\n\t\t\tfieldConfig: CustomTypeValues['config'];\n\t\t\tcustomTypeParams: CustomTypeParams<any>;\n\t\t},\n\t\t{\n\t\t\tsqliteColumnBuilderBrand: 'SQLiteCustomColumnBuilderBrand';\n\t\t}\n\t>\n{\n\tstatic override readonly [entityKind]: string = 'SQLiteCustomColumnBuilder';\n\n\tconstructor(\n\t\tname: T['name'],\n\t\tfieldConfig: CustomTypeValues['config'],\n\t\tcustomTypeParams: CustomTypeParams<any>,\n\t) {\n\t\tsuper(name, 'custom', 'SQLiteCustomColumn');\n\t\tthis.config.fieldConfig = fieldConfig;\n\t\tthis.config.customTypeParams = customTypeParams;\n\t}\n\n\t/** @internal */\n\tbuild<TTableName extends string>(\n\t\ttable: AnySQLiteTable<{ name: TTableName }>,\n\t): SQLiteCustomColumn<MakeColumnConfig<T, TTableName>> {\n\t\treturn new SQLiteCustomColumn<MakeColumnConfig<T, TTableName>>(\n\t\t\ttable,\n\t\t\tthis.config as ColumnBuilderRuntimeConfig<any, any>,\n\t\t);\n\t}\n}\n\nexport class SQLiteCustomColumn<T extends ColumnBaseConfig<'custom', 'SQLiteCustomColumn'>> extends SQLiteColumn<T> {\n\tstatic override readonly [entityKind]: string = 'SQLiteCustomColumn';\n\n\tprivate sqlName: string;\n\tprivate mapTo?: (value: T['data']) => T['driverParam'];\n\tprivate mapFrom?: (value: T['driverParam']) => T['data'];\n\n\tconstructor(\n\t\ttable: AnySQLiteTable<{ name: T['tableName'] }>,\n\t\tconfig: SQLiteCustomColumnBuilder<T>['config'],\n\t) {\n\t\tsuper(table, config);\n\t\tthis.sqlName = config.customTypeParams.dataType(config.fieldConfig);\n\t\tthis.mapTo = config.customTypeParams.toDriver;\n\t\tthis.mapFrom = config.customTypeParams.fromDriver;\n\t}\n\n\tgetSQLType(): string {\n\t\treturn this.sqlName;\n\t}\n\n\toverride mapFromDriverValue(value: T['driverParam']): T['data'] {\n\t\treturn typeof this.mapFrom === 'function' ? this.mapFrom(value) : value as T['data'];\n\t}\n\n\toverride mapToDriverValue(value: T['data']): T['driverParam'] {\n\t\treturn typeof this.mapTo === 'function' ? this.mapTo(value) : value as T['data'];\n\t}\n}\n\nexport type CustomTypeValues = {\n\t/**\n\t * Required type for custom column, that will infer proper type model\n\t *\n\t * Examples:\n\t *\n\t * If you want your column to be `string` type after selecting/or on inserting - use `data: string`. Like `text`, `varchar`\n\t *\n\t * If you want your column to be `number` type after selecting/or on inserting - use `data: number`. Like `integer`\n\t */\n\tdata: unknown;\n\n\t/**\n\t * Type helper, that represents what type database driver is accepting for specific database data type\n\t */\n\tdriverData?: unknown;\n\n\t/**\n\t * What config type should be used for {@link CustomTypeParams} `dataType` generation\n\t */\n\tconfig?: Record<string, any>;\n\n\t/**\n\t * Whether the config argument should be required or not\n\t * @default false\n\t */\n\tconfigRequired?: boolean;\n\n\t/**\n\t * If your custom data type should be notNull by default you can use `notNull: true`\n\t *\n\t * @example\n\t * const customSerial = customType<{ data: number, notNull: true, default: true }>({\n\t * \t dataType() {\n\t * \t return 'serial';\n\t * },\n\t * });\n\t */\n\tnotNull?: boolean;\n\n\t/**\n\t * If your custom data type has default you can use `default: true`\n\t *\n\t * @example\n\t * const customSerial = customType<{ data: number, notNull: true, default: true }>({\n\t * \t dataType() {\n\t * \t return 'serial';\n\t * },\n\t * });\n\t */\n\tdefault?: boolean;\n};\n\nexport interface CustomTypeParams<T extends CustomTypeValues> {\n\t/**\n\t * Database data type string representation, that is used for migrations\n\t * @example\n\t * ```\n\t * `jsonb`, `text`\n\t * ```\n\t *\n\t * If database data type needs additional params you can use them from `config` param\n\t * @example\n\t * ```\n\t * `varchar(256)`, `numeric(2,3)`\n\t * ```\n\t *\n\t * To make `config` be of specific type please use config generic in {@link CustomTypeValues}\n\t *\n\t * @example\n\t * Usage example\n\t * ```\n\t * dataType() {\n\t * return 'boolean';\n\t * },\n\t * ```\n\t * Or\n\t * ```\n\t * dataType(config) {\n\t * \t return typeof config.length !== 'undefined' ? `varchar(${config.length})` : `varchar`;\n\t * \t }\n\t * ```\n\t */\n\tdataType: (config: T['config'] | (Equal<T['configRequired'], true> extends true ? never : undefined)) => string;\n\n\t/**\n\t * Optional mapping function, between user input and driver\n\t * @example\n\t * For example, when using jsonb we need to map JS/TS object to string before writing to database\n\t * ```\n\t * toDriver(value: TData): string {\n\t * \t return JSON.stringify(value);\n\t * }\n\t * ```\n\t */\n\ttoDriver?: (value: T['data']) => T['driverData'] | SQL;\n\n\t/**\n\t * Optional mapping function, that is responsible for data mapping from database to JS/TS code\n\t * @example\n\t * For example, when using timestamp we need to map string Date representation to JS Date\n\t * ```\n\t * fromDriver(value: string): Date {\n\t * \treturn new Date(value);\n\t * },\n\t * ```\n\t */\n\tfromDriver?: (value: T['driverData']) => T['data'];\n}\n\n/**\n * Custom sqlite database data type generator\n */\nexport function customType<T extends CustomTypeValues = CustomTypeValues>(\n\tcustomTypeParams: CustomTypeParams<T>,\n): Equal<T['configRequired'], true> extends true ? {\n\t\t<TConfig extends Record<string, any> & T['config']>(\n\t\t\tfieldConfig: TConfig,\n\t\t): SQLiteCustomColumnBuilder<ConvertCustomConfig<'', T>>;\n\t\t<TName extends string>(\n\t\t\tdbName: TName,\n\t\t\tfieldConfig: T['config'],\n\t\t): SQLiteCustomColumnBuilder<ConvertCustomConfig<TName, T>>;\n\t}\n\t: {\n\t\t(): SQLiteCustomColumnBuilder<ConvertCustomConfig<'', T>>;\n\t\t<TConfig extends Record<string, any> & T['config']>(\n\t\t\tfieldConfig?: TConfig,\n\t\t): SQLiteCustomColumnBuilder<ConvertCustomConfig<'', T>>;\n\t\t<TName extends string>(\n\t\t\tdbName: TName,\n\t\t\tfieldConfig?: T['config'],\n\t\t): SQLiteCustomColumnBuilder<ConvertCustomConfig<TName, T>>;\n\t}\n{\n\treturn <TName extends string>(\n\t\ta?: TName | T['config'],\n\t\tb?: T['config'],\n\t): SQLiteCustomColumnBuilder<ConvertCustomConfig<TName, T>> => {\n\t\tconst { name, config } = getColumnNameAndConfig<T['config']>(a, b);\n\t\treturn new SQLiteCustomColumnBuilder(\n\t\t\tname as ConvertCustomConfig<TName, T>['name'],\n\t\t\tconfig,\n\t\t\tcustomTypeParams,\n\t\t);\n\t};\n}\n"],"mappings":"AAEA,SAAS,kBAAkB;AAG3B,SAAqB,8BAA8B;AACnD,SAAS,cAAc,2BAA2B;AAkB3C,MAAM,kCACJ,oBAUT;AAAA,EACC,QAA0B,UAAU,IAAY;AAAA,EAEhD,YACC,MACA,aACA,kBACC;AACD,UAAM,MAAM,UAAU,oBAAoB;AAC1C,SAAK,OAAO,cAAc;AAC1B,SAAK,OAAO,mBAAmB;AAAA,EAChC;AAAA;AAAA,EAGA,MACC,OACsD;AACtD,WAAO,IAAI;AAAA,MACV;AAAA,MACA,KAAK;AAAA,IACN;AAAA,EACD;AACD;AAEO,MAAM,2BAAuF,aAAgB;AAAA,EACnH,QAA0B,UAAU,IAAY;AAAA,EAExC;AAAA,EACA;AAAA,EACA;AAAA,EAER,YACC,OACA,QACC;AACD,UAAM,OAAO,MAAM;AACnB,SAAK,UAAU,OAAO,iBAAiB,SAAS,OAAO,WAAW;AAClE,SAAK,QAAQ,OAAO,iBAAiB;AACrC,SAAK,UAAU,OAAO,iBAAiB;AAAA,EACxC;AAAA,EAEA,aAAqB;AACpB,WAAO,KAAK;AAAA,EACb;AAAA,EAES,mBAAmB,OAAoC;AAC/D,WAAO,OAAO,KAAK,YAAY,aAAa,KAAK,QAAQ,KAAK,IAAI;AAAA,EACnE;AAAA,EAES,iBAAiB,OAAoC;AAC7D,WAAO,OAAO,KAAK,UAAU,aAAa,KAAK,MAAM,KAAK,IAAI;AAAA,EAC/D;AACD;AAmHO,SAAS,WACf,kBAoBD;AACC,SAAO,CACN,GACA,MAC8D;AAC9D,UAAM,EAAE,MAAM,OAAO,IAAI,uBAAoC,GAAG,CAAC;AACjE,WAAO,IAAI;AAAA,MACV;AAAA,MACA;AAAA,MACA;AAAA,IACD;AAAA,EACD;AACD;","names":[]}
1
+ {"version":3,"sources":["../../../src/sqlite-core/columns/custom.ts"],"sourcesContent":["import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts';\nimport type { ColumnBaseConfig } from '~/column.ts';\nimport { entityKind } from '~/entity.ts';\nimport type { SQL, SQLGenerator } from '~/sql/sql.ts';\nimport type { AnySQLiteTable } from '~/sqlite-core/table.ts';\nimport { type Equal, getColumnNameAndConfig } from '~/utils.ts';\nimport { SQLiteColumn, SQLiteColumnBuilder } from './common.ts';\n\nexport type ConvertCustomConfig<TName extends string, T extends Partial<CustomTypeValues>> =\n\t& {\n\t\tname: TName;\n\t\tdataType: 'custom';\n\t\tcolumnType: 'SQLiteCustomColumn';\n\t\tdata: T['data'];\n\t\tdriverParam: T['driverData'];\n\t\tenumValues: undefined;\n\t}\n\t& (T['notNull'] extends true ? { notNull: true } : {})\n\t& (T['default'] extends true ? { hasDefault: true } : {});\n\nexport interface SQLiteCustomColumnInnerConfig {\n\tcustomTypeValues: CustomTypeValues;\n}\n\nexport class SQLiteCustomColumnBuilder<T extends ColumnBuilderBaseConfig<'custom', 'SQLiteCustomColumn'>>\n\textends SQLiteColumnBuilder<\n\t\tT,\n\t\t{\n\t\t\tfieldConfig: CustomTypeValues['config'];\n\t\t\tcustomTypeParams: CustomTypeParams<any>;\n\t\t},\n\t\t{\n\t\t\tsqliteColumnBuilderBrand: 'SQLiteCustomColumnBuilderBrand';\n\t\t}\n\t>\n{\n\tstatic override readonly [entityKind]: string = 'SQLiteCustomColumnBuilder';\n\n\tconstructor(\n\t\tname: T['name'],\n\t\tfieldConfig: CustomTypeValues['config'],\n\t\tcustomTypeParams: CustomTypeParams<any>,\n\t) {\n\t\tsuper(name, 'custom', 'SQLiteCustomColumn');\n\t\tthis.config.fieldConfig = fieldConfig;\n\t\tthis.config.customTypeParams = customTypeParams;\n\t}\n\n\t/** @internal */\n\tbuild<TTableName extends string>(\n\t\ttable: AnySQLiteTable<{ name: TTableName }>,\n\t): SQLiteCustomColumn<MakeColumnConfig<T, TTableName>> {\n\t\treturn new SQLiteCustomColumn<MakeColumnConfig<T, TTableName>>(\n\t\t\ttable,\n\t\t\tthis.config as ColumnBuilderRuntimeConfig<any, any>,\n\t\t);\n\t}\n}\n\nexport class SQLiteCustomColumn<T extends ColumnBaseConfig<'custom', 'SQLiteCustomColumn'>> extends SQLiteColumn<T> {\n\tstatic override readonly [entityKind]: string = 'SQLiteCustomColumn';\n\n\tprivate sqlName: string;\n\tprivate mapTo?: (value: T['data']) => T['driverParam'];\n\tprivate mapFrom?: (value: T['driverParam']) => T['data'];\n\tprivate mapJson?: (value: unknown) => T['data'];\n\tprivate forJsonSelect?: (name: SQL, sql: SQLGenerator) => SQL;\n\n\tconstructor(\n\t\ttable: AnySQLiteTable<{ name: T['tableName'] }>,\n\t\tconfig: SQLiteCustomColumnBuilder<T>['config'],\n\t) {\n\t\tsuper(table, config);\n\t\tthis.sqlName = config.customTypeParams.dataType(config.fieldConfig);\n\t\tthis.mapTo = config.customTypeParams.toDriver;\n\t\tthis.mapFrom = config.customTypeParams.fromDriver;\n\t\tthis.mapJson = config.customTypeParams.fromJson;\n\t\tthis.forJsonSelect = config.customTypeParams.forJsonSelect;\n\t}\n\n\tgetSQLType(): string {\n\t\treturn this.sqlName;\n\t}\n\n\toverride mapFromDriverValue(value: T['driverParam']): T['data'] {\n\t\treturn typeof this.mapFrom === 'function' ? this.mapFrom(value) : value as T['data'];\n\t}\n\n\tmapFromJsonValue(value: unknown): T['data'] {\n\t\treturn typeof this.mapJson === 'function' ? this.mapJson(value) : this.mapFromDriverValue(value) as T['data'];\n\t}\n\n\tjsonSelectIdentifier(identifier: SQL, sql: SQLGenerator): SQL {\n\t\tif (typeof this.forJsonSelect === 'function') return this.forJsonSelect(identifier, sql);\n\n\t\tconst rawType = this.getSQLType().toLowerCase();\n\t\tconst parenPos = rawType.indexOf('(');\n\t\tconst type = (parenPos + 1) ? rawType.slice(0, parenPos) : rawType;\n\n\t\tswitch (type) {\n\t\t\tcase 'numeric':\n\t\t\tcase 'decimal':\n\t\t\tcase 'bigint': {\n\t\t\t\treturn sql`cast(${identifier} as text)`;\n\t\t\t}\n\t\t\tcase 'blob': {\n\t\t\t\treturn sql`hex(${identifier})`;\n\t\t\t}\n\t\t\tdefault: {\n\t\t\t\treturn identifier;\n\t\t\t}\n\t\t}\n\t}\n\n\toverride mapToDriverValue(value: T['data']): T['driverParam'] {\n\t\treturn typeof this.mapTo === 'function' ? this.mapTo(value) : value as T['data'];\n\t}\n}\n\nexport type CustomTypeValues = {\n\t/**\n\t * Required type for custom column, that will infer proper type model\n\t *\n\t * Examples:\n\t *\n\t * If you want your column to be `string` type after selecting/or on inserting - use `data: string`. Like `text`, `varchar`\n\t *\n\t * If you want your column to be `number` type after selecting/or on inserting - use `data: number`. Like `integer`\n\t */\n\tdata: unknown;\n\n\t/**\n\t * Type helper, that represents what type database driver is accepting for specific database data type\n\t */\n\tdriverData?: unknown;\n\n\t/**\n\t * Type helper, that represents what type database driver is returning for specific database data type\n\t *\n\t * Needed only in case driver's output and input for type differ\n\t *\n\t * @default\n\t * Defaults to `driverData`\n\t */\n\tdriverOutput?: unknown;\n\n\t/**\n\t * Type helper, that represents what type field returns after being aggregated to JSON\n\t */\n\tjsonData?: unknown;\n\n\t/**\n\t * What config type should be used for {@link CustomTypeParams} `dataType` generation\n\t */\n\tconfig?: Record<string, any>;\n\n\t/**\n\t * Whether the config argument should be required or not\n\t * @default false\n\t */\n\tconfigRequired?: boolean;\n\n\t/**\n\t * If your custom data type should be notNull by default you can use `notNull: true`\n\t *\n\t * @example\n\t * const customSerial = customType<{ data: number, notNull: true, default: true }>({\n\t * \t dataType() {\n\t * \t return 'serial';\n\t * },\n\t * });\n\t */\n\tnotNull?: boolean;\n\n\t/**\n\t * If your custom data type has default you can use `default: true`\n\t *\n\t * @example\n\t * const customSerial = customType<{ data: number, notNull: true, default: true }>({\n\t * \t dataType() {\n\t * \t return 'serial';\n\t * },\n\t * });\n\t */\n\tdefault?: boolean;\n};\n\nexport interface CustomTypeParams<T extends CustomTypeValues> {\n\t/**\n\t * Database data type string representation, that is used for migrations\n\t * @example\n\t * ```\n\t * `jsonb`, `text`\n\t * ```\n\t *\n\t * If database data type needs additional params you can use them from `config` param\n\t * @example\n\t * ```\n\t * `varchar(256)`, `numeric(2,3)`\n\t * ```\n\t *\n\t * To make `config` be of specific type please use config generic in {@link CustomTypeValues}\n\t *\n\t * @example\n\t * Usage example\n\t * ```\n\t * dataType() {\n\t * return 'boolean';\n\t * },\n\t * ```\n\t * Or\n\t * ```\n\t * dataType(config) {\n\t * \t return typeof config.length !== 'undefined' ? `varchar(${config.length})` : `varchar`;\n\t * \t }\n\t * ```\n\t */\n\tdataType: (config: T['config'] | (Equal<T['configRequired'], true> extends true ? never : undefined)) => string;\n\n\t/**\n\t * Optional mapping function, that is used to transform inputs from desired to be used in code format to one suitable for driver\n\t * @example\n\t * For example, when using jsonb we need to map JS/TS object to string before writing to database\n\t * ```\n\t * toDriver(value: TData): string {\n\t * \t return JSON.stringify(value);\n\t * }\n\t * ```\n\t */\n\ttoDriver?: (value: T['data']) => T['driverData'] | SQL;\n\n\t/**\n\t * Optional mapping function, that is used for transforming data returned by driver to desired column's output format\n\t * @example\n\t * For example, when using timestamp we need to map string Date representation to JS Date\n\t * ```\n\t * fromDriver(value: string): Date {\n\t * \treturn new Date(value);\n\t * }\n\t * ```\n\t *\n\t * It'll cause the returned data to change from:\n\t * ```\n\t * {\n\t * \tcustomField: \"2025-04-07T03:25:16.635Z\";\n\t * }\n\t * ```\n\t * to:\n\t * ```\n\t * {\n\t * \tcustomField: new Date(\"2025-04-07T03:25:16.635Z\");\n\t * }\n\t * ```\n\t */\n\tfromDriver?: (value: 'driverOutput' extends keyof T ? T['driverOutput'] : T['driverData']) => T['data'];\n\n\t/**\n\t * Optional mapping function, that is used for transforming data returned by transofmed to JSON in database data to desired format\n\t *\n\t * Used by relational queries\n\t * @example\n\t * For example, when querying blob column via RQB or JSON funcitons, the result field will be returned as it's hex string representation, as opposed to Buffer from regular query\n\t * To handle that, we need a separate function to handle such field's mapping:\n\t * ```\n\t * fromJson(value: string): Buffer {\n\t * \treturn Buffer.from(value, 'hex');\n\t * },\n\t * ```\n\t *\n\t * It'll cause the returned data to change from:\n\t * ```\n\t * {\n\t * \tcustomField: \"04A8...\";\n\t * }\n\t * ```\n\t * to:\n\t * ```\n\t * {\n\t * \tcustomField: Buffer([...]);\n\t * }\n\t * ```\n\t * @default\n\t * Defaults to {@link fromDriver} function\n\t */\n\tfromJson?: (value: T['jsonData']) => T['data'];\n\n\t/**\n\t * Optional selection modifier function, that is used for modifying selection of column inside JSON functions\n\t *\n\t * Additional mapping that could be required for such scenarios can be handled using {@link fromJson} function\n\t *\n\t * Used by relational queries\n\t * @example\n\t * For example, when using numeric field for bigint storage we need to cast field to text to preserve data integrity\n\t * ```\n\t * forJsonSelect(identifier: SQL, sql: SQLGenerator): SQL {\n\t * \treturn sql`cast(${identifier} as text)`\n\t * },\n\t * ```\n\t *\n\t * This will change query from:\n\t * ```\n\t * SELECT\n\t * \tjson_object('bigint', `t`.`bigint`)\n\t * \tFROM\n\t * \t(\n\t * \t\tSELECT\n\t * \t\t`table`.`custom_bigint` AS \"bigint\"\n\t * \t\tFROM\n\t * \t\t`table`\n\t * \t) AS `t`\n\t * ```\n\t * to:\n\t * ```\n\t * SELECT\n\t * \tjson_object('bigint', `t`.`bigint`)\n\t * \tFROM\n\t * \t(\n\t * \t\tSELECT\n\t * \t\tcast(`table`.`custom_bigint` as text) AS `bigint`\n\t * \t\tFROM\n\t * \t\t`table`\n\t * \t) AS `t`\n\t * ```\n\t *\n\t * Returned by query object will change from:\n\t * ```\n\t * {\n\t * \tbigint: 5044565289845416000; // Partial data loss due to direct conversion to JSON format\n\t * }\n\t * ```\n\t * to:\n\t * ```\n\t * {\n\t * \tbigint: \"5044565289845416380\"; // Data is preserved due to conversion of field to text before JSON-ification\n\t * }\n\t * ```\n\t *\n\t * @default\n\t * Following types are being casted to text by default: `numeric`, `decimal`, `bigint`, `blob` (via `hex()` function)\n\t */\n\tforJsonSelect?: (identifier: SQL, sql: SQLGenerator) => SQL;\n}\n\n/**\n * Custom sqlite database data type generator\n */\nexport function customType<T extends CustomTypeValues = CustomTypeValues>(\n\tcustomTypeParams: CustomTypeParams<T>,\n): Equal<T['configRequired'], true> extends true ? {\n\t\t<TConfig extends Record<string, any> & T['config']>(\n\t\t\tfieldConfig: TConfig,\n\t\t): SQLiteCustomColumnBuilder<ConvertCustomConfig<'', T>>;\n\t\t<TName extends string>(\n\t\t\tdbName: TName,\n\t\t\tfieldConfig: T['config'],\n\t\t): SQLiteCustomColumnBuilder<ConvertCustomConfig<TName, T>>;\n\t}\n\t: {\n\t\t(): SQLiteCustomColumnBuilder<ConvertCustomConfig<'', T>>;\n\t\t<TConfig extends Record<string, any> & T['config']>(\n\t\t\tfieldConfig?: TConfig,\n\t\t): SQLiteCustomColumnBuilder<ConvertCustomConfig<'', T>>;\n\t\t<TName extends string>(\n\t\t\tdbName: TName,\n\t\t\tfieldConfig?: T['config'],\n\t\t): SQLiteCustomColumnBuilder<ConvertCustomConfig<TName, T>>;\n\t}\n{\n\treturn <TName extends string>(\n\t\ta?: TName | T['config'],\n\t\tb?: T['config'],\n\t): SQLiteCustomColumnBuilder<ConvertCustomConfig<TName, T>> => {\n\t\tconst { name, config } = getColumnNameAndConfig<T['config']>(a, b);\n\t\treturn new SQLiteCustomColumnBuilder(\n\t\t\tname as ConvertCustomConfig<TName, T>['name'],\n\t\t\tconfig,\n\t\t\tcustomTypeParams,\n\t\t);\n\t};\n}\n"],"mappings":"AAEA,SAAS,kBAAkB;AAG3B,SAAqB,8BAA8B;AACnD,SAAS,cAAc,2BAA2B;AAkB3C,MAAM,kCACJ,oBAUT;AAAA,EACC,QAA0B,UAAU,IAAY;AAAA,EAEhD,YACC,MACA,aACA,kBACC;AACD,UAAM,MAAM,UAAU,oBAAoB;AAC1C,SAAK,OAAO,cAAc;AAC1B,SAAK,OAAO,mBAAmB;AAAA,EAChC;AAAA;AAAA,EAGA,MACC,OACsD;AACtD,WAAO,IAAI;AAAA,MACV;AAAA,MACA,KAAK;AAAA,IACN;AAAA,EACD;AACD;AAEO,MAAM,2BAAuF,aAAgB;AAAA,EACnH,QAA0B,UAAU,IAAY;AAAA,EAExC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAER,YACC,OACA,QACC;AACD,UAAM,OAAO,MAAM;AACnB,SAAK,UAAU,OAAO,iBAAiB,SAAS,OAAO,WAAW;AAClE,SAAK,QAAQ,OAAO,iBAAiB;AACrC,SAAK,UAAU,OAAO,iBAAiB;AACvC,SAAK,UAAU,OAAO,iBAAiB;AACvC,SAAK,gBAAgB,OAAO,iBAAiB;AAAA,EAC9C;AAAA,EAEA,aAAqB;AACpB,WAAO,KAAK;AAAA,EACb;AAAA,EAES,mBAAmB,OAAoC;AAC/D,WAAO,OAAO,KAAK,YAAY,aAAa,KAAK,QAAQ,KAAK,IAAI;AAAA,EACnE;AAAA,EAEA,iBAAiB,OAA2B;AAC3C,WAAO,OAAO,KAAK,YAAY,aAAa,KAAK,QAAQ,KAAK,IAAI,KAAK,mBAAmB,KAAK;AAAA,EAChG;AAAA,EAEA,qBAAqB,YAAiB,KAAwB;AAC7D,QAAI,OAAO,KAAK,kBAAkB;AAAY,aAAO,KAAK,cAAc,YAAY,GAAG;AAEvF,UAAM,UAAU,KAAK,WAAW,EAAE,YAAY;AAC9C,UAAM,WAAW,QAAQ,QAAQ,GAAG;AACpC,UAAM,OAAQ,WAAW,IAAK,QAAQ,MAAM,GAAG,QAAQ,IAAI;AAE3D,YAAQ,MAAM;AAAA,MACb,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK,UAAU;AACd,eAAO,WAAW,UAAU;AAAA,MAC7B;AAAA,MACA,KAAK,QAAQ;AACZ,eAAO,UAAU,UAAU;AAAA,MAC5B;AAAA,MACA,SAAS;AACR,eAAO;AAAA,MACR;AAAA,IACD;AAAA,EACD;AAAA,EAES,iBAAiB,OAAoC;AAC7D,WAAO,OAAO,KAAK,UAAU,aAAa,KAAK,MAAM,KAAK,IAAI;AAAA,EAC/D;AACD;AAsOO,SAAS,WACf,kBAoBD;AACC,SAAO,CACN,GACA,MAC8D;AAC9D,UAAM,EAAE,MAAM,OAAO,IAAI,uBAAoC,GAAG,CAAC;AACjE,WAAO,IAAI;AAAA,MACV;AAAA,MACA;AAAA,MACA;AAAA,IACD;AAAA,EACD;AACD;","names":[]}
@@ -620,6 +620,9 @@ class SQLiteDialect {
620
620
  case "SQLiteNumericBigInt": {
621
621
  return import_sql2.sql`cast(${name} as text) as ${import_sql2.sql.identifier(key)}`;
622
622
  }
623
+ case "SQLiteCustomColumn": {
624
+ return import_sql2.sql`${column.jsonSelectIdentifier(name, import_sql2.sql)} as ${import_sql2.sql.identifier(key)}`;
625
+ }
623
626
  default: {
624
627
  return import_sql2.sql`${name} as ${import_sql2.sql.identifier(key)}`;
625
628
  }