From 57ffa4211024840bbecce819c4c643f2c4403e4d Mon Sep 17 00:00:00 2001 From: Chiri Vulpes <6081834+ChiriVulpes@users.noreply.github.com> Date: Fri, 29 Mar 2024 01:13:19 +1300 Subject: [PATCH] Add partial support for optional columns, add support for TRUNCATE .. CASCADE --- src/Schema.ts | 29 +++++++++++++++++++++++++---- src/Table.ts | 4 ++-- src/statements/Insert.ts | 3 ++- src/statements/Truncate.ts | 8 +++++++- src/statements/Update.ts | 2 +- 5 files changed, 37 insertions(+), 9 deletions(-) diff --git a/src/Schema.ts b/src/Schema.ts index 966be28..f326316 100644 --- a/src/Schema.ts +++ b/src/Schema.ts @@ -4,7 +4,12 @@ interface SpecialKeys { PRIMARY_KEY?: keyof SCHEMA | (keyof SCHEMA)[]; } -type SchemaBase = Record; +interface OptionalTypeString { + type: TYPE; + optional: true; +} + +type SchemaBase = Record; // type Schema = { PRIMARY_KEY?: keyof SCHEMA } & SCHEMA; @@ -134,6 +139,10 @@ class Schema { return keys; } + public static optional (type: TYPE): { type: TYPE, optional: true } { + return { type, optional: true }; + } + public static getSingleColumnPrimaryKey (schema: SCHEMA) { const primaryKey = schema["PRIMARY_KEY"] as Schema.Column[] | undefined; // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access @@ -155,7 +164,13 @@ class Schema { } public static isColumn (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"); @@ -183,8 +198,14 @@ namespace Schema { export type ColumnTyped = keyof { [COLUMN in keyof SCHEMA as COLUMN extends keyof SpecialKeys ? never : SCHEMA[COLUMN] extends Vaguify ? COLUMN : never]: SCHEMA[COLUMN] }; export type Columns = { [COLUMN in keyof SCHEMA as COLUMN extends keyof SpecialKeys ? never : COLUMN]: SCHEMA[COLUMN] }; - export type RowOutput = { [COLUMN in keyof SCHEMA as COLUMN extends keyof SpecialKeys ? never : COLUMN]: OutputTypeFromString> }; - export type RowInput = { [COLUMN in keyof SCHEMA as COLUMN extends keyof SpecialKeys ? never : COLUMN]: InputTypeFromString, VARS> }; + export type RowOutput = ( + { [COLUMN in keyof SCHEMA as COLUMN extends keyof SpecialKeys ? never : SCHEMA[COLUMN] extends OptionalTypeString ? never : COLUMN]: OutputTypeFromString> } + & { [COLUMN in keyof SCHEMA as COLUMN extends keyof SpecialKeys ? never : SCHEMA[COLUMN] extends OptionalTypeString ? COLUMN : never]?: OutputTypeFromString ? TYPE : never, TypeString>> } + ) extends infer T ? { [P in keyof T]: T[P] } : never; + export type RowInput = ( + { [COLUMN in keyof SCHEMA as COLUMN extends keyof SpecialKeys ? never : SCHEMA[COLUMN] extends OptionalTypeString ? never : COLUMN]: InputTypeFromString, VARS> } + & { [COLUMN in keyof SCHEMA as COLUMN extends keyof SpecialKeys ? never : SCHEMA[COLUMN] extends OptionalTypeString ? COLUMN : never]?: InputTypeFromString ? TYPE : never, TypeString>, VARS> | null } + ) extends infer T ? { [P in keyof T]: T[P] } : never; type Vaguify = T extends TypeStringMap[DataTypeID.BIGINT] ? TypeStringMap[DataTypeID.BIGINT] | TypeStringMap[DataTypeID.BIGSERIAL] : T; diff --git a/src/Table.ts b/src/Table.ts index 0556f55..76fcbd0 100644 --- a/src/Table.ts +++ b/src/Table.ts @@ -78,8 +78,8 @@ export default class Table { public update (data: Partial>, initialiser?: Initialiser, UpdateTable>): UpdateTable { const query = new UpdateTable(this.name, this.schema); for (const key of Object.keys(data)) - if (data[key] !== undefined) - query.set(key as Schema.Column, data[key]!); + if (data[key as keyof Schema.RowInput] !== undefined) + query.set(key as Schema.Column, data[key as keyof Schema.RowInput] as never); // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-argument return initialiser?.(query) ?? query; diff --git a/src/statements/Insert.ts b/src/statements/Insert.ts index 14d45db..3a513b1 100644 --- a/src/statements/Insert.ts +++ b/src/statements/Insert.ts @@ -77,7 +77,8 @@ export default class InsertIntoTable 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); diff --git a/src/statements/Truncate.ts b/src/statements/Truncate.ts index a946284..44b35f2 100644 --- a/src/statements/Truncate.ts +++ b/src/statements/Truncate.ts @@ -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" : ""}`); } } diff --git a/src/statements/Update.ts b/src/statements/Update.ts index 5b4816e..f39e0ed 100644 --- a/src/statements/Update.ts +++ b/src/statements/Update.ts @@ -18,7 +18,7 @@ export default class UpdateTable | Partial>, value?: ValidType) { if (typeof input === "object") { for (const column of Object.keys(input)) - this.set(column as Schema.Column, input[column] as never); + this.set(column as Schema.Column, input[column as keyof Schema.RowInput] as never); } else { if (Schema.isColumn(this.schema, input, "TIMESTAMP") && typeof value === "number")