From a29e6f4428f7223dbe50551d9f9d5160f2d2f939 Mon Sep 17 00:00:00 2001 From: Madeorsk Date: Sat, 5 Oct 2024 18:56:38 +0200 Subject: [PATCH] Move all database queries in ModelQuery class. --- src/Drizzle.ts | 68 ++++++++++++-------------------------------------- src/Query.ts | 65 ++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 80 insertions(+), 53 deletions(-) diff --git a/src/Drizzle.ts b/src/Drizzle.ts index 7add89f..aac5b18 100644 --- a/src/Drizzle.ts +++ b/src/Drizzle.ts @@ -1,16 +1,9 @@ -import {IdentifierType, Model, ModelShape, SerializedModel} from "@sharkitek/core"; -import {eq, getTableColumns, Table, TableConfig} from "drizzle-orm"; +import {IdentifierType, Model, ModelClass, ModelShape} from "@sharkitek/core"; +import {Table, TableConfig} from "drizzle-orm"; import {PgDatabase} from "drizzle-orm/pg-core"; import {PgQueryResultHKT} from "drizzle-orm/pg-core/session"; import type {ExtractTablesWithRelations, TablesRelationalConfig} from "drizzle-orm/relations"; -import {ModelQuery} from "./Query"; - -/** - * Serialized values converters for database. - */ -export const serializedToDatabaseTypes: Record any> = { - "date": (serializedValue: string) => new Date(serializedValue), -}; +import {ModelQuery, query} from "./Query"; /** * Sharkitek model extension for Drizzle. @@ -40,7 +33,8 @@ export class DrizzleModel< Shape extends ModelShape, Identifier extends keyof Shape = any, TSchema extends TablesRelationalConfig = ExtractTablesWithRelations > { - constructor(protected model: ModelType, + constructor(protected modelClass: ModelClass, Shape, Identifier>, + protected model: ModelType, protected database: PgDatabase, protected table: TableType, protected scopes: Scopes & ThisType>) @@ -75,50 +69,17 @@ export class DrizzleModel< */ async save(): Promise { - // Get serialized model update. - const serializedModel = this.model.patch(); - - // Get table columns of the model. - const tableColumns = getTableColumns(this.table); - - // Create model data for the database. - const databaseModelData = Object.fromEntries( - Object.entries(serializedModel).map( - // Only keep table column values and convert them into database types, if it is required. - ([key, value]) => [key, tableColumns?.[key] ? (serializedToDatabaseTypes?.[tableColumns?.[key].dataType]?.(value) ?? value) : undefined] - ) - ) as Partial>; - - // Initialize query result variable. - let result: any; - - if (this.model.isNew()) - { // Insert the new model in database and get the inserted row data. - result = (await (this.database.insert(this.table)).values(databaseModelData as any).returning() as any)?.[0]; - } - else - { // Update model data in database, and get the updated row data. - result = (await (this.database.update(this.table) - .set(databaseModelData) - .where(eq((this.table as any)?.[this.model.getIdentifierName()], this.model.getIdentifier()))) - .returning() as any)?.[0]; - } - - // Update model from inserted or updated row data. - this.model.deserialize(result); - - return true; + // New query to save the model. + return query(this.modelClass).save(this.model as any); } + /** + * Refresh model data from database. + */ async refresh(): Promise { - // Update model from up-to-date row data. - this.model.deserialize( - (( // Retrieve model data from database. - await this.database.select().from(this.table) - .where(eq((this.table as any)?.[this.model.getIdentifierName()], this.model.getIdentifier())) - ) as any)[0] - ); + // New query to refresh the model. + await query(this.modelClass).refresh(this.model as any); } } @@ -145,7 +106,10 @@ export function drizzle< drizzle(): DrizzleModel { // Initialize drizzle model manager instance. - return new DrizzleModel(this, database, table, scopes); + return new DrizzleModel( + this.constructor as ModelClass, Shape, Identifier>, + this, database, table, scopes + ); } }; } diff --git a/src/Query.ts b/src/Query.ts index a49681c..c792124 100644 --- a/src/Query.ts +++ b/src/Query.ts @@ -1,5 +1,5 @@ import {AnyModel, IdentifierType, Model, ModelClass, ModelShape, SerializedModel} from "@sharkitek/core"; -import {eq, getTableName, Table, TableConfig} from "drizzle-orm"; +import {eq, getTableColumns, getTableName, Table, TableConfig} from "drizzle-orm"; import {PgDatabase} from "drizzle-orm/pg-core"; import {PgQueryResultHKT} from "drizzle-orm/pg-core/session"; import type {DBQueryConfig, ExtractTablesWithRelations, TablesRelationalConfig} from "drizzle-orm/relations"; @@ -7,6 +7,13 @@ import type {KnownKeysOnly} from "drizzle-orm/utils"; import {DrizzleExtension} from "./Drizzle"; import {inArray} from "drizzle-orm/sql/expressions/conditions"; +/** + * Serialized values converters for database. + */ +export const serializedToDatabaseTypes: Record any> = { + "date": (serializedValue: string) => new Date(serializedValue), +}; + /** * Model query manager. */ @@ -33,6 +40,62 @@ export class ModelQuery< return (new this.modelClass()).deserialize(rawModel) as ModelType; } + /** + * Save a model in database. + * @param model The model to save. + */ + async save(model: ModelType): Promise + { + // Get serialized model update. + const serializedModel = model.patch(); + + // Get table columns of the model. + const tableColumns = getTableColumns(this.table); + + // Create model data for the database. + const databaseModelData = Object.fromEntries( + Object.entries(serializedModel).map( + // Only keep table column values and convert them into database types, if it is required. + ([key, value]) => [key, tableColumns?.[key] ? (serializedToDatabaseTypes?.[tableColumns?.[key].dataType]?.(value) ?? value) : undefined] + ) + ) as Partial>; + + // Initialize query result variable. + let result: any; + + if (model.isNew()) + { // Insert the new model in database and get the inserted row data. + result = (await (this.database.insert(this.table)).values(databaseModelData as any).returning() as any)?.[0]; + } + else + { // Update model data in database, and get the updated row data. + result = (await (this.database.update(this.table) + .set(databaseModelData) + .where(eq((this.table as any)?.[model.getIdentifierName()], model.getIdentifier()))) + .returning() as any)?.[0]; + } + + // Update model from inserted or updated row data. + model.deserialize(result); + + return true; + } + + /** + * Refresh given model data from database. + * @param model The model to refresh. + */ + async refresh(model: ModelType): Promise + { + // Update model from up-to-date row data. + model.deserialize( + (( // Retrieve model data from database. + await this.database.select().from(this.table) + .where(eq((this.table as any)?.[model.getIdentifierName()], model.getIdentifier())) + ) as any)[0] + ); + } + /** * Find models matching the given configuration. * @param config Request configuration.