Skip to content

Commit

Permalink
new blob column type
Browse files Browse the repository at this point in the history
  • Loading branch information
Rodriguespn committed Jul 25, 2024
1 parent a623dce commit 10aec33
Showing 1 changed file with 96 additions and 59 deletions.
155 changes: 96 additions & 59 deletions drizzle-orm/src/singlestore-core/columns/blob.ts
Original file line number Diff line number Diff line change
@@ -1,121 +1,158 @@
import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder';
import type { ColumnBaseConfig } from '~/column.ts';
import { entityKind } from '~/entity.ts';
import type { AnySingleStoreTable } from '~/singlestore-core/table';
import { sql } from '~/sql/sql.ts';
import type { Equal } from '~/utils';
import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts';
import type { AnySingleStoreTable } from '../table';

export type SingleStoreBlobBuilderInitial<TName extends string> = SingleStoreBlobBuilder<{
type BlobMode = 'buffer' | 'json' | 'bigint';

export type SingleStoreBigIntBuilderInitial<TName extends string> = SingleStoreBigIntBuilder<{
name: TName;
dataType: 'string';
columnType: 'SingleStoreBlob';
data: Uint8Array;
driverParam: string;
dataType: 'bigint';
columnType: 'SingleStoreBigInt';
data: bigint;
driverParam: Buffer;
enumValues: undefined;
generated: undefined;
}>;

export class SingleStoreBlobBuilder<T extends ColumnBuilderBaseConfig<'string', 'SingleStoreBlob'>>
extends SingleStoreColumnBuilder<T, SingleStoreBlobConfig>
export class SingleStoreBigIntBuilder<T extends ColumnBuilderBaseConfig<'bigint', 'SingleStoreBigInt'>>
extends SingleStoreColumnBuilder<T>
{
static readonly [entityKind]: string = 'SingleStoreBlobBuilder';
static readonly [entityKind]: string = 'SingleStoreBigIntBuilder';

constructor(name: T['name'], _config?: SingleStoreBlobConfig) {
super(name, 'string', 'SingleStoreBlob');
constructor(name: T['name']) {
super(name, 'bigint', 'SingleStoreBigInt');
}

/** @internal */
override build<TTableName extends string>(
table: AnySingleStoreTable<{ name: TTableName }>,
): SingleStoreBlob<MakeColumnConfig<T, TTableName>> {
return new SingleStoreBlob(table, this.config as ColumnBuilderRuntimeConfig<any, any>);
): SingleStoreBigInt<MakeColumnConfig<T, TTableName>> {
return new SingleStoreBigInt<MakeColumnConfig<T, TTableName>>(table, this.config as ColumnBuilderRuntimeConfig<any>);
}
}

export class SingleStoreBlob<T extends ColumnBaseConfig<'string', 'SingleStoreBlob'>> extends SingleStoreColumn<T> {
static readonly [entityKind]: string = 'SingleStoreBlob';
export class SingleStoreBigInt<T extends ColumnBaseConfig<'bigint', 'SingleStoreBigInt'>> extends SingleStoreColumn<T> {
static readonly [entityKind]: string = 'SingleStoreBigInt';

constructor(table: AnySingleStoreTable<{ name: T['tableName'] }>, config: SingleStoreBlobBuilder<T>['config']) {
super(table, config);
getSQLType(): string {
return 'blob';
}

getSQLType(): string {
return 'binary(16)';
override mapFromDriverValue(value: Buffer): bigint {
return BigInt(value.toString());
}

override mapToDriverValue(value: string) {
return sql`UNHEX(REPLACE(${value}, "-", ""))`;
override mapToDriverValue(value: bigint): Buffer {
return Buffer.from(value.toString());
}
}

export type SingleStoreBlobStringBuilderInitial<TName extends string> = SingleStoreBlobStringBuilder<{
export type SingleStoreBlobJsonBuilderInitial<TName extends string> = SingleStoreBlobJsonBuilder<{
name: TName;
dataType: 'string';
columnType: 'SingleStoreBlobString';
data: string;
driverParam: string;
dataType: 'json';
columnType: 'SingleStoreBlobJson';
data: unknown;
driverParam: Buffer;
enumValues: undefined;
generated: undefined;
}>;

export class SingleStoreBlobStringBuilder<T extends ColumnBuilderBaseConfig<'string', 'SingleStoreBlobString'>>
extends SingleStoreColumnBuilder<T, SingleStoreBlobConfig>
export class SingleStoreBlobJsonBuilder<T extends ColumnBuilderBaseConfig<'json', 'SingleStoreBlobJson'>>
extends SingleStoreColumnBuilder<T>
{
static readonly [entityKind]: string = 'SingleStoreBlobStringBuilder';
static readonly [entityKind]: string = 'SingleStoreBlobJsonBuilder';

constructor(name: T['name'], _config?: SingleStoreBlobConfig) {
super(name, 'string', 'SingleStoreBlobString');
constructor(name: T['name']) {
super(name, 'json', 'SingleStoreBlobJson');
}

/** @internal */
override build<TTableName extends string>(
table: AnySingleStoreTable<{ name: TTableName }>,
): SingleStoreBlobString<MakeColumnConfig<T, TTableName>> {
return new SingleStoreBlobString(table, this.config as ColumnBuilderRuntimeConfig<any, any>);
): SingleStoreBlobJson<MakeColumnConfig<T, TTableName>> {
return new SingleStoreBlobJson<MakeColumnConfig<T, TTableName>>(
table,
this.config as ColumnBuilderRuntimeConfig<any>,
);
}
}

export class SingleStoreBlobString<T extends ColumnBaseConfig<'string', 'SingleStoreBlobString'>>
extends SingleStoreColumn<T>
{
static readonly [entityKind]: string = 'SingleStoreBlobString';
export class SingleStoreBlobJson<T extends ColumnBaseConfig<'json', 'SingleStoreBlobJson'>> extends SingleStoreColumn<T> {
static readonly [entityKind]: string = 'SingleStoreBlobJson';

constructor(table: AnySingleStoreTable<{ name: T['tableName'] }>, config: SingleStoreBlobStringBuilder<T>['config']) {
super(table, config);
getSQLType(): string {
return 'blob';
}

getSQLType(): string {
return 'binary(16)';
override mapFromDriverValue(value: Buffer): T['data'] {
return JSON.parse(value.toString());
}

override mapToDriverValue(value: string) {
return sql`UNHEX(REPLACE(${value}, "-", ""))`;
override mapToDriverValue(value: T['data']): Buffer {
return Buffer.from(JSON.stringify(value));
}
}

override mapFromDriverValue(value: Uint8Array): string {
const hex = Buffer.from(value).toString('hex');
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
export type SingleStoreBlobBufferBuilderInitial<TName extends string> = SingleStoreBlobBufferBuilder<{
name: TName;
dataType: 'buffer';
columnType: 'SingleStoreBlobBuffer';
data: Buffer;
driverParam: Buffer;
enumValues: undefined;
generated: undefined;
}>;

export class SingleStoreBlobBufferBuilder<T extends ColumnBuilderBaseConfig<'buffer', 'SingleStoreBlobBuffer'>>
extends SingleStoreColumnBuilder<T>
{
static readonly [entityKind]: string = 'SingleStoreBlobBufferBuilder';

constructor(name: T['name']) {
super(name, 'buffer', 'SingleStoreBlobBuffer');
}

/** @internal */
override build<TTableName extends string>(
table: AnySingleStoreTable<{ name: TTableName }>,
): SingleStoreBlobBuffer<MakeColumnConfig<T, TTableName>> {
return new SingleStoreBlobBuffer<MakeColumnConfig<T, TTableName>>(table, this.config as ColumnBuilderRuntimeConfig<any>);
}
}

export interface SingleStoreBlobConfig<TMode extends 'string' | 'buffer' = 'string' | 'buffer'> {
mode?: TMode;
export class SingleStoreBlobBuffer<T extends ColumnBaseConfig<'buffer', 'SingleStoreBlobBuffer'>> extends SingleStoreColumn<T> {
static readonly [entityKind]: string = 'SingleStoreBlobBuffer';

getSQLType(): string {
return 'blob';
}
}

export interface BlobConfig<TMode extends BlobMode = BlobMode> {
mode: TMode;
}

/**
* Creates a column with the data type `BINARY(16)`
* It's recommended to use `text('...', { mode: 'json' })` instead of `blob` in JSON mode, because it supports JSON functions:
* >All JSON functions currently throw an error if any of their arguments are BLOBs because BLOBs are reserved for a future enhancement in which BLOBs will store the binary encoding for JSON.
*
* Use config `{ mode: "string" }` for a string representation of the Blob
* https://www.sqlite.org/json1.html
*/
export function blob<TName extends string, TMode extends SingleStoreBlobConfig['mode'] & {}>(
export function blob<TName extends string, TMode extends BlobMode = BlobMode>(
name: TName,
config?: SingleStoreBlobConfig<TMode>,
): Equal<TMode, 'string'> extends true ? SingleStoreBlobStringBuilderInitial<TName>
: SingleStoreBlobBuilderInitial<TName>;
export function blob(name: string, config?: SingleStoreBlobConfig) {
if (config?.mode === 'string') {
return new SingleStoreBlobStringBuilder(name, config);
config?: BlobConfig<TMode>,
): Equal<TMode, 'bigint'> extends true ? SingleStoreBigIntBuilderInitial<TName>
: Equal<TMode, 'buffer'> extends true ? SingleStoreBlobBufferBuilderInitial<TName>
: SingleStoreBlobJsonBuilderInitial<TName>;
export function blob(name: string, config?: BlobConfig) {
if (config?.mode === 'json') {
return new SingleStoreBlobJsonBuilder(name);
}
if (config?.mode === 'bigint') {
return new SingleStoreBigIntBuilder(name);
}
return new SingleStoreBlobBuilder(name, config);
return new SingleStoreBlobBufferBuilder(name);
}

0 comments on commit 10aec33

Please sign in to comment.