drizzle-orm 1.0.0-beta.1-6b935a0 → 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.
- package/gel-core/columns/custom.cjs +6 -6
- package/gel-core/columns/custom.cjs.map +1 -1
- package/gel-core/columns/custom.d.cts +90 -15
- package/gel-core/columns/custom.d.ts +90 -15
- package/gel-core/columns/custom.js +6 -6
- package/gel-core/columns/custom.js.map +1 -1
- package/gel-core/dialect.cjs +1 -1
- package/gel-core/dialect.cjs.map +1 -1
- package/gel-core/dialect.js +1 -1
- package/gel-core/dialect.js.map +1 -1
- package/mysql-core/columns/custom.cjs +7 -7
- package/mysql-core/columns/custom.cjs.map +1 -1
- package/mysql-core/columns/custom.d.cts +93 -15
- package/mysql-core/columns/custom.d.ts +93 -15
- package/mysql-core/columns/custom.js +7 -7
- package/mysql-core/columns/custom.js.map +1 -1
- package/mysql-core/dialect.cjs +1 -1
- package/mysql-core/dialect.cjs.map +1 -1
- package/mysql-core/dialect.js +1 -1
- package/mysql-core/dialect.js.map +1 -1
- package/package.json +1 -1
- package/pg-core/columns/custom.cjs +7 -7
- package/pg-core/columns/custom.cjs.map +1 -1
- package/pg-core/columns/custom.d.cts +92 -15
- package/pg-core/columns/custom.d.ts +92 -15
- package/pg-core/columns/custom.js +7 -7
- package/pg-core/columns/custom.js.map +1 -1
- package/pg-core/dialect.cjs +1 -1
- package/pg-core/dialect.cjs.map +1 -1
- package/pg-core/dialect.js +1 -1
- package/pg-core/dialect.js.map +1 -1
- package/singlestore-core/columns/custom.cjs +7 -7
- package/singlestore-core/columns/custom.cjs.map +1 -1
- package/singlestore-core/columns/custom.d.cts +93 -15
- package/singlestore-core/columns/custom.d.ts +93 -15
- package/singlestore-core/columns/custom.js +7 -7
- package/singlestore-core/columns/custom.js.map +1 -1
- package/sqlite-core/columns/custom.cjs +8 -8
- package/sqlite-core/columns/custom.cjs.map +1 -1
- package/sqlite-core/columns/custom.d.cts +94 -16
- package/sqlite-core/columns/custom.d.ts +94 -16
- package/sqlite-core/columns/custom.js +8 -8
- package/sqlite-core/columns/custom.js.map +1 -1
- package/sqlite-core/dialect.cjs +1 -1
- package/sqlite-core/dialect.cjs.map +1 -1
- package/sqlite-core/dialect.js +1 -1
- package/sqlite-core/dialect.js.map +1 -1
- package/version.cjs +1 -1
- package/version.d.cts +1 -1
- package/version.d.ts +1 -1
- package/version.js +1 -1
|
@@ -36,14 +36,14 @@ export declare class SingleStoreCustomColumn<T extends ColumnBaseConfig<'custom'
|
|
|
36
36
|
private mapTo?;
|
|
37
37
|
private mapFrom?;
|
|
38
38
|
private mapJson?;
|
|
39
|
-
private
|
|
39
|
+
private forJsonSelect?;
|
|
40
40
|
constructor(table: AnySingleStoreTable<{
|
|
41
41
|
name: T['tableName'];
|
|
42
42
|
}>, config: SingleStoreCustomColumnBuilder<T>['config']);
|
|
43
43
|
getSQLType(): string;
|
|
44
44
|
mapFromDriverValue(value: T['driverParam']): T['data'];
|
|
45
45
|
mapFromJsonValue(value: unknown): T['data'];
|
|
46
|
-
|
|
46
|
+
jsonSelectIdentifier(identifier: SQL, sql: SQLGenerator): SQL;
|
|
47
47
|
mapToDriverValue(value: T['data']): T['driverParam'];
|
|
48
48
|
}
|
|
49
49
|
export type CustomTypeValues = {
|
|
@@ -57,6 +57,15 @@ export type CustomTypeValues = {
|
|
|
57
57
|
* If you want your column to be `number` type after selecting/or on inserting - use `data: number`. Like `integer`
|
|
58
58
|
*/
|
|
59
59
|
data: unknown;
|
|
60
|
+
/**
|
|
61
|
+
* Type helper, that represents what type database driver is returning for specific database data type
|
|
62
|
+
*
|
|
63
|
+
* Needed only in case driver's output and input for type differ
|
|
64
|
+
*
|
|
65
|
+
* @default
|
|
66
|
+
* Defaults to `driverData`
|
|
67
|
+
*/
|
|
68
|
+
driverOutput?: unknown;
|
|
60
69
|
/**
|
|
61
70
|
* Type helper, that represents what type database driver is accepting for specific database data type
|
|
62
71
|
*/
|
|
@@ -129,7 +138,7 @@ export interface CustomTypeParams<T extends CustomTypeValues> {
|
|
|
129
138
|
*/
|
|
130
139
|
dataType: (config: T['config'] | (Equal<T['configRequired'], true> extends true ? never : undefined)) => string;
|
|
131
140
|
/**
|
|
132
|
-
* Optional mapping function,
|
|
141
|
+
* Optional mapping function, that is used to transform inputs from desired to be used in code format to one suitable for driver
|
|
133
142
|
* @example
|
|
134
143
|
* For example, when using jsonb we need to map JS/TS object to string before writing to database
|
|
135
144
|
* ```
|
|
@@ -140,45 +149,114 @@ export interface CustomTypeParams<T extends CustomTypeValues> {
|
|
|
140
149
|
*/
|
|
141
150
|
toDriver?: (value: T['data']) => T['driverData'] | SQL;
|
|
142
151
|
/**
|
|
143
|
-
* Optional mapping function, that is
|
|
152
|
+
* Optional mapping function, that is used for transforming data returned by driver to desired column's output format
|
|
144
153
|
* @example
|
|
145
154
|
* For example, when using timestamp we need to map string Date representation to JS Date
|
|
146
155
|
* ```
|
|
147
156
|
* fromDriver(value: string): Date {
|
|
148
157
|
* return new Date(value);
|
|
149
|
-
* }
|
|
158
|
+
* }
|
|
159
|
+
* ```
|
|
160
|
+
*
|
|
161
|
+
* It'll cause the returned data to change from:
|
|
162
|
+
* ```
|
|
163
|
+
* {
|
|
164
|
+
* customField: "2025-04-07 03:25:16.635";
|
|
165
|
+
* }
|
|
166
|
+
* ```
|
|
167
|
+
* to:
|
|
168
|
+
* ```
|
|
169
|
+
* {
|
|
170
|
+
* customField: new Date("2025-04-07 03:25:16.635");
|
|
171
|
+
* }
|
|
150
172
|
* ```
|
|
151
173
|
*/
|
|
152
|
-
fromDriver?: (value: T['driverData']) => T['data'];
|
|
174
|
+
fromDriver?: (value: 'driverOutput' extends keyof T ? T['driverOutput'] : T['driverData']) => T['data'];
|
|
153
175
|
/**
|
|
154
|
-
* Optional mapping function, that is
|
|
176
|
+
* Optional mapping function, that is used for transforming data returned by transofmed to JSON in database data to desired format
|
|
155
177
|
*
|
|
156
|
-
* Used by
|
|
178
|
+
* Used by relational queries
|
|
157
179
|
* @example
|
|
158
|
-
* For example, when
|
|
180
|
+
* For example, when querying bigint column via RQB or JSON funcitons, the result field will be returned as it's string representation, as opposed to bigint from regular query
|
|
181
|
+
* To handle that, we need a separate function to handle such field's mapping:
|
|
159
182
|
* ```
|
|
160
183
|
* fromJson(value: string): bigint {
|
|
161
184
|
* return BigInt(value);
|
|
162
185
|
* },
|
|
163
186
|
* ```
|
|
164
187
|
*
|
|
188
|
+
* It'll cause the returned data to change from:
|
|
189
|
+
* ```
|
|
190
|
+
* {
|
|
191
|
+
* customField: "5044565289845416380";
|
|
192
|
+
* }
|
|
193
|
+
* ```
|
|
194
|
+
* to:
|
|
195
|
+
* ```
|
|
196
|
+
* {
|
|
197
|
+
* customField: 5044565289845416380n;
|
|
198
|
+
* }
|
|
199
|
+
* ```
|
|
165
200
|
* @default
|
|
166
|
-
* Defaults to
|
|
201
|
+
* Defaults to {@link fromDriver} function
|
|
167
202
|
*/
|
|
168
203
|
fromJson?: (value: T['jsonData']) => T['data'];
|
|
169
204
|
/**
|
|
170
|
-
* Optional
|
|
205
|
+
* Optional selection modifier function, that is used for modifying selection of column inside JSON functions
|
|
206
|
+
*
|
|
207
|
+
* Additional mapping that could be required for such scenarios can be handled using {@link fromJson} function
|
|
171
208
|
*
|
|
172
|
-
* Used by
|
|
209
|
+
* Used by relational queries
|
|
173
210
|
* @example
|
|
174
211
|
* For example, when using bigint we need to cast field to text to preserve data integrity
|
|
175
212
|
* ```
|
|
176
|
-
*
|
|
177
|
-
* return sql`cast(${
|
|
213
|
+
* forJsonSelect(identifier: SQL, sql: SQLGenerator): SQL {
|
|
214
|
+
* return sql`cast(${identifier} as char)`
|
|
178
215
|
* },
|
|
179
216
|
* ```
|
|
217
|
+
*
|
|
218
|
+
* This will change query from:
|
|
219
|
+
* ```
|
|
220
|
+
* SELECT
|
|
221
|
+
* json_build_object('bigint', `t`.`bigint`)
|
|
222
|
+
* FROM
|
|
223
|
+
* (
|
|
224
|
+
* SELECT
|
|
225
|
+
* `table`.`custom_bigint` AS `bigint`
|
|
226
|
+
* FROM
|
|
227
|
+
* `table`
|
|
228
|
+
* ) AS `t`
|
|
229
|
+
* ```
|
|
230
|
+
* to:
|
|
231
|
+
* ```
|
|
232
|
+
* SELECT
|
|
233
|
+
* json_build_object('bigint', `t`.`bigint`)
|
|
234
|
+
* FROM
|
|
235
|
+
* (
|
|
236
|
+
* SELECT
|
|
237
|
+
* cast(`table`.`custom_bigint` as char) AS `bigint`
|
|
238
|
+
* FROM
|
|
239
|
+
* `table`
|
|
240
|
+
* ) AS `t`
|
|
241
|
+
* ```
|
|
242
|
+
*
|
|
243
|
+
* Returned by query object will change from:
|
|
244
|
+
* ```
|
|
245
|
+
* {
|
|
246
|
+
* bigint: 5044565289845416000; // Partial data loss due to direct conversion to JSON format
|
|
247
|
+
* }
|
|
248
|
+
* ```
|
|
249
|
+
* to:
|
|
250
|
+
* ```
|
|
251
|
+
* {
|
|
252
|
+
* bigint: "5044565289845416380"; // Data is preserved due to conversion of field to text before JSON-ification
|
|
253
|
+
* }
|
|
254
|
+
* ```
|
|
255
|
+
*
|
|
256
|
+
* @default
|
|
257
|
+
* Following types are being casted to text by default: `binary`, `varbinary`, `time`, `datetime`, `decimal`, `float`, 'bigint'
|
|
180
258
|
*/
|
|
181
|
-
|
|
259
|
+
forJsonSelect?: (identifier: SQL, sql: SQLGenerator) => SQL;
|
|
182
260
|
}
|
|
183
261
|
/**
|
|
184
262
|
* Custom singlestore database data type generator
|
|
@@ -22,14 +22,14 @@ class SingleStoreCustomColumn extends SingleStoreColumn {
|
|
|
22
22
|
mapTo;
|
|
23
23
|
mapFrom;
|
|
24
24
|
mapJson;
|
|
25
|
-
|
|
25
|
+
forJsonSelect;
|
|
26
26
|
constructor(table, config) {
|
|
27
27
|
super(table, config);
|
|
28
28
|
this.sqlName = config.customTypeParams.dataType(config.fieldConfig);
|
|
29
29
|
this.mapTo = config.customTypeParams.toDriver;
|
|
30
30
|
this.mapFrom = config.customTypeParams.fromDriver;
|
|
31
31
|
this.mapJson = config.customTypeParams.fromJson;
|
|
32
|
-
this.
|
|
32
|
+
this.forJsonSelect = config.customTypeParams.forJsonSelect;
|
|
33
33
|
}
|
|
34
34
|
getSQLType() {
|
|
35
35
|
return this.sqlName;
|
|
@@ -40,9 +40,9 @@ class SingleStoreCustomColumn extends SingleStoreColumn {
|
|
|
40
40
|
mapFromJsonValue(value) {
|
|
41
41
|
return typeof this.mapJson === "function" ? this.mapJson(value) : this.mapFromDriverValue(value);
|
|
42
42
|
}
|
|
43
|
-
|
|
44
|
-
if (typeof this.
|
|
45
|
-
return this.
|
|
43
|
+
jsonSelectIdentifier(identifier, sql) {
|
|
44
|
+
if (typeof this.forJsonSelect === "function")
|
|
45
|
+
return this.forJsonSelect(identifier, sql);
|
|
46
46
|
const rawType = this.getSQLType().toLowerCase();
|
|
47
47
|
const parenPos = rawType.indexOf("(");
|
|
48
48
|
const type = parenPos + 1 ? rawType.slice(0, parenPos) : rawType;
|
|
@@ -54,10 +54,10 @@ class SingleStoreCustomColumn extends SingleStoreColumn {
|
|
|
54
54
|
case "decimal":
|
|
55
55
|
case "float":
|
|
56
56
|
case "bigint": {
|
|
57
|
-
return sql`cast(${
|
|
57
|
+
return sql`cast(${identifier} as char)`;
|
|
58
58
|
}
|
|
59
59
|
default: {
|
|
60
|
-
return
|
|
60
|
+
return identifier;
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
63
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/singlestore-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 { AnySingleStoreTable } from '~/singlestore-core/table.ts';\nimport type { SQL, SQLGenerator } from '~/sql/sql.ts';\nimport { type Equal, getColumnNameAndConfig } from '~/utils.ts';\nimport { SingleStoreColumn, SingleStoreColumnBuilder } 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: 'SingleStoreCustomColumn';\n\t\tdata: T['data'];\n\t\tdriverParam: T['driverData'];\n\t\tenumValues: undefined;\n\t\tgenerated: undefined;\n\t}\n\t& (T['notNull'] extends true ? { notNull: true } : {})\n\t& (T['default'] extends true ? { hasDefault: true } : {});\n\nexport interface SingleStoreCustomColumnInnerConfig {\n\tcustomTypeValues: CustomTypeValues;\n}\n\nexport class SingleStoreCustomColumnBuilder<T extends ColumnBuilderBaseConfig<'custom', 'SingleStoreCustomColumn'>>\n\textends SingleStoreColumnBuilder<\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\tsinglestoreColumnBuilderBrand: 'SingleStoreCustomColumnBuilderBrand';\n\t\t}\n\t>\n{\n\tstatic override readonly [entityKind]: string = 'SingleStoreCustomColumnBuilder';\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', 'SingleStoreCustomColumn');\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: AnySingleStoreTable<{ name: TTableName }>,\n\t): SingleStoreCustomColumn<MakeColumnConfig<T, TTableName>> {\n\t\treturn new SingleStoreCustomColumn<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 SingleStoreCustomColumn<T extends ColumnBaseConfig<'custom', 'SingleStoreCustomColumn'>>\n\textends SingleStoreColumn<T>\n{\n\tstatic override readonly [entityKind]: string = 'SingleStoreCustomColumn';\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 wrapName?: (name: SQL, sql: SQLGenerator) => SQL;\n\n\tconstructor(\n\t\ttable: AnySingleStoreTable<{ name: T['tableName'] }>,\n\t\tconfig: SingleStoreCustomColumnBuilder<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.wrapName = config.customTypeParams.jsonWrap;\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\tjsonWrapName(name: SQL, sql: SQLGenerator): SQL {\n\t\tif (typeof this.wrapName === 'function') return this.wrapName(name, 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 'binary':\n\t\t\tcase 'varbinary':\n\t\t\tcase 'time':\n\t\t\tcase 'datetime':\n\t\t\tcase 'decimal':\n\t\t\tcase 'float':\n\t\t\tcase 'bigint': {\n\t\t\t\treturn sql`cast(${name} as char)`;\n\t\t\t}\n\t\t\tdefault: {\n\t\t\t\treturn name;\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 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, 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\t/**\n\t * Optional mapping function, that is responsible for data mapping from database's JSON format to JS/TS code\n\t *\n\t * Used by Relational Queries V2\n\t * @example\n\t * For example, when using bigint we need to map it's string representation to JS bigint\n\t * ```\n\t * fromJson(value: string): bigint {\n\t * \treturn BigInt(value);\n\t * },\n\t * ```\n\t *\n\t * @default\n\t * Defaults to `fromDriver` function\n\t */\n\tfromJson?: (value: T['jsonData']) => T['data'];\n\n\t/**\n\t * Optional name wrapper function, that is responsible for modifying field in selection before it's casted to JSON\n\t *\n\t * Used by Relational Queries V2\n\t * @example\n\t * For example, when using bigint we need to cast field to text to preserve data integrity\n\t * ```\n\t * jsonWrap(name: SQL, sql: SQLGenerator): SQL {\n\t * \treturn sql`cast(${name} as char)`\n\t * },\n\t * ```\n\t */\n\tjsonWrap?: (name: SQL, sql: SQLGenerator) => SQL;\n}\n\n/**\n * Custom singlestore 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): SingleStoreCustomColumnBuilder<ConvertCustomConfig<'', T>>;\n\t\t<TName extends string>(\n\t\t\tdbName: TName,\n\t\t\tfieldConfig: T['config'],\n\t\t): SingleStoreCustomColumnBuilder<ConvertCustomConfig<TName, T>>;\n\t}\n\t: {\n\t\t(): SingleStoreCustomColumnBuilder<ConvertCustomConfig<'', T>>;\n\t\t<TConfig extends Record<string, any> & T['config']>(\n\t\t\tfieldConfig?: TConfig,\n\t\t): SingleStoreCustomColumnBuilder<ConvertCustomConfig<'', T>>;\n\t\t<TName extends string>(\n\t\t\tdbName: TName,\n\t\t\tfieldConfig?: T['config'],\n\t\t): SingleStoreCustomColumnBuilder<ConvertCustomConfig<TName, T>>;\n\t}\n{\n\treturn <TName extends string>(\n\t\ta?: TName | T['config'],\n\t\tb?: T['config'],\n\t): SingleStoreCustomColumnBuilder<ConvertCustomConfig<TName, T>> => {\n\t\tconst { name, config } = getColumnNameAndConfig<T['config']>(a, b);\n\t\treturn new SingleStoreCustomColumnBuilder(name as ConvertCustomConfig<TName, T>['name'], config, customTypeParams);\n\t};\n}\n"],"mappings":"AAEA,SAAS,kBAAkB;AAG3B,SAAqB,8BAA8B;AACnD,SAAS,mBAAmB,gCAAgC;AAmBrD,MAAM,uCACJ,yBAUT;AAAA,EACC,QAA0B,UAAU,IAAY;AAAA,EAEhD,YACC,MACA,aACA,kBACC;AACD,UAAM,MAAM,UAAU,yBAAyB;AAC/C,SAAK,OAAO,cAAc;AAC1B,SAAK,OAAO,mBAAmB;AAAA,EAChC;AAAA;AAAA,EAGA,MACC,OAC2D;AAC3D,WAAO,IAAI;AAAA,MACV;AAAA,MACA,KAAK;AAAA,IACN;AAAA,EACD;AACD;AAEO,MAAM,gCACJ,kBACT;AAAA,EACC,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,WAAW,OAAO,iBAAiB;AAAA,EACzC;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,aAAa,MAAW,KAAwB;AAC/C,QAAI,OAAO,KAAK,aAAa;AAAY,aAAO,KAAK,SAAS,MAAM,GAAG;AAEvE,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;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK,UAAU;AACd,eAAO,WAAW,IAAI;AAAA,MACvB;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;AAuJO,SAAS,WACf,kBAoBD;AACC,SAAO,CACN,GACA,MACmE;AACnE,UAAM,EAAE,MAAM,OAAO,IAAI,uBAAoC,GAAG,CAAC;AACjE,WAAO,IAAI,+BAA+B,MAA+C,QAAQ,gBAAgB;AAAA,EAClH;AACD;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/singlestore-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 { AnySingleStoreTable } from '~/singlestore-core/table.ts';\nimport type { SQL, SQLGenerator } from '~/sql/sql.ts';\nimport { type Equal, getColumnNameAndConfig } from '~/utils.ts';\nimport { SingleStoreColumn, SingleStoreColumnBuilder } 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: 'SingleStoreCustomColumn';\n\t\tdata: T['data'];\n\t\tdriverParam: T['driverData'];\n\t\tenumValues: undefined;\n\t\tgenerated: undefined;\n\t}\n\t& (T['notNull'] extends true ? { notNull: true } : {})\n\t& (T['default'] extends true ? { hasDefault: true } : {});\n\nexport interface SingleStoreCustomColumnInnerConfig {\n\tcustomTypeValues: CustomTypeValues;\n}\n\nexport class SingleStoreCustomColumnBuilder<T extends ColumnBuilderBaseConfig<'custom', 'SingleStoreCustomColumn'>>\n\textends SingleStoreColumnBuilder<\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\tsinglestoreColumnBuilderBrand: 'SingleStoreCustomColumnBuilderBrand';\n\t\t}\n\t>\n{\n\tstatic override readonly [entityKind]: string = 'SingleStoreCustomColumnBuilder';\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', 'SingleStoreCustomColumn');\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: AnySingleStoreTable<{ name: TTableName }>,\n\t): SingleStoreCustomColumn<MakeColumnConfig<T, TTableName>> {\n\t\treturn new SingleStoreCustomColumn<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 SingleStoreCustomColumn<T extends ColumnBaseConfig<'custom', 'SingleStoreCustomColumn'>>\n\textends SingleStoreColumn<T>\n{\n\tstatic override readonly [entityKind]: string = 'SingleStoreCustomColumn';\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: AnySingleStoreTable<{ name: T['tableName'] }>,\n\t\tconfig: SingleStoreCustomColumnBuilder<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 'binary':\n\t\t\tcase 'varbinary':\n\t\t\tcase 'time':\n\t\t\tcase 'datetime':\n\t\t\tcase 'decimal':\n\t\t\tcase 'float':\n\t\t\tcase 'bigint': {\n\t\t\t\treturn sql`cast(${identifier} as char)`;\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 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 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 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-07 03:25:16.635\";\n\t * }\n\t * ```\n\t * to:\n\t * ```\n\t * {\n\t * \tcustomField: new Date(\"2025-04-07 03:25:16.635\");\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 bigint column via RQB or JSON funcitons, the result field will be returned as it's string representation, as opposed to bigint 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): bigint {\n\t * \treturn BigInt(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: \"5044565289845416380\";\n\t * }\n\t * ```\n\t * to:\n\t * ```\n\t * {\n\t * \tcustomField: 5044565289845416380n;\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 bigint 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 char)`\n\t * },\n\t * ```\n\t *\n\t * This will change query from:\n\t * ```\n\t * SELECT\n\t * \tjson_build_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_build_object('bigint', `t`.`bigint`)\n\t * \tFROM\n\t * \t(\n\t * \t\tSELECT\n\t * \t\tcast(`table`.`custom_bigint` as char) 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: `binary`, `varbinary`, `time`, `datetime`, `decimal`, `float`, 'bigint'\n\t */\n\tforJsonSelect?: (identifier: SQL, sql: SQLGenerator) => SQL;\n}\n\n/**\n * Custom singlestore 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): SingleStoreCustomColumnBuilder<ConvertCustomConfig<'', T>>;\n\t\t<TName extends string>(\n\t\t\tdbName: TName,\n\t\t\tfieldConfig: T['config'],\n\t\t): SingleStoreCustomColumnBuilder<ConvertCustomConfig<TName, T>>;\n\t}\n\t: {\n\t\t(): SingleStoreCustomColumnBuilder<ConvertCustomConfig<'', T>>;\n\t\t<TConfig extends Record<string, any> & T['config']>(\n\t\t\tfieldConfig?: TConfig,\n\t\t): SingleStoreCustomColumnBuilder<ConvertCustomConfig<'', T>>;\n\t\t<TName extends string>(\n\t\t\tdbName: TName,\n\t\t\tfieldConfig?: T['config'],\n\t\t): SingleStoreCustomColumnBuilder<ConvertCustomConfig<TName, T>>;\n\t}\n{\n\treturn <TName extends string>(\n\t\ta?: TName | T['config'],\n\t\tb?: T['config'],\n\t): SingleStoreCustomColumnBuilder<ConvertCustomConfig<TName, T>> => {\n\t\tconst { name, config } = getColumnNameAndConfig<T['config']>(a, b);\n\t\treturn new SingleStoreCustomColumnBuilder(name as ConvertCustomConfig<TName, T>['name'], config, customTypeParams);\n\t};\n}\n"],"mappings":"AAEA,SAAS,kBAAkB;AAG3B,SAAqB,8BAA8B;AACnD,SAAS,mBAAmB,gCAAgC;AAmBrD,MAAM,uCACJ,yBAUT;AAAA,EACC,QAA0B,UAAU,IAAY;AAAA,EAEhD,YACC,MACA,aACA,kBACC;AACD,UAAM,MAAM,UAAU,yBAAyB;AAC/C,SAAK,OAAO,cAAc;AAC1B,SAAK,OAAO,mBAAmB;AAAA,EAChC;AAAA;AAAA,EAGA,MACC,OAC2D;AAC3D,WAAO,IAAI;AAAA,MACV;AAAA,MACA,KAAK;AAAA,IACN;AAAA,EACD;AACD;AAEO,MAAM,gCACJ,kBACT;AAAA,EACC,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;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK,UAAU;AACd,eAAO,WAAW,UAAU;AAAA,MAC7B;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,MACmE;AACnE,UAAM,EAAE,MAAM,OAAO,IAAI,uBAAoC,GAAG,CAAC;AACjE,WAAO,IAAI,+BAA+B,MAA+C,QAAQ,gBAAgB;AAAA,EAClH;AACD;","names":[]}
|
|
@@ -47,14 +47,14 @@ class SQLiteCustomColumn extends import_common.SQLiteColumn {
|
|
|
47
47
|
mapTo;
|
|
48
48
|
mapFrom;
|
|
49
49
|
mapJson;
|
|
50
|
-
|
|
50
|
+
forJsonSelect;
|
|
51
51
|
constructor(table, config) {
|
|
52
52
|
super(table, config);
|
|
53
53
|
this.sqlName = config.customTypeParams.dataType(config.fieldConfig);
|
|
54
54
|
this.mapTo = config.customTypeParams.toDriver;
|
|
55
55
|
this.mapFrom = config.customTypeParams.fromDriver;
|
|
56
56
|
this.mapJson = config.customTypeParams.fromJson;
|
|
57
|
-
this.
|
|
57
|
+
this.forJsonSelect = config.customTypeParams.forJsonSelect;
|
|
58
58
|
}
|
|
59
59
|
getSQLType() {
|
|
60
60
|
return this.sqlName;
|
|
@@ -65,9 +65,9 @@ class SQLiteCustomColumn extends import_common.SQLiteColumn {
|
|
|
65
65
|
mapFromJsonValue(value) {
|
|
66
66
|
return typeof this.mapJson === "function" ? this.mapJson(value) : this.mapFromDriverValue(value);
|
|
67
67
|
}
|
|
68
|
-
|
|
69
|
-
if (typeof this.
|
|
70
|
-
return this.
|
|
68
|
+
jsonSelectIdentifier(identifier, sql) {
|
|
69
|
+
if (typeof this.forJsonSelect === "function")
|
|
70
|
+
return this.forJsonSelect(identifier, sql);
|
|
71
71
|
const rawType = this.getSQLType().toLowerCase();
|
|
72
72
|
const parenPos = rawType.indexOf("(");
|
|
73
73
|
const type = parenPos + 1 ? rawType.slice(0, parenPos) : rawType;
|
|
@@ -75,13 +75,13 @@ class SQLiteCustomColumn extends import_common.SQLiteColumn {
|
|
|
75
75
|
case "numeric":
|
|
76
76
|
case "decimal":
|
|
77
77
|
case "bigint": {
|
|
78
|
-
return sql`cast(${
|
|
78
|
+
return sql`cast(${identifier} as text)`;
|
|
79
79
|
}
|
|
80
80
|
case "blob": {
|
|
81
|
-
return sql`hex(${
|
|
81
|
+
return sql`hex(${identifier})`;
|
|
82
82
|
}
|
|
83
83
|
default: {
|
|
84
|
-
return
|
|
84
|
+
return identifier;
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
87
|
}
|
|
@@ -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, 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 wrapName?: (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.wrapName = config.customTypeParams.jsonWrap;\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\tjsonWrapName(name: SQL, sql: SQLGenerator): SQL {\n\t\tif (typeof this.wrapName === 'function') return this.wrapName(name, 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(${name} as text)`;\n\t\t\t}\n\t\t\tcase 'blob': {\n\t\t\t\treturn sql`hex(${name})`;\n\t\t\t}\n\t\t\tdefault: {\n\t\t\t\treturn name;\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 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, 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\t/**\n\t * Optional mapping function, that is responsible for data mapping from database's JSON format to JS/TS code\n\t *\n\t * Used by Relational Queries V2\n\t * @example\n\t * For example, when using blob we need to map it's hex representation back to Buffer\n\t * ```\n\t * fromJson(value: string): Buffer {\n\t * \treturn Buffer.from(value, 'hex');\n\t * },\n\t * ```\n\t *\n\t * @default\n\t * Defaults to `fromDriver` function\n\t */\n\tfromJson?: (value: T['jsonData']) => T['data'];\n\n\t/**\n\t * Optional name wrapper function, that is responsible for modifying field in selection before it's casted to JSON\n\t *\n\t * Used by Relational Queries V2\n\t * @example\n\t * For example, when using blob we need to cast field to hex to be able to query it in JSON fields\n\t * ```\n\t * jsonWrap(name: SQL, sql: SQLGenerator): SQL {\n\t * \treturn sql`hex(${name})`\n\t * },\n\t * ```\n\t */\n\tjsonWrap?: (name: 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,WAAW,OAAO,iBAAiB;AAAA,EACzC;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,aAAa,MAAW,KAAwB;AAC/C,QAAI,OAAO,KAAK,aAAa;AAAY,aAAO,KAAK,SAAS,MAAM,GAAG;AAEvE,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,IAAI;AAAA,MACvB;AAAA,MACA,KAAK,QAAQ;AACZ,eAAO,UAAU,IAAI;AAAA,MACtB;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;AAuJO,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":[]}
|
|
@@ -35,14 +35,14 @@ export declare class SQLiteCustomColumn<T extends ColumnBaseConfig<'custom', 'SQ
|
|
|
35
35
|
private mapTo?;
|
|
36
36
|
private mapFrom?;
|
|
37
37
|
private mapJson?;
|
|
38
|
-
private
|
|
38
|
+
private forJsonSelect?;
|
|
39
39
|
constructor(table: AnySQLiteTable<{
|
|
40
40
|
name: T['tableName'];
|
|
41
41
|
}>, config: SQLiteCustomColumnBuilder<T>['config']);
|
|
42
42
|
getSQLType(): string;
|
|
43
43
|
mapFromDriverValue(value: T['driverParam']): T['data'];
|
|
44
44
|
mapFromJsonValue(value: unknown): T['data'];
|
|
45
|
-
|
|
45
|
+
jsonSelectIdentifier(identifier: SQL, sql: SQLGenerator): SQL;
|
|
46
46
|
mapToDriverValue(value: T['data']): T['driverParam'];
|
|
47
47
|
}
|
|
48
48
|
export type CustomTypeValues = {
|
|
@@ -60,6 +60,15 @@ export type CustomTypeValues = {
|
|
|
60
60
|
* Type helper, that represents what type database driver is accepting for specific database data type
|
|
61
61
|
*/
|
|
62
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;
|
|
63
72
|
/**
|
|
64
73
|
* Type helper, that represents what type field returns after being aggregated to JSON
|
|
65
74
|
*/
|
|
@@ -128,7 +137,7 @@ export interface CustomTypeParams<T extends CustomTypeValues> {
|
|
|
128
137
|
*/
|
|
129
138
|
dataType: (config: T['config'] | (Equal<T['configRequired'], true> extends true ? never : undefined)) => string;
|
|
130
139
|
/**
|
|
131
|
-
* Optional mapping function,
|
|
140
|
+
* Optional mapping function, that is used to transform inputs from desired to be used in code format to one suitable for driver
|
|
132
141
|
* @example
|
|
133
142
|
* For example, when using jsonb we need to map JS/TS object to string before writing to database
|
|
134
143
|
* ```
|
|
@@ -139,45 +148,114 @@ export interface CustomTypeParams<T extends CustomTypeValues> {
|
|
|
139
148
|
*/
|
|
140
149
|
toDriver?: (value: T['data']) => T['driverData'] | SQL;
|
|
141
150
|
/**
|
|
142
|
-
* Optional mapping function, that is
|
|
151
|
+
* Optional mapping function, that is used for transforming data returned by driver to desired column's output format
|
|
143
152
|
* @example
|
|
144
153
|
* For example, when using timestamp we need to map string Date representation to JS Date
|
|
145
154
|
* ```
|
|
146
155
|
* fromDriver(value: string): Date {
|
|
147
156
|
* return new Date(value);
|
|
148
|
-
* }
|
|
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
|
+
* }
|
|
149
171
|
* ```
|
|
150
172
|
*/
|
|
151
|
-
fromDriver?: (value: T['driverData']) => T['data'];
|
|
173
|
+
fromDriver?: (value: 'driverOutput' extends keyof T ? T['driverOutput'] : T['driverData']) => T['data'];
|
|
152
174
|
/**
|
|
153
|
-
* Optional mapping function, that is
|
|
175
|
+
* Optional mapping function, that is used for transforming data returned by transofmed to JSON in database data to desired format
|
|
154
176
|
*
|
|
155
|
-
* Used by
|
|
177
|
+
* Used by relational queries
|
|
156
178
|
* @example
|
|
157
|
-
* For example, when
|
|
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:
|
|
158
181
|
* ```
|
|
159
182
|
* fromJson(value: string): Buffer {
|
|
160
183
|
* return Buffer.from(value, 'hex');
|
|
161
184
|
* },
|
|
162
185
|
* ```
|
|
163
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
|
+
* ```
|
|
164
199
|
* @default
|
|
165
|
-
* Defaults to
|
|
200
|
+
* Defaults to {@link fromDriver} function
|
|
166
201
|
*/
|
|
167
202
|
fromJson?: (value: T['jsonData']) => T['data'];
|
|
168
203
|
/**
|
|
169
|
-
* Optional
|
|
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
|
|
170
207
|
*
|
|
171
|
-
* Used by
|
|
208
|
+
* Used by relational queries
|
|
172
209
|
* @example
|
|
173
|
-
* For example, when using
|
|
210
|
+
* For example, when using numeric field for bigint storage we need to cast field to text to preserve data integrity
|
|
174
211
|
* ```
|
|
175
|
-
*
|
|
176
|
-
* return sql`
|
|
212
|
+
* forJsonSelect(identifier: SQL, sql: SQLGenerator): SQL {
|
|
213
|
+
* return sql`cast(${identifier} as text)`
|
|
177
214
|
* },
|
|
178
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)
|
|
179
257
|
*/
|
|
180
|
-
|
|
258
|
+
forJsonSelect?: (identifier: SQL, sql: SQLGenerator) => SQL;
|
|
181
259
|
}
|
|
182
260
|
/**
|
|
183
261
|
* Custom sqlite database data type generator
|