Move all database queries in ModelQuery class.
This commit is contained in:
parent
ff793f31f4
commit
a29e6f4428
2 changed files with 80 additions and 53 deletions
|
@ -1,16 +1,9 @@
|
||||||
import {IdentifierType, Model, ModelShape, SerializedModel} from "@sharkitek/core";
|
import {IdentifierType, Model, ModelClass, ModelShape} from "@sharkitek/core";
|
||||||
import {eq, getTableColumns, Table, TableConfig} from "drizzle-orm";
|
import {Table, TableConfig} from "drizzle-orm";
|
||||||
import {PgDatabase} from "drizzle-orm/pg-core";
|
import {PgDatabase} from "drizzle-orm/pg-core";
|
||||||
import {PgQueryResultHKT} from "drizzle-orm/pg-core/session";
|
import {PgQueryResultHKT} from "drizzle-orm/pg-core/session";
|
||||||
import type {ExtractTablesWithRelations, TablesRelationalConfig} from "drizzle-orm/relations";
|
import type {ExtractTablesWithRelations, TablesRelationalConfig} from "drizzle-orm/relations";
|
||||||
import {ModelQuery} from "./Query";
|
import {ModelQuery, query} from "./Query";
|
||||||
|
|
||||||
/**
|
|
||||||
* Serialized values converters for database.
|
|
||||||
*/
|
|
||||||
export const serializedToDatabaseTypes: Record<string, (serializedValue: any) => any> = {
|
|
||||||
"date": (serializedValue: string) => new Date(serializedValue),
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sharkitek model extension for Drizzle.
|
* Sharkitek model extension for Drizzle.
|
||||||
|
@ -40,7 +33,8 @@ export class DrizzleModel<
|
||||||
Shape extends ModelShape, Identifier extends keyof Shape = any, TSchema extends TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>
|
Shape extends ModelShape, Identifier extends keyof Shape = any, TSchema extends TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
constructor(protected model: ModelType,
|
constructor(protected modelClass: ModelClass<ModelType & DrizzleExtension<ModelType, TableType, TC, TQueryResult, TFullSchema, Scopes, Shape, Identifier, TSchema>, Shape, Identifier>,
|
||||||
|
protected model: ModelType,
|
||||||
protected database: PgDatabase<TQueryResult, TFullSchema, TSchema>,
|
protected database: PgDatabase<TQueryResult, TFullSchema, TSchema>,
|
||||||
protected table: TableType,
|
protected table: TableType,
|
||||||
protected scopes: Scopes & ThisType<ModelQuery<ModelType, TableType, TC, TQueryResult, TFullSchema, Shape, Identifier, TSchema>>)
|
protected scopes: Scopes & ThisType<ModelQuery<ModelType, TableType, TC, TQueryResult, TFullSchema, Shape, Identifier, TSchema>>)
|
||||||
|
@ -75,50 +69,17 @@ export class DrizzleModel<
|
||||||
*/
|
*/
|
||||||
async save(): Promise<boolean>
|
async save(): Promise<boolean>
|
||||||
{
|
{
|
||||||
// Get serialized model update.
|
// New query to save the model.
|
||||||
const serializedModel = this.model.patch();
|
return query(this.modelClass).save(this.model as any);
|
||||||
|
|
||||||
// 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<SerializedModel<Shape>>;
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refresh model data from database.
|
||||||
|
*/
|
||||||
async refresh(): Promise<void>
|
async refresh(): Promise<void>
|
||||||
{
|
{
|
||||||
// Update model from up-to-date row data.
|
// New query to refresh the model.
|
||||||
this.model.deserialize(
|
await query(this.modelClass).refresh(this.model as any);
|
||||||
(( // 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]
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,7 +106,10 @@ export function drizzle<
|
||||||
drizzle(): DrizzleModel<ModelType, TableType, TC, TQueryResult, TFullSchema, Scopes, Shape, Identifier, TSchema>
|
drizzle(): DrizzleModel<ModelType, TableType, TC, TQueryResult, TFullSchema, Scopes, Shape, Identifier, TSchema>
|
||||||
{
|
{
|
||||||
// Initialize drizzle model manager instance.
|
// Initialize drizzle model manager instance.
|
||||||
return new DrizzleModel<ModelType, TableType, TC, TQueryResult, TFullSchema, Scopes, Shape, Identifier, TSchema>(this, database, table, scopes);
|
return new DrizzleModel<ModelType, TableType, TC, TQueryResult, TFullSchema, Scopes, Shape, Identifier, TSchema>(
|
||||||
|
this.constructor as ModelClass<ModelType & DrizzleExtension<ModelType, TableType, TC, TQueryResult, TFullSchema, Scopes, Shape, Identifier, TSchema>, Shape, Identifier>,
|
||||||
|
this, database, table, scopes
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
65
src/Query.ts
65
src/Query.ts
|
@ -1,5 +1,5 @@
|
||||||
import {AnyModel, IdentifierType, Model, ModelClass, ModelShape, SerializedModel} from "@sharkitek/core";
|
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 {PgDatabase} from "drizzle-orm/pg-core";
|
||||||
import {PgQueryResultHKT} from "drizzle-orm/pg-core/session";
|
import {PgQueryResultHKT} from "drizzle-orm/pg-core/session";
|
||||||
import type {DBQueryConfig, ExtractTablesWithRelations, TablesRelationalConfig} from "drizzle-orm/relations";
|
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 {DrizzleExtension} from "./Drizzle";
|
||||||
import {inArray} from "drizzle-orm/sql/expressions/conditions";
|
import {inArray} from "drizzle-orm/sql/expressions/conditions";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialized values converters for database.
|
||||||
|
*/
|
||||||
|
export const serializedToDatabaseTypes: Record<string, (serializedValue: any) => any> = {
|
||||||
|
"date": (serializedValue: string) => new Date(serializedValue),
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Model query manager.
|
* Model query manager.
|
||||||
*/
|
*/
|
||||||
|
@ -33,6 +40,62 @@ export class ModelQuery<
|
||||||
return (new this.modelClass()).deserialize(rawModel) as ModelType;
|
return (new this.modelClass()).deserialize(rawModel) as ModelType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save a model in database.
|
||||||
|
* @param model The model to save.
|
||||||
|
*/
|
||||||
|
async save(model: ModelType): Promise<boolean>
|
||||||
|
{
|
||||||
|
// 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<SerializedModel<Shape>>;
|
||||||
|
|
||||||
|
// 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<void>
|
||||||
|
{
|
||||||
|
// 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.
|
* Find models matching the given configuration.
|
||||||
* @param config Request configuration.
|
* @param config Request configuration.
|
||||||
|
|
Loading…
Reference in a new issue