Skip to content

Commit

Permalink
add blob column type to singlestore
Browse files Browse the repository at this point in the history
  • Loading branch information
Rodriguespn committed Dec 10, 2024
1 parent 74a51ae commit 6dc290a
Show file tree
Hide file tree
Showing 9 changed files with 268 additions and 41 deletions.
8 changes: 7 additions & 1 deletion drizzle-kit/src/introspect-singlestore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ const singlestoreImportsList = new Set([
'float',
'int',
'json',
'blob',
// TODO: add new type BSON
// TODO: add new type Blob
// TODO: add new type UUID
// TODO: add new type GUID
// TODO: add new type Vector
Expand Down Expand Up @@ -789,6 +789,12 @@ const column = (
return out;
}

if (lowered === 'blob') {
let out = `${casing(name)}: blob(${dbColumnName({ name, casing: rawCasing })})`;
out += defaultValue ? `.default(${mapColumnDefault(defaultValue)})` : '';
return out;
}

console.log('uknown', type);
return `// Warning: Can't parse ${type} from database\n\t// ${type}Type: ${type}("${name}")`;
};
Expand Down
3 changes: 0 additions & 3 deletions drizzle-kit/src/serializer/singlestoreSerializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,9 +150,6 @@ export const generateSingleStoreSnapshot = (
columnToSet.default = column.default;
}
}
// if (['blob', 'text', 'json'].includes(column.getSQLType())) {
// columnToSet.default = `(${columnToSet.default})`;
// }
}
}
columnsObject[column.name] = columnToSet;
Expand Down
13 changes: 13 additions & 0 deletions drizzle-kit/src/snapshotsDiffer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2686,6 +2686,19 @@ export const applyMysqlSnapshotsDiff = async (
};
};

// This is necessary to make sure that BigInt is serialized to Number
// at the diffSchemasOrTables function. Ohterwise, it will be serialized to BigInt
// and the diff will throw the following error
// "TypeError: Do not know how to serialize a BigInt"

declare global {
interface BigInt {
toJSON(): Number;
}
}

BigInt.prototype.toJSON = function () { return Number(this) }

export const applySingleStoreSnapshotsDiff = async (
json1: SingleStoreSchemaSquashed,
json2: SingleStoreSchemaSquashed,
Expand Down
9 changes: 9 additions & 0 deletions drizzle-kit/tests/push/singlestore.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { SQL, sql } from 'drizzle-orm';
import {
bigint,
binary,
blob,
char,
date,
datetime,
Expand Down Expand Up @@ -249,6 +250,14 @@ const singlestoreSuite: DialectSuite = {
columnNotNull: binary('column_not_null', { length: 1 }).notNull(),
columnDefault: binary('column_default', { length: 12 }),
}),
allBlobs: singlestoreTable('all_blobs', {
bigIntSimple: blob('big_int_simple', { mode: 'bigint' }),
bigIntColumnNotNull: blob('big_int_column_not_null', { mode: 'bigint' }).notNull(),
bigIntColumnDefault: blob('big_int_column_default', { mode: 'bigint' }).default(BigInt(12)),
jsonSimple: blob('json_simple', { mode: 'json' }),
jsonColumnNotNull: blob('json_column_not_null', { mode: 'json' }).notNull(),
jsonColumnDefault: blob('json_column_default', { mode: 'json' }).default('{"hello":"world"}'),
})
};

const { statements } = await diffTestSchemasPushSingleStore(
Expand Down
2 changes: 2 additions & 0 deletions drizzle-orm/src/singlestore-core/columns/all.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { bigint } from './bigint.ts';
import { binary } from './binary.ts';
import { blob } from './blob.ts';
import { boolean } from './boolean.ts';
import { char } from './char.ts';
import { customType } from './custom.ts';
Expand All @@ -25,6 +26,7 @@ import { year } from './year.ts';

export function getSingleStoreColumnBuilders() {
return {
blob,
bigint,
binary,
boolean,
Expand Down
177 changes: 177 additions & 0 deletions drizzle-orm/src/singlestore-core/columns/blob.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts';
import type { ColumnBaseConfig } from '~/column.ts';
import { entityKind } from '~/entity.ts';
import type { AnySingleStoreTable } from '~/singlestore-core/table.ts';
import { type Equal, getColumnNameAndConfig } from '~/utils.ts';
import { SingleStoreColumn, SingleStoreColumnBuilder } from './common.ts';

type BlobMode = 'buffer' | 'json' | 'bigint';

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

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

constructor(name: T['name']) {
super(name, 'bigint', 'SingleStoreBigInt');
}

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

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

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

override mapFromDriverValue(value: Buffer | Uint8Array): bigint {
if (Buffer.isBuffer(value)) {
return BigInt(value.toString());
}

return BigInt(String.fromCodePoint(...value));
}

override mapToDriverValue(value: bigint): Buffer {
return Buffer.from(value.toString());
}
}

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

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

constructor(name: T['name']) {
super(name, 'json', 'SingleStoreBlobJson');
}

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

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

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

override mapFromDriverValue(value: Buffer | Uint8Array | ArrayBuffer): T['data'] {
if (Buffer.isBuffer(value)) {
return JSON.parse(value.toString());
}

// for sqlite durable objects
// eslint-disable-next-line no-instanceof/no-instanceof
if (value instanceof ArrayBuffer) {
const decoder = new TextDecoder();
return JSON.parse(decoder.decode(value));
}

return JSON.parse(String.fromCodePoint(...value));
}

override mapToDriverValue(value: T['data']): Buffer {
return Buffer.from(JSON.stringify(value));
}
}

export type SingleStoreBlobBufferBuilderInitial<TName extends string> = SingleStoreBlobBufferBuilder<{
name: TName;
dataType: 'buffer';
columnType: 'SingleStoreBlobBuffer';
data: Buffer;
driverParam: Buffer;
enumValues: undefined;
}>;

export class SingleStoreBlobBufferBuilder<T extends ColumnBuilderBaseConfig<'buffer', 'SingleStoreBlobBuffer'>>
extends SingleStoreColumnBuilder<T>
{
static override 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 class SingleStoreBlobBuffer<T extends ColumnBaseConfig<'buffer', 'SingleStoreBlobBuffer'>> extends SingleStoreColumn<T> {
static override readonly [entityKind]: string = 'SingleStoreBlobBuffer';

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

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

/**
* 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.
*
* https://www.sqlite.org/json1.html
*/
export function blob(): SingleStoreBlobJsonBuilderInitial<''>;
export function blob<TMode extends BlobMode = BlobMode>(
config?: BlobConfig<TMode>,
): Equal<TMode, 'bigint'> extends true ? SingleStoreBigIntBuilderInitial<''>
: Equal<TMode, 'buffer'> extends true ? SingleStoreBlobBufferBuilderInitial<''>
: SingleStoreBlobJsonBuilderInitial<''>;
export function blob<TName extends string, TMode extends BlobMode = BlobMode>(
name: TName,
config?: BlobConfig<TMode>,
): Equal<TMode, 'bigint'> extends true ? SingleStoreBigIntBuilderInitial<TName>
: Equal<TMode, 'buffer'> extends true ? SingleStoreBlobBufferBuilderInitial<TName>
: SingleStoreBlobJsonBuilderInitial<TName>;
export function blob(a?: string | BlobConfig, b?: BlobConfig) {
const { name, config } = getColumnNameAndConfig<BlobConfig | undefined>(a, b);
if (config?.mode === 'json') {
return new SingleStoreBlobJsonBuilder(name);
}
if (config?.mode === 'bigint') {
return new SingleStoreBigIntBuilder(name);
}
return new SingleStoreBlobBufferBuilder(name);
}
1 change: 1 addition & 0 deletions drizzle-orm/src/singlestore-core/columns/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './blob.ts';
export * from './bigint.ts';
export * from './binary.ts';
export * from './boolean.ts';
Expand Down
7 changes: 7 additions & 0 deletions drizzle-orm/type-tests/singlestore/tables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { type Equal, Expect } from 'type-tests/utils.ts';
import type { BuildColumn } from '~/column-builder.ts';
import { eq } from '~/expressions.ts';
import {
blob,
bigint,
binary,
boolean,
Expand Down Expand Up @@ -836,6 +837,9 @@ Expect<

{
singlestoreTable('all_columns', {
blob: blob('blob'),
blob2: blob('blob2', { mode: 'bigint' }),
blobdef: blob('blobdef').default(0),
bigint: bigint('bigint', { mode: 'number' }),
bigint2: bigint('bigint', { mode: 'number', unsigned: true }),
bigintdef: bigint('bigintdef', { mode: 'number' }).default(0),
Expand Down Expand Up @@ -934,6 +938,9 @@ Expect<

{
singlestoreTable('all_columns_without_name', {
blob: blob(),
blob2: blob({ mode: 'bigint' }),
blobdef: blob().default(0),
bigint: bigint({ mode: 'number' }),
bigint2: bigint({ mode: 'number', unsigned: true }),
bigintdef: bigint({ mode: 'number' }).default(0),
Expand Down
Loading

0 comments on commit 6dc290a

Please sign in to comment.