All files / third-parties/drizzle-adapter/src/ydb-core/columns custom.ts

100% Statements 17/17
90% Branches 9/10
100% Functions 9/9
100% Lines 17/17

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142                                186x                                                                                         34x             186x 186x 186x           186x                   34x             186x 186x 186x 186x       102x       37x       66x                                                       778x 186x 186x      
import type {
	ColumnBuilderBaseConfig,
	ColumnBuilderRuntimeConfig,
	MakeColumnConfig,
} from 'drizzle-orm/column-builder'
import type { ColumnBaseConfig } from 'drizzle-orm/column'
import { entityKind } from 'drizzle-orm/entity'
import type { SQL } from 'drizzle-orm/sql/sql'
import type { Table } from 'drizzle-orm/table'
import { type Equal } from 'drizzle-orm/utils'
import { YdbColumn, YdbColumnBuilder } from './common.js'
 
function getColumnNameAndConfig<TConfig extends Record<string, any> | undefined>(
	a: string | TConfig | undefined,
	b: TConfig | undefined
) {
	return {
		name: typeof a === 'string' && a.length > 0 ? a : '',
		config: typeof a === 'object' ? a : b,
	}
}
 
export type ConvertCustomConfig<TName extends string, T extends Partial<CustomTypeValues>> = {
	name: TName
	dataType: 'custom'
	columnType: 'YdbCustomColumn'
	data: T['data']
	driverParam: T['driverData']
	enumValues: undefined
} & (T['notNull'] extends true ? { notNull: true } : {}) &
	(T['default'] extends true ? { hasDefault: true } : {})
 
export interface CustomTypeValues {
	data: unknown
	driverData?: unknown
	config?: Record<string, any>
	configRequired?: boolean
	notNull?: boolean
	default?: boolean
}
 
export interface CustomTypeParams<T extends CustomTypeValues> {
	dataType: (
		config: T['config'] | (Equal<T['configRequired'], true> extends true ? never : undefined)
	) => string
	toDriver?: (value: T['data']) => T['driverData'] | SQL
	fromDriver?: (value: T['driverData']) => T['data']
}
 
export class YdbCustomColumnBuilder<
	T extends ColumnBuilderBaseConfig<'custom', 'YdbCustomColumn'>,
> extends YdbColumnBuilder<
	T,
	{
		fieldConfig: CustomTypeValues['config']
		customTypeParams: CustomTypeParams<any>
	},
	{
		ydbColumnBuilderBrand: 'YdbCustomColumnBuilderBrand'
	}
> {
	static override readonly [entityKind]: string = 'YdbCustomColumnBuilder'
 
	constructor(
		name: T['name'],
		fieldConfig: CustomTypeValues['config'],
		customTypeParams: CustomTypeParams<any>
	) {
		super(name, 'custom', 'YdbCustomColumn')
		this.config.fieldConfig = fieldConfig
		this.config.customTypeParams = customTypeParams
	}
 
	override build<TTable extends Table>(
		table: TTable
	): YdbCustomColumn<MakeColumnConfig<T, TTable['_']['name']>> {
		return new YdbCustomColumn<MakeColumnConfig<T, TTable['_']['name']>>(
			table,
			this.config as ColumnBuilderRuntimeConfig<any, any>
		)
	}
}
 
export class YdbCustomColumn<
	T extends ColumnBaseConfig<'custom', 'YdbCustomColumn'>,
> extends YdbColumn<T> {
	static override readonly [entityKind]: string = 'YdbCustomColumn'
 
	readonly #sqlName: string
	readonly #mapTo: ((value: T['data']) => T['driverParam'] | SQL) | undefined
	readonly #mapFrom: ((value: T['driverParam']) => T['data']) | undefined
 
	constructor(table: Table, config: YdbCustomColumnBuilder<any>['config']) {
		super(table, config)
		this.#sqlName = config.customTypeParams.dataType(config.fieldConfig)
		this.#mapTo = config.customTypeParams.toDriver
		this.#mapFrom = config.customTypeParams.fromDriver
	}
 
	override getSQLType(): string {
		return this.#sqlName
	}
 
	override mapFromDriverValue(value: T['driverParam']): T['data'] {
		return typeof this.#mapFrom === 'function' ? this.#mapFrom(value) : (value as T['data'])
	}
 
	override mapToDriverValue(value: T['data']): T['driverParam'] {
		return typeof this.#mapTo === 'function'
			? (this.#mapTo(value) as T['driverParam'])
			: (value as T['driverParam'])
	}
}
 
export function customType<T extends CustomTypeValues = CustomTypeValues>(
	customTypeParams: CustomTypeParams<T>
): Equal<T['configRequired'], true> extends true
	? {
			<TConfig extends Record<string, any> & T['config']>(
				fieldConfig: TConfig
			): YdbCustomColumnBuilder<ConvertCustomConfig<'', T>>
			<TName extends string>(
				dbName: TName,
				fieldConfig: T['config']
			): YdbCustomColumnBuilder<ConvertCustomConfig<TName, T>>
		}
	: {
			(): YdbCustomColumnBuilder<ConvertCustomConfig<'', T>>
			<TConfig extends Record<string, any> & T['config']>(
				fieldConfig?: TConfig
			): YdbCustomColumnBuilder<ConvertCustomConfig<'', T>>
			<TName extends string>(
				dbName: TName,
				fieldConfig?: T['config']
			): YdbCustomColumnBuilder<ConvertCustomConfig<TName, T>>
		} {
	return ((a?: string | T['config'], b?: T['config']) => {
		let { name, config } = getColumnNameAndConfig<T['config']>(a, b)
		return new YdbCustomColumnBuilder(name as any, config, customTypeParams)
	}) as any
}