Skip to content

Commit

Permalink
Add support for blob SQL type in relational queries
Browse files Browse the repository at this point in the history
SQLite does not support selecting a blob type column in 'json_array()' and this function is used in relational queries.
Solve this by wrapping blob type columns in 'hex()' function to cast the blob to a hex string that we can parse back into a blob later.
Said 'later' being the 'mapFromDriverValue' step where inside this function we turn the hex string back into a buffer before passing it along.
  • Loading branch information
Colonel-Sandvich committed May 3, 2024
1 parent a78eefe commit 96ae030
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 5 deletions.
16 changes: 12 additions & 4 deletions drizzle-orm/src/sqlite-core/columns/blob.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { ColumnBaseConfig } from '~/column.ts';
import { entityKind } from '~/entity.ts';
import type { AnySQLiteTable } from '~/sqlite-core/table.ts';
import type { Equal } from '~/utils.ts';
import { hexStringToBuffer } from '../utils.ts';
import { SQLiteColumn, SQLiteColumnBuilder } from './common.ts';

type BlobMode = 'buffer' | 'json' | 'bigint';
Expand Down Expand Up @@ -40,8 +41,8 @@ export class SQLiteBigInt<T extends ColumnBaseConfig<'bigint', 'SQLiteBigInt'>>
return 'blob';
}

override mapFromDriverValue(value: Buffer): bigint {
return BigInt(value.toString());
override mapFromDriverValue(value: Buffer | string): bigint {
return BigInt(typeof value === 'string' ? value : value.toString());
}

override mapToDriverValue(value: bigint): Buffer {
Expand Down Expand Up @@ -85,8 +86,8 @@ export class SQLiteBlobJson<T extends ColumnBaseConfig<'json', 'SQLiteBlobJson'>
return 'blob';
}

override mapFromDriverValue(value: Buffer): T['data'] {
return JSON.parse(value.toString());
override mapFromDriverValue(value: Buffer | string): T['data'] {
return JSON.parse(typeof value === 'string' ? value : value.toString());
}

override mapToDriverValue(value: T['data']): Buffer {
Expand Down Expand Up @@ -126,6 +127,13 @@ export class SQLiteBlobBuffer<T extends ColumnBaseConfig<'buffer', 'SQLiteBlobBu
getSQLType(): string {
return 'blob';
}

override mapFromDriverValue(value: Buffer | string): Buffer {
if (typeof value === 'string') {
value = hexStringToBuffer(value);
}
return value;
}
}

export interface BlobConfig<TMode extends BlobMode = BlobMode> {
Expand Down
4 changes: 4 additions & 0 deletions drizzle-orm/src/sqlite-core/columns/custom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { entityKind } from '~/entity.ts';
import type { SQL } from '~/sql/sql.ts';
import type { AnySQLiteTable } from '~/sqlite-core/table.ts';
import type { Equal } from '~/utils.ts';
import { hexStringToBuffer } from '../utils.ts';
import { SQLiteColumn, SQLiteColumnBuilder } from './common.ts';

export type ConvertCustomConfig<TName extends string, T extends Partial<CustomTypeValues>> =
Expand Down Expand Up @@ -79,6 +80,9 @@ export class SQLiteCustomColumn<T extends ColumnBaseConfig<'custom', 'SQLiteCust
}

override mapFromDriverValue(value: T['driverParam']): T['data'] {
if (typeof value === 'string' && this.getSQLType() === 'blob') {
value = hexStringToBuffer(value);
}
return typeof this.mapFrom === 'function' ? this.mapFrom(value) : value as T['data'];
}

Expand Down
8 changes: 7 additions & 1 deletion drizzle-orm/src/sqlite-core/dialect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -638,7 +638,13 @@ export abstract class SQLiteDialect {
let field = sql`json_array(${
sql.join(
selection.map(({ field }) =>
is(field, SQLiteColumn) ? sql.identifier(field.name) : is(field, SQL.Aliased) ? field.sql : field
is(field, SQLiteColumn)
? field.getSQLType() === 'blob'
? sql.raw(`hex("${field.name}")`)
: sql.identifier(field.name)
: is(field, SQL.Aliased)
? field.sql
: field
),
sql`, `,
)
Expand Down
11 changes: 11 additions & 0 deletions drizzle-orm/src/sqlite-core/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,14 @@ export function getViewConfig<
...view[SQLiteViewConfig],
};
}

export function hexStringToBuffer(hexString: string): Buffer {
const numChunks = Math.ceil(hexString.length / 2);
const chunks = Array.from<number>({ length: numChunks });

for (let i = 0; i < numChunks; ++i) {
chunks[i] = Number.parseInt(hexString.slice(2 * i, 2 * i + 2), 16);
}

return Buffer.from(chunks);
}

0 comments on commit 96ae030

Please sign in to comment.