From 2ccd5af61133e77b1c5f11a901af7da58d0aeb20 Mon Sep 17 00:00:00 2001 From: yizhi <946185759@qq.com> Date: Tue, 19 Nov 2024 14:36:39 +0800 Subject: [PATCH] =?UTF-8?q?1.=20=E4=BF=AE=E5=A4=8DFloatColumn=E5=AF=B9nume?= =?UTF-8?q?ric=E7=9A=84=E9=97=AE=E9=A2=98=202.=20=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=BA=93=E6=8A=9B=E5=87=BA=E9=94=99=E8=AF=AF=E6=97=B6=EF=BC=8C?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0sql=E5=B1=9E=E6=80=A7=203.=20=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E5=99=A8=E6=8E=92=E5=BA=8F=E9=97=AE=E9=A2=98=E7=9A=84?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- src/database.ts | 28 +++++++++++++++++++++++++--- src/entity.ts | 2 +- src/query.ts | 35 +++++++++++++++++++++++------------ 4 files changed, 50 insertions(+), 17 deletions(-) diff --git a/package.json b/package.json index b813e4d..0598d3a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@yizhi/postgres", - "version": "1.0.8", + "version": "1.0.10", "main": "dist/index.js", "types": "typing/index.d.ts", "scripts": {}, diff --git a/src/database.ts b/src/database.ts index ce49110..a54b7b0 100644 --- a/src/database.ts +++ b/src/database.ts @@ -4,6 +4,10 @@ import { DeleteBuilder, IDeleteBuilder, IInsertBuilder, InsertBuilder, ISelectBu import { Class } from "./types"; import { formatSQL } from "./util"; +interface IQueryResult extends QueryResult { + sql: string; +} + /** * 数据库基本操作 */ @@ -13,7 +17,7 @@ export interface IDatabase { * @param sql sql语句 * @param args sql参数 */ - query(sql: string, args?: any[] | Record): Promise> + query(sql: string, args?: any[] | Record): Promise> /** * 查询实体 @@ -83,7 +87,16 @@ class PostgresClient implements IPostgresClient { this.#client = client; } - public query(sql: string, args?: any[] | Record): Promise> { return this.#client.query(args ? formatSQL(sql, args) : sql); } + public async query(sql: string, args?: any[] | Record): Promise> { + sql = args ? formatSQL(sql, args) : sql; + try { + const res = await this.#client.query(sql); + return { ...res, sql }; + } catch (err: any) { + err.sql = sql; + throw err; + } + } public async trans() { @@ -155,7 +168,16 @@ export const database: IPostgresDatabase = { if (pool) pool.end().catch((err) => console.error(err)); }, - query(sql, args) { return getPool().query(args ? formatSQL(sql, args) : sql); }, + async query(sql, args) { + sql = args ? formatSQL(sql, args) : sql; + try { + const res = await getPool().query(sql); + return { ...res, sql }; + } catch (err: any) { + err.sql = sql; + throw err; + } + }, select(Entity, alias) { return new SelectBuilder(this.query.bind(this), Entity, alias); }, insert(Entity) { return new InsertBuilder(this.query.bind(this), Entity); }, update(Entity) { return new UpdateBuilder(this.query.bind(this), Entity); }, diff --git a/src/entity.ts b/src/entity.ts index 5fbc202..bbccdcd 100644 --- a/src/entity.ts +++ b/src/entity.ts @@ -179,7 +179,7 @@ export function FloatColumn(name?: any, option?: any) { name = undefined; } - return Field(name, v => escapeValue(v), v => v, false, option?.virtual ?? false); + return Field(name, v => escapeValue(v), v => parseFloat(v), false, option?.virtual ?? false); } diff --git a/src/query.ts b/src/query.ts index 94735b9..8d8afb0 100644 --- a/src/query.ts +++ b/src/query.ts @@ -40,7 +40,7 @@ interface ISearchOptionMap { tsquery: string | string[] | { /** 关键字 */ keywords: string | string[] - /** 是否进行绝对匹配,如果为true,则只匹配关键字,否则匹配关键字前缀,默认true */ + /** 是否进行绝对匹配,如果为true,则只匹配关键字,否则匹配关键字前缀,默认false */ absolute?: boolean /** 匹配方式,默认or */ method?: "or" | "and" @@ -140,7 +140,14 @@ interface IGroupFn { group(...name: Array<(keyof E) | (() => string)>): this } -export interface ISelectBuilder extends IWhereFn, IFilterFn, IJoinFn { +interface IOrderByOption { + /** 对nul字段的处理方式 */ + nulls?: "first" | "last" + /** 是否将排序字段添加到内部的分组中 */ + group?: boolean +} + +export interface ISelectBuilder extends IWhereFn, IFilterFn, IJoinFn, IGroupFn { /** * 设置查询偏移 * @param offset 查询偏移 @@ -158,13 +165,13 @@ export interface ISelectBuilder extends IWhereFn, IFil * @param name 排序名称 * @param sort 排序方式 */ - order(name: string, sort: "asc" | "desc"): this + order(name: string, sort: "asc" | "desc", option?: IOrderByOption): this /** * 排序 * @param name 排序名称 * @param sort 排序方式 */ - order(name: keyof E, sort: "asc" | "desc"): this + order(name: keyof E, sort: "asc" | "desc", option?: IOrderByOption): this // __sql__(count: boolean): string @@ -472,7 +479,7 @@ function WithWhere>(Base: B) { const opt = option as ISearchOptionMap["tsquery"]; let keywords: string[]; let method: "or" | "and" = "or"; - let absolute = true; + let absolute = false; //处理选项 if (typeof opt === "string") keywords = opt.split(/\s+/).map(s => s.trim()).filter(s => s.length); else if (opt instanceof Array) keywords = opt; @@ -617,6 +624,7 @@ class Joinner extends WithGroup(WithJoin(WithWhere(WithFi } public build(base: BE, data: D[]) { + if (!this.columns.length) return; const parsed = this.__build__(data, this.joinners); if (this.#joinConfig.many) base[this.#baseName as keyof BE] = parsed as any; else base[this.#baseName as keyof BE] = (parsed[0] ?? null) as any; @@ -626,7 +634,7 @@ class Joinner extends WithGroup(WithJoin(WithWhere(WithFi export class SelectBuilder extends WithGroup(WithJoin(WithWhere(WithFilter(SQLBuilder)))) implements ISelectBuilder { #offset?: number #limit?: number - #orders?: Array<[name: string, order: "asc" | "desc"]> + #orders?: Array<[name: string, order: "asc" | "desc", nulls: "first" | "last" | null, group: boolean]> #query: IQueryFunc #fullJoinners?: Joinner[] @@ -645,11 +653,11 @@ export class SelectBuilder extends WithGroup(WithJoin(Wit return this; } - public order(name: any, sort: "asc" | "desc") { + public order(name: any, sort: "asc" | "desc", option?: IOrderByOption) { this.#orders ??= []; const col = this.config.fields.find(f => f.prop === name); - if (col) this.#orders.push([escapeID(this.alias, col.name), sort]); - else this.#orders.push([name, sort]); + if (col) this.#orders.push([escapeID(this.alias, col.name), sort, option?.nulls ?? null, option?.group ?? false]); + else this.#orders.push([name, sort, option?.nulls ?? null, option?.group ?? false]); return this; } @@ -670,6 +678,7 @@ export class SelectBuilder extends WithGroup(WithJoin(Wit } async findAndCount() { + // console.log(this.__sql__(true)) const res = await this.#query(this.__sql__(true)); const count = res.rows[0]?.__data_count__ ?? 0; return [this.build(res.rows) as E[], parseInt(count)] as [E[], number]; @@ -710,14 +719,16 @@ export class SelectBuilder extends WithGroup(WithJoin(Wit } public __inner_sql__(count: boolean, join = "\n") { + const groups = [...this.primaryNames.map(p => escapeID(this.alias, p))]; + this.#orders?.filter(([name, ord, nulls, group]) => group).forEach(([name, ord, nulls, group]) => groups.push(name)); //内部的join const innerSQLItems = [ `select ${escapeID(this.alias)}.*${count ? `, count(*) over () as __data_count__` : ''}`, //字段列表 `from ${this.tableSQL} ${escapeID(this.alias)}`, //表名 ...this.__joins__, //join ...this.__wheres__.length ? [`where ${this.__wheres__}`] : [], //where条件 - `group by ${this.primaryNames.map(p => escapeID(this.alias, p)).join(",")}`, //内部查询分组 - ...(!count && this.#orders?.length) ? [`order by ${this.#orders.map(([name, order]) => `${name} ${order}`).join(",")}`] : [], //排序 + `group by ${groups.join(",")}`, //内部查询分组 + ...(count && this.#orders?.length) ? [`order by ${this.#orders.map(([name, ord, nulls]) => `${name} ${ord}${nulls ? ` nulls ${nulls}` : ""}`).join(",")}`] : [], //排序 ...(typeof this.#offset == "number") ? [`offset ${this.#offset}`] : [], //offset ...(typeof this.#limit == "number") ? [`limit ${this.#limit}`] : [], //limit ]; @@ -732,7 +743,7 @@ export class SelectBuilder extends WithGroup(WithJoin(Wit ...this.__joins__, //join ...this.__wheres__.length ? [`where ${this.__wheres__}`] : [], //where条件 ...this.ctx.groups.length ? [`group by ${this.ctx.groups.join(",")}`] : [], //分组 - ...this.#orders ? [`order by ${this.#orders.map(([name, ord]) => `${name} ${ord}`).join(", ")}`] : [], //排序 + ...this.#orders ? [`order by ${this.#orders.map(([name, ord, nulls]) => `${name} ${ord}${nulls ? ` nulls ${nulls}` : ""}`).join(", ")}`] : [], //排序 ]; return outterSQLItems.join("\n");