Lodash 是一個很實用的 JavaScript 函式庫。它提供了很多預設的實用函數,可以更容易地處理數據、操作物件和字串,並控制函數的執行。目的是為了簡化重複性的代碼,減少開發時間和錯誤。
這個是 TypeScript 的型別定義包,用於 Lodash 函式庫。當你在用 TypeScript 開發時,它提供 Lodash 函數的型別定義,這樣編譯器在使用 Lodash 時得到自動完成功能和型別檢查。如果只是用 JavaScript,那就不需要下載這個型別定義包。
export interface IBase<T> {
findAll(trx?: Knex.Transaction): Promise<T[] | null>;
findOne(id: any, trx?: Knex.Transaction): Promise<T | null>;
create(data: Omit<T, 'id'>, trx?: Knex.Transaction): Promise<T | null>;
update(id: any, data: Partial<Omit<T, 'id'>>, trx?: Knex.Transaction): Promise<T | null>;
delete(id: any, trx?: Knex.Transaction): Promise<void>;
}
interface
是用來定義物件結構的一種方式。它描述了物件應該有哪些屬性及其類型。IBase
是一個介面,用來定義一組針對資料庫操作的常見方法。IBase
時,才會傳入真正的類型。created_at
和 updated_at
)、唯一標識碼(UUID)、系統內部狀態。T
表示單一的一個資料元素,而 T[]
則表示一個包含多個資料元素的陣列。也就是說,查詢所有資料用 T[]
表示資料陣列,查詢單一資料或創建新資料用 T
表示單個資料。void
是 TypeScript 和 JavaScript 中用來表示「沒有返回值」的函數。export abstract class Base<T> implements IBase<T> {
protected knexSql: Knex;
protected tableName: string = '';
protected schema = {};
constructor({ knexSql, tableName }: { knexSql: Knex, tableName?: string }) {
this.knexSql = knexSql;
if (tableName) this.tableName = tableName;
}
public findAll = async (trx?: Knex.Transaction) => {
//select col1, col2, ...from tableName
let sqlBuilder = this.knexSql(this.tableName).select(this.schema);
if (trx) sqlBuilder = sqlBuilder.transacting(trx);
const result = await sqlBuilder;
if (isEmpty(result)) return null;
return result.map(this.DBData2DataObject) as T[];
}
public findAll = async (trx?: Knex.Transaction) => {}
let sqlBuilder = this.knexSql(this.tableName).select(this.schema);
if (trx) sqlBuilder = sqlBuilder.transacting(trx);
如果有提供 trx 交易物件,則將查詢納入該交易,以確保資料的一致性和原子性。
const result = await sqlBuilder;
if (isEmpty(result)) return null;
return result.map(this.DBData2DataObject) as T[];
public findOne = async (id: any, trx?: Knex.Transaction) => {
let sqlBuilder = this.knexSql(this.tableName).select(this.schema).where(id);
if (trx) sqlBuilder = sqlBuilder.transacting(trx);
const result = await sqlBuilder;
if (isEmpty(result)) return null;
return this.DBData2DataObject(result[0]) as T;
}
public create = async (data: Omit<T, 'id'>, trx?: Knex.Transaction) => {
let sqlBuilder = this.knexSql(this.tableName).insert(this.DataObject2DBData(data));
if (trx) sqlBuilder = sqlBuilder.transacting(trx);
const result = await sqlBuilder;
if (isEmpty(result)) return null;
const id = result[0];
return await this.findOne(id, trx);
}
public create = async (data: Omit<T, 'id'>, trx?: Knex.Transaction) => {
let sqlBuilder = this.knexSql(this.tableName).insert(this.DataObject2DBData(data));
if (isEmpty(result)) return null;
const id = result[0];
return await this.findOne(id, trx);
public update = async (id: any, data: Partial<Omit<T, 'id'>>, trx?: Knex.Transaction) => {
let sqlBuilder = this.knexSql(this.tableName).update(this.DataObject2DBData(data).where({ id }));
if (trx) sqlBuilder = sqlBuilder.transacting(trx);
await sqlBuilder;
return await this.findOne(id, trx);}
public delete = async (id: any, trx?: Knex.Transaction) => {程式碼解說:
let sqlBuilder = this.knexSql(this.tableName).where({ id }).del();
if (trx) sqlBuilder = sqlBuilder.transacting(trx);
await sqlBuilder;
return
}
return;
private DBData2DataObject = (data: any) => {
const transform = mapValues(data, (value, key) => {
if (['updatedAt', 'createdAt'].includes(key)) return new Date(value);
if (isJson(value)) return JSON.parse(value);
return value;
});
return mapKeys(transform, (_value, key) => camelCase(key));
}
private DataObject2DBData = (data: any) => {
const transform = mapValues(data, (value, key) => {
if (['updatedAt', 'createdAt'].includes(key)) return new Date(value);
if (isJson(value)) return JSON.parse(value);
return value;
});
return mapKeys(transform, (_value, key) => snakeCase(key));
}
export const isJson = (value: string) => {
try {
return Boolean(JSON.parse(value));
} catch (e) {
return false;
}
}
export const isJson = (value: string) => {}
try
區塊:try {
return Boolean(JSON.parse(value));
}
catch
區塊:catch (e) {
return false;
}
Product
的 介面:export interface Product {
//符合 TypeScript 的語法和類型系統
id: number;
name: string;
amount: number;
description: string;
pre_order: number;
price: number;
}
IProductModel
的 介面:export interface IProductModel extends IBase<Product> {}
簡單來說,IProductModel
介面是 IBase
介面的具體化,專門用於操作 Product
類型的資料。這樣定義能讓代碼更具模組化和可重用性。
export class ProductModel extends Base<Product> implements IProductModel {}
tableName = 'products';
schema
屬性:schema = {
id: 'id',
name: 'name',
amount: 'amount',
description: 'description',
pre_order: 'pre_order',
price: 'price'
};
constructor({ knexSql, tableName }: { knexSql: Knex; tableName?: string }) {
super({ knexSql, tableName });
}
super
),將這些參數傳遞給父類別進行初始化。createModel
:static createModel = ({
knexSql,
tableName,
}: {
knexSql: Knex;
tableName?: string;
}) => {
return new ProductModel({ knexSql, tableName })
}