Skip to content

Commit

Permalink
Feature/mysql (#4)
Browse files Browse the repository at this point in the history
Add core structure for MySql package
Add basic set of data types
  • Loading branch information
AndriiSherman committed Jul 26, 2022
1 parent bd1cf83 commit f6a39f7
Show file tree
Hide file tree
Showing 41 changed files with 2,898 additions and 340 deletions.
1 change: 1 addition & 0 deletions drizzle-orm-mysql/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
"mysql2": "^2.3.3",
"resolve-tspaths": "^0.7.0",
"ts-node": "^10.8.2",
"type-fest": "^2.16.0",
"typescript": "4.8.0-beta",
"uvu": "^0.5.3"
}
Expand Down
8 changes: 8 additions & 0 deletions drizzle-orm-mysql/src/branded-types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { ColumnDriverParam } from 'drizzle-orm/branded-types';
import { MySqlColumnDriverDataType } from './connection';

export const brand = Symbol('brand');

export type MySqlColumnDriverParam<T extends MySqlColumnDriverDataType = MySqlColumnDriverDataType> = ColumnDriverParam<
T
>;
75 changes: 75 additions & 0 deletions drizzle-orm-mysql/src/columns/bigint.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { ColumnData, ColumnDriverParam, ColumnHasDefault, ColumnNotNull, TableName } from 'drizzle-orm/branded-types';
import { AnyMySqlTable } from '~/table';
import { MySqlColumnBuilder, MySqlColumnWithMapper } from './common';

export class MySqlBigInt53Builder<
TNotNull extends ColumnNotNull = ColumnNotNull<false>,
THasDefault extends ColumnHasDefault = ColumnHasDefault<false>,
> extends MySqlColumnBuilder<ColumnData<number>, ColumnDriverParam<number | string>, TNotNull, THasDefault> {
/** @internal */
override build<TTableName extends TableName>(
table: AnyMySqlTable<TTableName>,
): MySqlBigInt53<TTableName, TNotNull, THasDefault> {
return new MySqlBigInt53<TTableName, TNotNull, THasDefault>(table, this);
}
}

export class MySqlBigInt53<
TTableName extends TableName,
TNotNull extends ColumnNotNull,
THasDefault extends ColumnHasDefault,
> extends MySqlColumnWithMapper<
TTableName,
ColumnData<number>,
ColumnDriverParam<number | string>,
TNotNull,
THasDefault
> {
brand!: 'MySqlBigInt53';

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

override mapFromDriverValue = (value: ColumnDriverParam<number | string>): ColumnData<number> => {
if (typeof value === 'number') {
return value as number as ColumnData<number>;
}
return parseInt(value) as ColumnData<number>;
};
}

export class MySqlBigInt64Builder<
TNotNull extends ColumnNotNull = ColumnNotNull<false>,
THasDefault extends ColumnHasDefault = ColumnHasDefault<false>,
> extends MySqlColumnBuilder<ColumnData<bigint>, ColumnDriverParam<string>, TNotNull, THasDefault> {
/** @internal */
override build<TTableName extends TableName>(
table: AnyMySqlTable<TTableName>,
): MySqlBigInt64<TTableName, TNotNull, THasDefault> {
return new MySqlBigInt64<TTableName, TNotNull, THasDefault>(table, this);
}
}

export class MySqlBigInt64<
TTableName extends TableName,
TNotNull extends ColumnNotNull,
THasDefault extends ColumnHasDefault,
> extends MySqlColumnWithMapper<TTableName, ColumnData<bigint>, ColumnDriverParam<string>, TNotNull, THasDefault> {
brand!: 'MySqlBigInt64';

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

override mapFromDriverValue = (value: ColumnDriverParam<string>): ColumnData<bigint> => {
return BigInt(value) as ColumnData<bigint>;
};
}

export function bigint(name: string, maxBytes: 'max_bytes_53' | 'max_bytes_64') {
if (maxBytes === 'max_bytes_53') {
return new MySqlBigInt53Builder(name);
}
return new MySqlBigInt64Builder(name);
}
52 changes: 52 additions & 0 deletions drizzle-orm-mysql/src/columns/binary.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { AnyTable } from 'drizzle-orm';
import { ColumnData, ColumnDriverParam, ColumnHasDefault, ColumnNotNull, TableName } from 'drizzle-orm/branded-types';
import { AnyMySqlTable } from '~/table';
import { MySqlColumnBuilder, MySqlColumnWithMapper } from './common';

export class MySqlBinaryBuilder<
TNotNull extends ColumnNotNull = ColumnNotNull<false>,
THasDefault extends ColumnHasDefault = ColumnHasDefault<false>,
> extends MySqlColumnBuilder<ColumnData<string>, ColumnDriverParam<string>, TNotNull, THasDefault> {
/** @internal */ length: number | undefined;

constructor(name: string, length?: number) {
super(name);
this.length = length;
}

/** @internal */
override build<TTableName extends TableName>(
table: AnyMySqlTable<TTableName>,
): MySqlBinary<TTableName, TNotNull, THasDefault> {
return new MySqlBinary<TTableName, TNotNull, THasDefault>(table, this);
}
}

export class MySqlBinary<
TTableName extends TableName,
TNotNull extends ColumnNotNull,
THasDefault extends ColumnHasDefault,
> extends MySqlColumnWithMapper<
TTableName,
ColumnData<string>,
ColumnDriverParam<string>,
TNotNull,
THasDefault
> {
protected brand!: 'MySqlBinary';

length: number | undefined;

constructor(table: AnyMySqlTable<TTableName>, builder: MySqlBinaryBuilder<TNotNull, THasDefault>) {
super(table, builder);
this.length = builder.length;
}

getSQLType(): string {
return typeof this.length !== 'undefined' ? `binary(${this.length})` : `binary`;
}
}

export function binary(name: string, length?: number) {
return new MySqlBinaryBuilder(name, length);
}
52 changes: 52 additions & 0 deletions drizzle-orm-mysql/src/columns/char.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { AnyTable } from 'drizzle-orm';
import { ColumnData, ColumnDriverParam, ColumnHasDefault, ColumnNotNull, TableName } from 'drizzle-orm/branded-types';
import { AnyMySqlTable } from '~/table';
import { MySqlColumnBuilder, MySqlColumnWithMapper } from './common';

export class MySqlCharBuilder<
TNotNull extends ColumnNotNull = ColumnNotNull<false>,
THasDefault extends ColumnHasDefault = ColumnHasDefault<false>,
> extends MySqlColumnBuilder<ColumnData<string>, ColumnDriverParam<string>, TNotNull, THasDefault> {
/** @internal */ length: number | undefined;

constructor(name: string, length?: number) {
super(name);
this.length = length;
}

/** @internal */
override build<TTableName extends TableName>(
table: AnyMySqlTable<TTableName>,
): MySqlChar<TTableName, TNotNull, THasDefault> {
return new MySqlChar<TTableName, TNotNull, THasDefault>(table, this);
}
}

export class MySqlChar<
TTableName extends TableName,
TNotNull extends ColumnNotNull,
THasDefault extends ColumnHasDefault,
> extends MySqlColumnWithMapper<
TTableName,
ColumnData<string>,
ColumnDriverParam<string>,
TNotNull,
THasDefault
> {
protected brand!: 'MySqlChar';

length: number | undefined;

constructor(table: AnyMySqlTable<TTableName>, builder: MySqlCharBuilder<TNotNull, THasDefault>) {
super(table, builder);
this.length = builder.length;
}

getSQLType(): string {
return typeof this.length !== 'undefined' ? `char(${this.length})` : `char`;
}
}

export function char(name: string, length?: number) {
return new MySqlCharBuilder(name, length);
}
142 changes: 142 additions & 0 deletions drizzle-orm-mysql/src/columns/common.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
import { Column } from 'drizzle-orm';
import { ColumnData, ColumnHasDefault, ColumnNotNull, TableName, Unwrap } from 'drizzle-orm/branded-types';
import { ColumnBuilder } from 'drizzle-orm/column-builder';
import { Simplify } from 'type-fest';
import { MySqlColumnDriverParam } from '~/branded-types';
import { AnyForeignKey, ForeignKeyBuilder, UpdateDeleteAction } from '~/foreign-keys';
import { AnyMySQL } from '~/sql';
import { AnyMySqlTable } from '~/table';

export interface ReferenceConfig<TData extends ColumnData> {
ref: () => AnyMySqlColumn<any, TData>;
actions: {
onUpdate?: UpdateDeleteAction;
onDelete?: UpdateDeleteAction;
};
}

export abstract class MySqlColumnBuilder<
TData extends ColumnData,
TDriverParam extends MySqlColumnDriverParam,
TNotNull extends ColumnNotNull,
THasDefault extends ColumnHasDefault,
> extends ColumnBuilder<TData, TDriverParam, TNotNull, THasDefault> {
private foreignKeyConfigs: ReferenceConfig<TData>[] = [];

constructor(name: string) {
super(name);
}

override notNull(): MySqlColumnBuilder<TData, TDriverParam, ColumnNotNull<true>, THasDefault> {
return super.notNull() as any;
}

override default(
value: Unwrap<TData> | AnyMySQL,
): MySqlColumnBuilder<TData, TDriverParam, TNotNull, ColumnHasDefault<true>> {
return super.default(value) as any;
}

override primaryKey(): MySqlColumnBuilder<TData, TDriverParam, ColumnNotNull<true>, THasDefault> {
return super.primaryKey() as any;
}

references(
ref: ReferenceConfig<TData>['ref'],
actions: ReferenceConfig<TData>['actions'] = {},
): this {
this.foreignKeyConfigs.push({ ref, actions });
return this;
}

/** @internal */
buildForeignKeys(column: AnyMySqlColumn, table: AnyMySqlTable): AnyForeignKey[] {
return this.foreignKeyConfigs.map(({ ref, actions }) => {
const builder = new ForeignKeyBuilder(() => {
const foreignColumn = ref();
return { columns: [column], foreignColumns: [foreignColumn] };
});
if (actions.onUpdate) {
builder.onUpdate(actions.onUpdate);
}
if (actions.onDelete) {
builder.onDelete(actions.onDelete);
}
return builder.build(table);
});
}

/** @internal */
abstract override build<TTableName extends TableName>(
table: AnyMySqlTable<TTableName>,
): MySqlColumn<TTableName, TData, TDriverParam, TNotNull, THasDefault>;
}

export type AnyMySqlColumnBuilder = MySqlColumnBuilder<any, any, any, any>;

export abstract class MySqlColumn<
TTableName extends TableName<string>,
TDataType extends ColumnData,
TDriverData extends MySqlColumnDriverParam,
TNotNull extends ColumnNotNull,
THasDefault extends ColumnHasDefault,
> extends Column<TTableName, TDataType, TDriverData, TNotNull, THasDefault> {
override readonly table!: AnyMySqlTable<TTableName>;

constructor(
table: AnyMySqlTable<TTableName>,
builder: MySqlColumnBuilder<TDataType, TDriverData, TNotNull, THasDefault>,
) {
super(table, builder);
}
}

export abstract class MySqlColumnWithMapper<
TTableName extends TableName,
TData extends ColumnData,
TDriverParam extends MySqlColumnDriverParam,
TNotNull extends ColumnNotNull,
THasDefault extends ColumnHasDefault,
> extends MySqlColumn<TTableName, TData, TDriverParam, TNotNull, THasDefault> {
override mapFromDriverValue = (value: TDriverParam): TData => {
return value as unknown as TData;
};

override mapToDriverValue = (value: TData): TDriverParam => {
return value as unknown as TDriverParam;
};
}

export type AnyMySqlColumn<
TTableName extends TableName = any,
TData extends ColumnData = any,
TDriverParam extends MySqlColumnDriverParam = MySqlColumnDriverParam,
TNotNull extends ColumnNotNull = any,
THasDefault extends ColumnHasDefault = any,
> = MySqlColumn<TTableName, TData, TDriverParam, TNotNull, THasDefault>;

export type AnyMySqlColumnWithMapper<
TTableName extends TableName = TableName,
TData extends ColumnData = any,
TDriverParam extends MySqlColumnDriverParam = MySqlColumnDriverParam,
TNotNull extends ColumnNotNull = ColumnNotNull,
THasDefault extends ColumnHasDefault = ColumnHasDefault,
> = MySqlColumnWithMapper<TTableName, TData, TDriverParam, TNotNull, THasDefault>;

export type BuildMySqlColumn<TTableName extends TableName, TBuilder extends AnyMySqlColumnBuilder> = TBuilder extends
MySqlColumnBuilder<
infer TData,
infer TDriverParam,
infer TNotNull,
infer THasDefault
> ? MySqlColumnWithMapper<TTableName, TData, TDriverParam, TNotNull, THasDefault>
: never;

export type BuildMySqlColumns<
TTableName extends TableName,
TConfigMap extends Record<string, AnyMySqlColumnBuilder>,
> = Simplify<
{
[Key in keyof TConfigMap]: BuildMySqlColumn<TTableName, TConfigMap[Key]>;
}
>;
Loading

0 comments on commit f6a39f7

Please sign in to comment.