{"version":3,"file":"custom.cjs","names":["SingleStoreColumnBuilder","entityKind","SingleStoreColumn"],"sources":["../../../src/singlestore-core/columns/custom.ts"],"sourcesContent":["import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig } from '~/column-builder.ts';\nimport type { ColumnBaseConfig } from '~/column.ts';\nimport { entityKind } from '~/entity.ts';\nimport type { AnySingleStoreTable, SingleStoreTable } 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<T extends Partial<CustomTypeValues>> =\n\t& {\n\t\tdataType: 'custom';\n\t\tdata: T['data'];\n\t\tdriverParam: T['driverData'];\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'>>\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>\n{\n\tstatic override readonly [entityKind]: string = 'SingleStoreCustomColumnBuilder';\n\n\tconstructor(\n\t\tname: string,\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\toverride build(table: SingleStoreTable) {\n\t\treturn new SingleStoreCustomColumn(\n\t\t\ttable,\n\t\t\tthis.config as any,\n\t\t);\n\t}\n}\n\nexport class SingleStoreCustomColumn<T extends ColumnBaseConfig<'custom'>> extends SingleStoreColumn<T> {\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: ColumnBuilderRuntimeConfig<T['data']> & {\n\t\t\tfieldConfig: CustomTypeValues['config'];\n\t\t\tcustomTypeParams: CustomTypeParams<any>;\n\t\t},\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 interface 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 * Defaults to {@link 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](https://orm.drizzle.team/docs/rqb-v2)\n\t *\n\t * Defaults to {@link fromDriver} function\n\t * @example\n\t * For example, when querying bigint column via [RQB](https://orm.drizzle.team/docs/rqb-v2) or [JSON functions](https://orm.drizzle.team/docs/json-functions), 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 */\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](https://orm.drizzle.team/docs/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](https://orm.drizzle.team/docs/rqb-v2)\n\t *\n\t * Following types are being casted to text by default: `binary`, `varbinary`, `time`, `datetime`, `decimal`, `float`, `bigint`\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\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(\n\t\t\tdbname: string,\n\t\t\tfieldConfig: T['config'],\n\t\t): SingleStoreCustomColumnBuilder<ConvertCustomConfig<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(\n\t\t\tdbname: string,\n\t\t\tfieldConfig?: T['config'],\n\t\t): SingleStoreCustomColumnBuilder<ConvertCustomConfig<T>>;\n\t}\n{\n\treturn (\n\t\ta?: string | T['config'],\n\t\tb?: T['config'],\n\t): SingleStoreCustomColumnBuilder<ConvertCustomConfig<T>> => {\n\t\tconst { name, config } = getColumnNameAndConfig<T['config']>(a, b);\n\t\treturn new SingleStoreCustomColumnBuilder(name, config, customTypeParams);\n\t};\n}\n"],"mappings":";;;;;;;AAqBA,IAAa,iCAAb,cACSA,iEAOT;CACC,QAA0BC,0BAAsB;CAEhD,YACC,MACA,aACA,kBACC;AACD,QAAM,MAAM,UAAU,0BAA0B;AAChD,OAAK,OAAO,cAAc;AAC1B,OAAK,OAAO,mBAAmB;;;CAIhC,AAAS,MAAM,OAAyB;AACvC,SAAO,IAAI,wBACV,OACA,KAAK,OACL;;;AAIH,IAAa,0BAAb,cAAmFC,0DAAqB;CACvG,QAA0BD,0BAAsB;CAEhD,AAAQ;CACR,AAAQ;CACR,AAAQ;CACR,AAAQ;CACR,AAAQ;CAER,YACC,OACA,QAIC;AACD,QAAM,OAAO,OAAO;AACpB,OAAK,UAAU,OAAO,iBAAiB,SAAS,OAAO,YAAY;AACnE,OAAK,QAAQ,OAAO,iBAAiB;AACrC,OAAK,UAAU,OAAO,iBAAiB;AACvC,OAAK,UAAU,OAAO,iBAAiB;AACvC,OAAK,gBAAgB,OAAO,iBAAiB;;CAG9C,aAAqB;AACpB,SAAO,KAAK;;CAGb,AAAS,sBAAsB,UAAuC;AACrE,SAAO,OAAO,KAAK,YAAY,aAAa,KAAK,QAAQ,MAAM,GAAG;;CAGnE,iBAAiB,OAA2B;AAC3C,SAAO,OAAO,KAAK,YAAY,aAAa,KAAK,QAAQ,MAAM,GAAG,KAAK,mBAAmB,MAAM;;CAGjG,qBAAqB,YAAiB,KAAwB;AAC7D,MAAI,OAAO,KAAK,kBAAkB,WAAY,QAAO,KAAK,cAAc,YAAY,IAAI;EAExF,MAAM,UAAU,KAAK,YAAY,CAAC,aAAa;EAC/C,MAAM,WAAW,QAAQ,QAAQ,IAAI;AAGrC,UAFc,WAAW,IAAK,QAAQ,MAAM,GAAG,SAAS,GAAG,SAE3D;GACC,KAAK;GACL,KAAK;GACL,KAAK;GACL,KAAK;GACL,KAAK;GACL,KAAK;GACL,KAAK,SACJ,QAAO,GAAG,QAAQ,WAAW;GAE9B,QACC,QAAO;;;CAKV,AAAS,oBAAoB,UAAuC;AACnE,SAAO,OAAO,KAAK,UAAU,aAAa,KAAK,MAAM,MAAM,GAAG;;;;;;AAsOhE,SAAgB,WACf,kBAoBD;AACC,SACC,GACA,MAC4D;EAC5D,MAAM,EAAE,MAAM,kDAA+C,GAAG,EAAE;AAClE,SAAO,IAAI,+BAA+B,MAAM,QAAQ,iBAAiB"}