Skip to content

Commit

Permalink
Add partial support for optional columns, add support for TRUNCATE ..…
Browse files Browse the repository at this point in the history
… CASCADE
  • Loading branch information
ChiriVulpes committed Mar 28, 2024
1 parent 0da22af commit 57ffa42
Show file tree
Hide file tree
Showing 5 changed files with 37 additions and 9 deletions.
29 changes: 25 additions & 4 deletions src/Schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ interface SpecialKeys<SCHEMA> {
PRIMARY_KEY?: keyof SCHEMA | (keyof SCHEMA)[];
}

type SchemaBase = Record<string, TypeString>;
interface OptionalTypeString<TYPE extends TypeString = TypeString> {
type: TYPE;
optional: true;
}

type SchemaBase = Record<string, TypeString | OptionalTypeString>;

// type Schema<SCHEMA extends SchemaBase = SchemaBase> = { PRIMARY_KEY?: keyof SCHEMA } & SCHEMA;

Expand Down Expand Up @@ -134,6 +139,10 @@ class Schema {
return keys;
}

public static optional<TYPE extends TypeString> (type: TYPE): { type: TYPE, optional: true } {
return { type, optional: true };
}

public static getSingleColumnPrimaryKey<SCHEMA extends TableSchema> (schema: SCHEMA) {
const primaryKey = schema["PRIMARY_KEY"] as Schema.Column<SCHEMA>[] | undefined;
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
Expand All @@ -155,7 +164,13 @@ class Schema {
}

public static isColumn<SCHEMA extends TableSchema> (schema: SCHEMA, column: keyof SCHEMA, type: TypeString) {
const columnType = schema[column] as TypeString;
let columnType = schema[column] as TypeString | OptionalTypeString;
if (!columnType)
throw new Error(`No column ${String(column)} in schema`);

if (typeof columnType === "object")
columnType = columnType.type;

switch (type) {
case "TIMESTAMP":
return columnType.startsWith("TIMESTAMP");
Expand Down Expand Up @@ -183,8 +198,14 @@ namespace Schema {
export type ColumnTyped<SCHEMA, TYPE> =
keyof { [COLUMN in keyof SCHEMA as COLUMN extends keyof SpecialKeys<any> ? never : SCHEMA[COLUMN] extends Vaguify<TYPE> ? COLUMN : never]: SCHEMA[COLUMN] };
export type Columns<SCHEMA> = { [COLUMN in keyof SCHEMA as COLUMN extends keyof SpecialKeys<any> ? never : COLUMN]: SCHEMA[COLUMN] };
export type RowOutput<SCHEMA> = { [COLUMN in keyof SCHEMA as COLUMN extends keyof SpecialKeys<any> ? never : COLUMN]: OutputTypeFromString<Extract<SCHEMA[COLUMN], TypeString>> };
export type RowInput<SCHEMA, VARS = {}> = { [COLUMN in keyof SCHEMA as COLUMN extends keyof SpecialKeys<any> ? never : COLUMN]: InputTypeFromString<Extract<SCHEMA[COLUMN], TypeString>, VARS> };
export type RowOutput<SCHEMA> = (
{ [COLUMN in keyof SCHEMA as COLUMN extends keyof SpecialKeys<any> ? never : SCHEMA[COLUMN] extends OptionalTypeString ? never : COLUMN]: OutputTypeFromString<Extract<SCHEMA[COLUMN], TypeString>> }
& { [COLUMN in keyof SCHEMA as COLUMN extends keyof SpecialKeys<any> ? never : SCHEMA[COLUMN] extends OptionalTypeString ? COLUMN : never]?: OutputTypeFromString<Extract<SCHEMA[COLUMN] extends OptionalTypeString<infer TYPE> ? TYPE : never, TypeString>> }
) extends infer T ? { [P in keyof T]: T[P] } : never;
export type RowInput<SCHEMA, VARS = {}> = (
{ [COLUMN in keyof SCHEMA as COLUMN extends keyof SpecialKeys<any> ? never : SCHEMA[COLUMN] extends OptionalTypeString ? never : COLUMN]: InputTypeFromString<Extract<SCHEMA[COLUMN], TypeString>, VARS> }
& { [COLUMN in keyof SCHEMA as COLUMN extends keyof SpecialKeys<any> ? never : SCHEMA[COLUMN] extends OptionalTypeString ? COLUMN : never]?: InputTypeFromString<Extract<SCHEMA[COLUMN] extends OptionalTypeString<infer TYPE> ? TYPE : never, TypeString>, VARS> | null }
) extends infer T ? { [P in keyof T]: T[P] } : never;

type Vaguify<T> = T extends TypeStringMap[DataTypeID.BIGINT] ? TypeStringMap[DataTypeID.BIGINT] | TypeStringMap[DataTypeID.BIGSERIAL]
: T;
Expand Down
4 changes: 2 additions & 2 deletions src/Table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@ export default class Table<SCHEMA extends TableSchema> {
public update (data: Partial<Schema.RowInput<SCHEMA>>, initialiser?: Initialiser<UpdateTable<SCHEMA>, UpdateTable<SCHEMA, any>>): UpdateTable<SCHEMA, any> {
const query = new UpdateTable<SCHEMA, any>(this.name, this.schema);
for (const key of Object.keys(data))
if (data[key] !== undefined)
query.set(key as Schema.Column<SCHEMA>, data[key]!);
if (data[key as keyof Schema.RowInput<SCHEMA>] !== undefined)
query.set(key as Schema.Column<SCHEMA>, data[key as keyof Schema.RowInput<SCHEMA>] as never);

// eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-argument
return initialiser?.(query) ?? query;
Expand Down
3 changes: 2 additions & 1 deletion src/statements/Insert.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ export default class InsertIntoTable<SCHEMA extends TableSchema, COLUMNS extends
public compile () {
const rows = this.rows
.map(row => row
.map((value: ValidType, i) => {
.map((v, i) => {
let value = v as ValidType;
const column = this.columns[i];
if (Schema.isColumn(this.schema, column, "TIMESTAMP") && typeof value === "number")
value = new Date(value);
Expand Down
8 changes: 7 additions & 1 deletion src/statements/Truncate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,13 @@ export default class TruncateTable extends Statement<[]> {
super();
}

private shouldCascade?: true;
public cascade () {
this.shouldCascade = true;
return this;
}

public compile () {
return this.queryable(`TRUNCATE ${this.tableName ?? ""}`);
return this.queryable(`TRUNCATE ${this.tableName ?? ""} ${this.shouldCascade ? "CASCADE" : ""}`);
}
}
2 changes: 1 addition & 1 deletion src/statements/Update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export default class UpdateTable<SCHEMA extends TableSchema, RESULT = [], VARS =
public set (input: Schema.Column<SCHEMA> | Partial<Schema.RowInput<SCHEMA, VARS>>, value?: ValidType) {
if (typeof input === "object") {
for (const column of Object.keys(input))
this.set(column as Schema.Column<SCHEMA>, input[column] as never);
this.set(column as Schema.Column<SCHEMA>, input[column as keyof Schema.RowInput<SCHEMA, VARS>] as never);

} else {
if (Schema.isColumn(this.schema, input, "TIMESTAMP") && typeof value === "number")
Expand Down

0 comments on commit 57ffa42

Please sign in to comment.