1. 修复FloatColumn对numeric的问题

2. 数据库抛出错误时,增加sql属性
3. 查询器排序问题的修复
This commit is contained in:
2024-11-19 14:36:39 +08:00
parent 3be2c77008
commit 2ccd5af611
4 changed files with 50 additions and 17 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "@yizhi/postgres", "name": "@yizhi/postgres",
"version": "1.0.8", "version": "1.0.10",
"main": "dist/index.js", "main": "dist/index.js",
"types": "typing/index.d.ts", "types": "typing/index.d.ts",
"scripts": {}, "scripts": {},

View File

@ -4,6 +4,10 @@ import { DeleteBuilder, IDeleteBuilder, IInsertBuilder, InsertBuilder, ISelectBu
import { Class } from "./types"; import { Class } from "./types";
import { formatSQL } from "./util"; import { formatSQL } from "./util";
interface IQueryResult<R extends QueryResultRow = any> extends QueryResult<R> {
sql: string;
}
/** /**
* 数据库基本操作 * 数据库基本操作
*/ */
@ -13,7 +17,7 @@ export interface IDatabase {
* @param sql sql语句 * @param sql sql语句
* @param args sql参数 * @param args sql参数
*/ */
query<R extends QueryResultRow = any>(sql: string, args?: any[] | Record<string, any>): Promise<QueryResult<R>> query<R extends QueryResultRow = any>(sql: string, args?: any[] | Record<string, any>): Promise<IQueryResult<R>>
/** /**
* 查询实体 * 查询实体
@ -83,7 +87,16 @@ class PostgresClient implements IPostgresClient {
this.#client = client; this.#client = client;
} }
public query<R extends QueryResultRow = any>(sql: string, args?: any[] | Record<string, any>): Promise<QueryResult<R>> { return this.#client.query(args ? formatSQL(sql, args) : sql); } public async query<R extends QueryResultRow = any>(sql: string, args?: any[] | Record<string, any>): Promise<IQueryResult<R>> {
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() { public async trans() {
@ -155,7 +168,16 @@ export const database: IPostgresDatabase = {
if (pool) pool.end().catch((err) => console.error(err)); 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); }, select(Entity, alias) { return new SelectBuilder(this.query.bind(this), Entity, alias); },
insert(Entity) { return new InsertBuilder(this.query.bind(this), Entity); }, insert(Entity) { return new InsertBuilder(this.query.bind(this), Entity); },
update(Entity) { return new UpdateBuilder(this.query.bind(this), Entity); }, update(Entity) { return new UpdateBuilder(this.query.bind(this), Entity); },

View File

@ -179,7 +179,7 @@ export function FloatColumn(name?: any, option?: any) {
name = undefined; 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);
} }

View File

@ -40,7 +40,7 @@ interface ISearchOptionMap {
tsquery: string | string[] | { tsquery: string | string[] | {
/** 关键字 */ /** 关键字 */
keywords: string | string[] keywords: string | string[]
/** 是否进行绝对匹配如果为true则只匹配关键字否则匹配关键字前缀默认true */ /** 是否进行绝对匹配如果为true则只匹配关键字否则匹配关键字前缀默认false */
absolute?: boolean absolute?: boolean
/** 匹配方式默认or */ /** 匹配方式默认or */
method?: "or" | "and" method?: "or" | "and"
@ -140,7 +140,14 @@ interface IGroupFn<E extends BasicEntity> {
group(...name: Array<(keyof E) | (() => string)>): this group(...name: Array<(keyof E) | (() => string)>): this
} }
export interface ISelectBuilder<E extends BasicEntity> extends IWhereFn<E>, IFilterFn<E>, IJoinFn<E> { interface IOrderByOption {
/** 对nul字段的处理方式 */
nulls?: "first" | "last"
/** 是否将排序字段添加到内部的分组中 */
group?: boolean
}
export interface ISelectBuilder<E extends BasicEntity> extends IWhereFn<E>, IFilterFn<E>, IJoinFn<E>, IGroupFn<E> {
/** /**
* 设置查询偏移 * 设置查询偏移
* @param offset 查询偏移 * @param offset 查询偏移
@ -158,13 +165,13 @@ export interface ISelectBuilder<E extends BasicEntity> extends IWhereFn<E>, IFil
* @param name 排序名称 * @param name 排序名称
* @param sort 排序方式 * @param sort 排序方式
*/ */
order(name: string, sort: "asc" | "desc"): this order(name: string, sort: "asc" | "desc", option?: IOrderByOption): this
/** /**
* 排序 * 排序
* @param name 排序名称 * @param name 排序名称
* @param sort 排序方式 * @param sort 排序方式
*/ */
order(name: keyof E, sort: "asc" | "desc"): this order(name: keyof E, sort: "asc" | "desc", option?: IOrderByOption): this
// __sql__(count: boolean): string // __sql__(count: boolean): string
@ -472,7 +479,7 @@ function WithWhere<E extends BasicEntity, B extends Constructor<E>>(Base: B) {
const opt = option as ISearchOptionMap["tsquery"]; const opt = option as ISearchOptionMap["tsquery"];
let keywords: string[]; let keywords: string[];
let method: "or" | "and" = "or"; 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); if (typeof opt === "string") keywords = opt.split(/\s+/).map(s => s.trim()).filter(s => s.length);
else if (opt instanceof Array) keywords = opt; else if (opt instanceof Array) keywords = opt;
@ -617,6 +624,7 @@ class Joinner<E extends BasicEntity> extends WithGroup(WithJoin(WithWhere(WithFi
} }
public build<BE extends BasicEntity, D>(base: BE, data: D[]) { public build<BE extends BasicEntity, D>(base: BE, data: D[]) {
if (!this.columns.length) return;
const parsed = this.__build__(data, this.joinners); const parsed = this.__build__(data, this.joinners);
if (this.#joinConfig.many) base[this.#baseName as keyof BE] = parsed as any; 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; else base[this.#baseName as keyof BE] = (parsed[0] ?? null) as any;
@ -626,7 +634,7 @@ class Joinner<E extends BasicEntity> extends WithGroup(WithJoin(WithWhere(WithFi
export class SelectBuilder<E extends BasicEntity> extends WithGroup(WithJoin(WithWhere(WithFilter(SQLBuilder))))<E> implements ISelectBuilder<E> { export class SelectBuilder<E extends BasicEntity> extends WithGroup(WithJoin(WithWhere(WithFilter(SQLBuilder))))<E> implements ISelectBuilder<E> {
#offset?: number #offset?: number
#limit?: 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<any> #query: IQueryFunc<any>
#fullJoinners?: Joinner<any>[] #fullJoinners?: Joinner<any>[]
@ -645,11 +653,11 @@ export class SelectBuilder<E extends BasicEntity> extends WithGroup(WithJoin(Wit
return this; return this;
} }
public order(name: any, sort: "asc" | "desc") { public order(name: any, sort: "asc" | "desc", option?: IOrderByOption) {
this.#orders ??= []; this.#orders ??= [];
const col = this.config.fields.find(f => f.prop === name); const col = this.config.fields.find(f => f.prop === name);
if (col) this.#orders.push([escapeID(this.alias, col.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]); else this.#orders.push([name, sort, option?.nulls ?? null, option?.group ?? false]);
return this; return this;
} }
@ -670,6 +678,7 @@ export class SelectBuilder<E extends BasicEntity> extends WithGroup(WithJoin(Wit
} }
async findAndCount() { async findAndCount() {
// console.log(this.__sql__(true))
const res = await this.#query(this.__sql__(true)); const res = await this.#query(this.__sql__(true));
const count = res.rows[0]?.__data_count__ ?? 0; const count = res.rows[0]?.__data_count__ ?? 0;
return [this.build(res.rows) as E[], parseInt(count)] as [E[], number]; return [this.build(res.rows) as E[], parseInt(count)] as [E[], number];
@ -710,14 +719,16 @@ export class SelectBuilder<E extends BasicEntity> extends WithGroup(WithJoin(Wit
} }
public __inner_sql__(count: boolean, join = "\n") { 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 //内部的join
const innerSQLItems = [ const innerSQLItems = [
`select ${escapeID(this.alias)}.*${count ? `, count(*) over () as __data_count__` : ''}`, //字段列表 `select ${escapeID(this.alias)}.*${count ? `, count(*) over () as __data_count__` : ''}`, //字段列表
`from ${this.tableSQL} ${escapeID(this.alias)}`, //表名 `from ${this.tableSQL} ${escapeID(this.alias)}`, //表名
...this.__joins__, //join ...this.__joins__, //join
...this.__wheres__.length ? [`where ${this.__wheres__}`] : [], //where条件 ...this.__wheres__.length ? [`where ${this.__wheres__}`] : [], //where条件
`group by ${this.primaryNames.map(p => escapeID(this.alias, p)).join(",")}`, //内部查询分组 `group by ${groups.join(",")}`, //内部查询分组
...(!count && this.#orders?.length) ? [`order by ${this.#orders.map(([name, order]) => `${name} ${order}`).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.#offset == "number") ? [`offset ${this.#offset}`] : [], //offset
...(typeof this.#limit == "number") ? [`limit ${this.#limit}`] : [], //limit ...(typeof this.#limit == "number") ? [`limit ${this.#limit}`] : [], //limit
]; ];
@ -732,7 +743,7 @@ export class SelectBuilder<E extends BasicEntity> extends WithGroup(WithJoin(Wit
...this.__joins__, //join ...this.__joins__, //join
...this.__wheres__.length ? [`where ${this.__wheres__}`] : [], //where条件 ...this.__wheres__.length ? [`where ${this.__wheres__}`] : [], //where条件
...this.ctx.groups.length ? [`group by ${this.ctx.groups.join(",")}`] : [], //分组 ...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"); return outterSQLItems.join("\n");