1. 修复FloatColumn对numeric的问题
2. 数据库抛出错误时,增加sql属性 3. 查询器排序问题的修复
This commit is contained in:
@ -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": {},
|
||||||
|
@ -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); },
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
35
src/query.ts
35
src/query.ts
@ -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");
|
||||||
|
Reference in New Issue
Block a user