Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add date mode for text data type in SQLite #2195

Draft
wants to merge 4 commits into
base: beta
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
55 changes: 53 additions & 2 deletions drizzle-orm/src/sqlite-core/columns/text.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,53 @@ export class SQLiteText<T extends ColumnBaseConfig<'string', 'SQLiteText'>>
}
}

export type SQLiteTextDateBuilderInitial<TName extends string> = SQLiteTextDateBuilder<{
name: TName;
dataType: 'date';
columnType: 'SQLiteTextDate';
data: Date;
driverParam: string;
enumValues: undefined;
}>;

export class SQLiteTextDateBuilder<T extends ColumnBuilderBaseConfig<'date', 'SQLiteTextDate'>>
extends SQLiteColumnBuilder<T>
{
static readonly [entityKind]: string = 'SQLiteTextDateBuilder';

constructor(name: T['name']) {
super(name, 'date', 'SQLiteTextDate');
}

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

export class SQLiteTextDate<T extends ColumnBaseConfig<'date', 'SQLiteTextDate'>>
extends SQLiteColumn<T, { length: number | undefined; enumValues: T['enumValues'] }>
{
static readonly [entityKind]: string = 'SQLiteTextDate';

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

override mapFromDriverValue(value: string): Date {
return new Date(value);
}

override mapToDriverValue(value: Date): string {
return value.toISOString();
}
}

export type SQLiteTextJsonBuilderInitial<TName extends string> = SQLiteTextJsonBuilder<{
name: TName;
dataType: 'json';
Expand Down Expand Up @@ -103,7 +150,7 @@ export class SQLiteTextJson<T extends ColumnBaseConfig<'json', 'SQLiteTextJson'>
}

export type SQLiteTextConfig<
TMode extends 'text' | 'json',
TMode extends 'text' | 'json' | 'date',
TEnum extends readonly string[] | string[] | undefined,
> = TMode extends 'text' ? {
mode?: TMode;
Expand All @@ -118,16 +165,20 @@ export function text<
TName extends string,
U extends string,
T extends Readonly<[U, ...U[]]>,
TMode extends 'text' | 'json' = 'text' | 'json',
TMode extends 'text' | 'json' | 'date' = 'text' | 'json' | 'date',
>(
name: TName,
config: SQLiteTextConfig<TMode, T | Writable<T>> = {} as SQLiteTextConfig<TMode, T | Writable<T>>,
): Equal<TMode, 'json'> extends true ? SQLiteTextJsonBuilderInitial<TName>
: Equal<TMode, 'date'> extends true ? SQLiteTextDateBuilderInitial<TName>
: SQLiteTextBuilderInitial<TName, Writable<T>>
{
return (config.mode === 'json'
? new SQLiteTextJsonBuilder(name)
: config.mode === 'date'
? new SQLiteTextDateBuilder(name)
: new SQLiteTextBuilder(name, config as SQLiteTextConfig<'text', Writable<T>>)) as Equal<TMode, 'json'> extends true
? SQLiteTextJsonBuilderInitial<TName>
: Equal<TMode, 'date'> extends true ? SQLiteTextDateBuilderInitial<TName>
: SQLiteTextBuilderInitial<TName, Writable<T>>;
}
30 changes: 30 additions & 0 deletions integration-tests/tests/libsql.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2798,3 +2798,33 @@ test.serial('test $onUpdateFn and $onUpdate works updating', async (t) => {
t.assert(eachUser.updatedAt!.valueOf() > Date.now() - msDelay);
}
});

test.serial('test date mode for text data type', async (t) => {
const { db } = t.context;

const test = sqliteTable('test', {
t1: text('t1', { mode: 'date' }),
t2: text('t2', { mode: 'date' }),
});

await db.run(sql`create table ${test} (t1 text, t2 text)`);

const now = new Date();
const now2 = new Date('2024-04-19 23:01:30');

await db.insert(test).values({ t1: now, t2: now2 }).run();
const res = await db.select().from(test).all();

t.deepEqual(res, [{ t1: now, t2: now2 }]);

const res2 = await db.all<
Array<{
t1: string;
t2: string;
}>
>(sql`select * from ${test}`);

t.deepEqual(res2, [{ t1: now.toISOString(), t2: now2.toISOString() }]);

await db.run(sql`drop table ${test}`);
});