durcno 1.0.0-alpha.16 → 1.0.0-alpha.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin.cjs +4 -2
- package/dist/src/columns/common.d.mts +1 -1
- package/dist/src/constraints/check.d.mts +1 -1
- package/dist/src/cte.d.mts +16 -0
- package/dist/src/cte.mjs +5 -0
- package/dist/src/db.d.mts +24 -1
- package/dist/src/db.mjs +10 -1
- package/dist/src/filters/array.d.mts +1 -1
- package/dist/src/filters/index.d.mts +1 -1
- package/dist/src/filters/index.mjs +1 -1
- package/dist/src/filters/string.d.mts +1 -1
- package/dist/src/functions/aggregate.d.mts +24 -8
- package/dist/src/functions/aggregate.mjs +68 -9
- package/dist/src/functions/arithmetic.d.mts +67 -0
- package/dist/src/functions/arithmetic.mjs +123 -0
- package/dist/src/functions/index.d.mts +15 -18
- package/dist/src/functions/index.mjs +19 -23
- package/dist/src/functions/numeric.d.mts +16 -1
- package/dist/src/functions/numeric.mjs +45 -0
- package/dist/src/functions/pgvector.d.mts +4 -1
- package/dist/src/functions/pgvector.mjs +9 -0
- package/dist/src/functions/postgis.d.mts +3 -0
- package/dist/src/functions/postgis.mjs +9 -0
- package/dist/src/functions/string.d.mts +22 -1
- package/dist/src/functions/string.mjs +63 -0
- package/dist/src/index.d.mts +8 -5
- package/dist/src/index.mjs +3 -1
- package/dist/src/query-builders/aggregates.d.mts +1 -1
- package/dist/src/query-builders/count.d.mts +1 -1
- package/dist/src/query-builders/delete.d.mts +14 -7
- package/dist/src/query-builders/delete.mjs +26 -9
- package/dist/src/query-builders/distinct.d.mts +1 -1
- package/dist/src/query-builders/exists.d.mts +1 -1
- package/dist/src/query-builders/first.d.mts +1 -1
- package/dist/src/query-builders/helpers.mjs +28 -0
- package/dist/src/query-builders/insert.d.mts +9 -5
- package/dist/src/query-builders/insert.mjs +19 -7
- package/dist/src/query-builders/orderby-clause.d.mts +1 -1
- package/dist/src/query-builders/pre.d.mts +1 -1
- package/dist/src/query-builders/query-promise.d.mts +2 -2
- package/dist/src/query-builders/query.d.mts +2 -1
- package/dist/src/query-builders/rq.d.mts +2 -2
- package/dist/src/query-builders/select.d.mts +14 -6
- package/dist/src/query-builders/select.mjs +37 -13
- package/dist/src/query-builders/update.d.mts +15 -8
- package/dist/src/query-builders/update.mjs +22 -9
- package/dist/src/query-builders/with.d.mts +51 -0
- package/dist/src/query-builders/with.mjs +47 -0
- package/dist/src/table.d.mts +3 -1
- package/dist/src/table.mjs +2 -2
- package/dist/src/virtual-table.d.mts +51 -0
- package/dist/src/virtual-table.mjs +55 -0
- package/package.json +1 -1
package/dist/bin.cjs
CHANGED
|
@@ -9631,7 +9631,9 @@ function orderTables(tables, order) {
|
|
|
9631
9631
|
Object.entries(tables).map(([tableName, table]) => {
|
|
9632
9632
|
const references = Object.values(table.columns).map(
|
|
9633
9633
|
(column) => column.references ? `${column.references.schema}.${column.references.table}` : void 0
|
|
9634
|
-
).filter(
|
|
9634
|
+
).filter(
|
|
9635
|
+
(table2) => table2 !== void 0 && table2 !== tableName
|
|
9636
|
+
);
|
|
9635
9637
|
return [tableName, references];
|
|
9636
9638
|
})
|
|
9637
9639
|
);
|
|
@@ -10455,7 +10457,7 @@ async function status(options) {
|
|
|
10455
10457
|
}
|
|
10456
10458
|
|
|
10457
10459
|
// src/cli/index.ts
|
|
10458
|
-
program.version("1.0.0-alpha.
|
|
10460
|
+
program.version("1.0.0-alpha.16");
|
|
10459
10461
|
var Options = {
|
|
10460
10462
|
config: ["--config <path>", "Path to the config file"]
|
|
10461
10463
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { AnyFilter } from "../filters/index.mjs";
|
|
1
2
|
import { CheckExpression } from "../constraints/check.mjs";
|
|
2
3
|
import { entityType } from "../symbols.mjs";
|
|
3
4
|
import { AnyColumn, StdTable, StdTableColumn } from "../table.mjs";
|
|
4
|
-
import { AnyFilter } from "../filters/index.mjs";
|
|
5
5
|
import { Arg } from "../query-builders/pre.mjs";
|
|
6
6
|
import { Query, QueryContext } from "../query-builders/query.mjs";
|
|
7
7
|
import { Sql } from "../sql.mjs";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { AnyColumn, TableAnyColumn } from "../table.mjs";
|
|
2
1
|
import { AnyFilter, Filter } from "../filters/index.mjs";
|
|
2
|
+
import { AnyColumn, TableAnyColumn } from "../table.mjs";
|
|
3
3
|
import { QueryContext } from "../query-builders/query.mjs";
|
|
4
4
|
import { Sql } from "../sql.mjs";
|
|
5
5
|
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { VirtualTable } from "./virtual-table.mjs";
|
|
2
|
+
import { AnyColumn } from "./table.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/cte.d.ts
|
|
5
|
+
declare class Cte<TName extends string, TColumns extends Record<string, AnyColumn>> extends VirtualTable<TName, TColumns> {
|
|
6
|
+
/** Phantom type — extracts `TName` safely through `CteWithColumns` intersections. */
|
|
7
|
+
readonly $cteName: TName;
|
|
8
|
+
}
|
|
9
|
+
type CteWithColumns<TName extends string, TColumns extends Record<string, AnyColumn>> = Cte<TName, TColumns> & TColumns;
|
|
10
|
+
type AnyCteWithColumns = CteWithColumns<any, Record<any, any>>;
|
|
11
|
+
/** Maps a tuple of `CteWithColumns` to an object keyed by CTE name. */
|
|
12
|
+
type CtesByName<TCtes extends AnyCteWithColumns[]> = { [K in TCtes[number] as K extends {
|
|
13
|
+
$cteName: infer TName extends string;
|
|
14
|
+
} ? TName : never]: K };
|
|
15
|
+
//#endregion
|
|
16
|
+
export { AnyCteWithColumns, Cte, CteWithColumns, CtesByName };
|
package/dist/src/cte.mjs
ADDED
package/dist/src/db.d.mts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { CamelToSnake, Valueof } from "./types.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { AnySubquery, InferQueryColumns } from "./virtual-table.mjs";
|
|
3
3
|
import { SelectBuilder } from "./query-builders/select.mjs";
|
|
4
4
|
import { FilterExpression } from "./filters/index.mjs";
|
|
5
|
+
import { AnyColumn, AnyRelations, IsTableWC, Relations, TableWCorNever, TableWithColumns } from "./table.mjs";
|
|
6
|
+
import { AnyCteWithColumns, CteWithColumns } from "./cte.mjs";
|
|
5
7
|
import { Config } from "./index.mjs";
|
|
6
8
|
import { AggregateQuery } from "./query-builders/aggregates.mjs";
|
|
7
9
|
import { CountQuery } from "./query-builders/count.mjs";
|
|
@@ -13,6 +15,7 @@ import { InsertBuilder } from "./query-builders/insert.mjs";
|
|
|
13
15
|
import { RawQuery } from "./query-builders/raw.mjs";
|
|
14
16
|
import { RelationQueryBuilder } from "./query-builders/rq.mjs";
|
|
15
17
|
import { UpdateBuilder } from "./query-builders/update.mjs";
|
|
18
|
+
import { WithStatement } from "./query-builders/with.mjs";
|
|
16
19
|
import { $Pool, QueryExecutor } from "./connectors/common.mjs";
|
|
17
20
|
|
|
18
21
|
//#region src/db.d.ts
|
|
@@ -149,6 +152,26 @@ declare class Base<TTName extends string, TTables extends Record<TTName, TableWi
|
|
|
149
152
|
* @returns A RawQuery instance that resolves to the query result (or transformed result if handler provided)
|
|
150
153
|
*/
|
|
151
154
|
raw<TReturn = unknown>(query: string, args: (string | number | null)[] | undefined, rowsHandler: ((rows: any[]) => TReturn) | undefined): RawQuery<TReturn>;
|
|
155
|
+
/**
|
|
156
|
+
* Create a CTE definition by name.
|
|
157
|
+
* @param name The CTE name to be used in the WITH clause
|
|
158
|
+
* @returns An object with `.as()` to bind a subquery
|
|
159
|
+
*
|
|
160
|
+
* @example
|
|
161
|
+
* const activeCte = db.with("activeUsers").as(db.from(Users).select(...));
|
|
162
|
+
*/
|
|
163
|
+
with<TCteName extends string>(name: TCteName): {
|
|
164
|
+
as: <TQuery extends AnySubquery>(query: TQuery) => CteWithColumns<TCteName, InferQueryColumns<TCteName, TQuery>>;
|
|
165
|
+
};
|
|
166
|
+
/**
|
|
167
|
+
* Attach one or more CTEs to a statement.
|
|
168
|
+
* @param ctes One or more CTE instances created via `db.with("name").as(...)`
|
|
169
|
+
* @returns A `WithStatement` to build the SELECT/INSERT/UPDATE/DELETE against
|
|
170
|
+
*
|
|
171
|
+
* @example
|
|
172
|
+
* const rows = await db.with(activeCte).from(ctes => ctes.activeUsers).select();
|
|
173
|
+
*/
|
|
174
|
+
with<TCtes extends [AnyCteWithColumns, ...AnyCteWithColumns[]]>(...ctes: TCtes): WithStatement<TCtes, TPrepare>;
|
|
152
175
|
}
|
|
153
176
|
declare class DB<TTName extends string, TTables extends Record<TTName, TableWithColumns<string, string, Record<string, AnyColumn>>>, TAllRelations extends Record<StdTableFullName, AnyRelations>> extends Base<TTName, TTables, TAllRelations, false> {
|
|
154
177
|
#private;
|
package/dist/src/db.mjs
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { Query } from "./query-builders/query.mjs";
|
|
2
2
|
import { is } from "./entity.mjs";
|
|
3
|
+
import { Relations, Table } from "./table.mjs";
|
|
4
|
+
import { bindVirtualTableColumns } from "./virtual-table.mjs";
|
|
5
|
+
import { Cte } from "./cte.mjs";
|
|
3
6
|
import { AggregateQuery } from "./query-builders/aggregates.mjs";
|
|
4
7
|
import { CountQuery } from "./query-builders/count.mjs";
|
|
5
8
|
import { DeleteQuery } from "./query-builders/delete.mjs";
|
|
@@ -11,7 +14,7 @@ import { RawQuery } from "./query-builders/raw.mjs";
|
|
|
11
14
|
import { RelationQueryBuilder } from "./query-builders/rq.mjs";
|
|
12
15
|
import { SelectBuilder } from "./query-builders/select.mjs";
|
|
13
16
|
import { UpdateBuilder } from "./query-builders/update.mjs";
|
|
14
|
-
import {
|
|
17
|
+
import { WithStatement } from "./query-builders/with.mjs";
|
|
15
18
|
//#region src/db.ts
|
|
16
19
|
var Base = class {
|
|
17
20
|
#allRelations;
|
|
@@ -119,6 +122,12 @@ var Base = class {
|
|
|
119
122
|
raw(query, args = [], rowsHandler) {
|
|
120
123
|
return new RawQuery(query, args, rowsHandler, this.#getExecutor());
|
|
121
124
|
}
|
|
125
|
+
with(nameOrFirstCte, ...restCtes) {
|
|
126
|
+
if (typeof nameOrFirstCte === "string") return { as: (query) => {
|
|
127
|
+
return bindVirtualTableColumns(new Cte(nameOrFirstCte, query.getResolvedColumns(), query));
|
|
128
|
+
} };
|
|
129
|
+
return new WithStatement([nameOrFirstCte, ...restCtes], this.#getExecutor(), this.$.pre);
|
|
130
|
+
}
|
|
122
131
|
};
|
|
123
132
|
var DB = class extends Base {
|
|
124
133
|
#pool;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { BasicTypes, Or } from "../types.mjs";
|
|
2
|
-
import { AnyColumn } from "../table.mjs";
|
|
3
2
|
import { AnyScalarSqlFn } from "../functions/index.mjs";
|
|
4
3
|
import { SelectQuery } from "../query-builders/select.mjs";
|
|
4
|
+
import { AnyColumn } from "../table.mjs";
|
|
5
5
|
import { Arg, IsArg } from "../query-builders/pre.mjs";
|
|
6
6
|
import { Query, QueryContext } from "../query-builders/query.mjs";
|
|
7
7
|
import { Sql } from "../sql.mjs";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { AnyColumn } from "../table.mjs";
|
|
2
1
|
import { AnyScalarSqlFn, ExprColumns, HasArg, SqlFn } from "./index.mjs";
|
|
2
|
+
import { AnyColumn } from "../table.mjs";
|
|
3
3
|
import { Query, QueryContext } from "../query-builders/query.mjs";
|
|
4
4
|
|
|
5
5
|
//#region src/functions/aggregate.d.ts
|
|
@@ -36,6 +36,9 @@ declare class CountFn<TExpr extends AnyColumn> extends SqlFn<TExpr, false, "aggr
|
|
|
36
36
|
private readonly expr;
|
|
37
37
|
readonly isAggregate = true;
|
|
38
38
|
constructor(expr: TExpr);
|
|
39
|
+
toDriverValue(value: number | null): unknown;
|
|
40
|
+
toSQLValue(value: number | null): string;
|
|
41
|
+
fromDriverValue(value: unknown): number | null;
|
|
39
42
|
/** Appends `count(expr)` to the query SQL. */
|
|
40
43
|
toQuery(query: Query, ctx?: QueryContext): void;
|
|
41
44
|
}
|
|
@@ -50,6 +53,9 @@ declare class CountFn<TExpr extends AnyColumn> extends SqlFn<TExpr, false, "aggr
|
|
|
50
53
|
*/
|
|
51
54
|
declare class CountStarFn extends SqlFn<never, false, "aggregate", "numeric", number> {
|
|
52
55
|
readonly isAggregate = true;
|
|
56
|
+
toDriverValue(value: number | null): unknown;
|
|
57
|
+
toSQLValue(value: number | null): string;
|
|
58
|
+
fromDriverValue(value: unknown): number | null;
|
|
53
59
|
/** Appends `count(*)` to the query SQL. */
|
|
54
60
|
toQuery(query: Query, _ctx?: QueryContext): void;
|
|
55
61
|
}
|
|
@@ -66,6 +72,9 @@ declare class CountDistinctFn<TExpr extends AnyColumn> extends SqlFn<TExpr, fals
|
|
|
66
72
|
private readonly expr;
|
|
67
73
|
readonly isAggregate = true;
|
|
68
74
|
constructor(expr: TExpr);
|
|
75
|
+
toDriverValue(value: number | null): unknown;
|
|
76
|
+
toSQLValue(value: number | null): string;
|
|
77
|
+
fromDriverValue(value: unknown): number | null;
|
|
69
78
|
/** Appends `count(DISTINCT expr)` to the query SQL. */
|
|
70
79
|
toQuery(query: Query, ctx?: QueryContext): void;
|
|
71
80
|
}
|
|
@@ -111,6 +120,9 @@ declare class SumFn<TExpr extends NumericAggregateInput> extends SqlFn<ExprColum
|
|
|
111
120
|
private readonly expr;
|
|
112
121
|
readonly isAggregate = true;
|
|
113
122
|
constructor(expr: TExpr);
|
|
123
|
+
toDriverValue(value: TExpr["$"]["TsType"] | null): unknown;
|
|
124
|
+
toSQLValue(value: TExpr["$"]["TsType"] | null): string;
|
|
125
|
+
fromDriverValue(value: unknown): TExpr["$"]["TsType"] | null;
|
|
114
126
|
/** Appends `sum(expr)` to the query SQL. */
|
|
115
127
|
toQuery(query: Query, ctx?: QueryContext): void;
|
|
116
128
|
}
|
|
@@ -140,12 +152,12 @@ declare class AvgFn<TExpr extends NumericAggregateInput> extends SqlFn<ExprColum
|
|
|
140
152
|
private readonly expr;
|
|
141
153
|
readonly isAggregate = true;
|
|
142
154
|
constructor(expr: TExpr);
|
|
155
|
+
toDriverValue(value: TExpr["$"]["TsType"] | null): unknown;
|
|
156
|
+
toSQLValue(value: TExpr["$"]["TsType"] | null): string;
|
|
143
157
|
/**
|
|
144
158
|
* Preserves the raw PostgreSQL `numeric` string (e.g. `"2.5000000000"`).
|
|
145
|
-
* The default `SqlFn.fromDriver` would coerce numeric strings to `number`,
|
|
146
|
-
* which contradicts the declared `string | null` return type.
|
|
147
159
|
*/
|
|
148
|
-
|
|
160
|
+
fromDriverValue(value: unknown): TExpr["$"]["TsType"] | null;
|
|
149
161
|
/** Appends `avg(expr)` to the query SQL. */
|
|
150
162
|
toQuery(query: Query, ctx?: QueryContext): void;
|
|
151
163
|
}
|
|
@@ -176,11 +188,13 @@ declare class MinFn<TExpr extends AggregateInput> extends SqlFn<ExprColumns<TExp
|
|
|
176
188
|
private readonly expr;
|
|
177
189
|
readonly isAggregate = true;
|
|
178
190
|
constructor(expr: TExpr);
|
|
191
|
+
toDriverValue(value: TExpr["$"]["TsType"] | null): unknown;
|
|
192
|
+
toSQLValue(value: TExpr["$"]["TsType"] | null): string;
|
|
179
193
|
/**
|
|
180
|
-
* Delegates to the inner expression's own
|
|
194
|
+
* Delegates to the inner expression's own conversion so that the result
|
|
181
195
|
* is deserialized to the same TypeScript type as the wrapped column/function.
|
|
182
196
|
*/
|
|
183
|
-
|
|
197
|
+
fromDriverValue(value: unknown): TExpr["$"]["TsType"] | null;
|
|
184
198
|
/** Appends `min(expr)` to the query SQL. */
|
|
185
199
|
toQuery(query: Query, ctx?: QueryContext): void;
|
|
186
200
|
}
|
|
@@ -211,11 +225,13 @@ declare class MaxFn<TExpr extends AggregateInput> extends SqlFn<ExprColumns<TExp
|
|
|
211
225
|
private readonly expr;
|
|
212
226
|
readonly isAggregate = true;
|
|
213
227
|
constructor(expr: TExpr);
|
|
228
|
+
toDriverValue(value: TExpr["$"]["TsType"] | null): unknown;
|
|
229
|
+
toSQLValue(value: TExpr["$"]["TsType"] | null): string;
|
|
214
230
|
/**
|
|
215
|
-
* Delegates to the inner expression's own
|
|
231
|
+
* Delegates to the inner expression's own conversion so that the result
|
|
216
232
|
* is deserialized to the same TypeScript type as the wrapped column/function.
|
|
217
233
|
*/
|
|
218
|
-
|
|
234
|
+
fromDriverValue(value: unknown): TExpr["$"]["TsType"] | null;
|
|
219
235
|
/** Appends `max(expr)` to the query SQL. */
|
|
220
236
|
toQuery(query: Query, ctx?: QueryContext): void;
|
|
221
237
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { SqlFn } from "./index.mjs";
|
|
2
|
+
import { isCol } from "../entity.mjs";
|
|
2
3
|
//#region src/functions/aggregate.ts
|
|
3
4
|
/**
|
|
4
5
|
* SQL aggregate expression: `count(col)`
|
|
@@ -17,6 +18,15 @@ var CountFn = class extends SqlFn {
|
|
|
17
18
|
super();
|
|
18
19
|
this.expr = expr;
|
|
19
20
|
}
|
|
21
|
+
toDriverValue(value) {
|
|
22
|
+
return value;
|
|
23
|
+
}
|
|
24
|
+
toSQLValue(value) {
|
|
25
|
+
return SqlFn._numericToSQL(value);
|
|
26
|
+
}
|
|
27
|
+
fromDriverValue(value) {
|
|
28
|
+
return SqlFn._numericFromDriver(value);
|
|
29
|
+
}
|
|
20
30
|
/** Appends `count(expr)` to the query SQL. */
|
|
21
31
|
toQuery(query, ctx) {
|
|
22
32
|
query.sql += "count(";
|
|
@@ -35,6 +45,15 @@ var CountFn = class extends SqlFn {
|
|
|
35
45
|
*/
|
|
36
46
|
var CountStarFn = class extends SqlFn {
|
|
37
47
|
isAggregate = true;
|
|
48
|
+
toDriverValue(value) {
|
|
49
|
+
return value;
|
|
50
|
+
}
|
|
51
|
+
toSQLValue(value) {
|
|
52
|
+
return SqlFn._numericToSQL(value);
|
|
53
|
+
}
|
|
54
|
+
fromDriverValue(value) {
|
|
55
|
+
return SqlFn._numericFromDriver(value);
|
|
56
|
+
}
|
|
38
57
|
/** Appends `count(*)` to the query SQL. */
|
|
39
58
|
toQuery(query, _ctx) {
|
|
40
59
|
query.sql += "count(*)";
|
|
@@ -55,6 +74,15 @@ var CountDistinctFn = class extends SqlFn {
|
|
|
55
74
|
super();
|
|
56
75
|
this.expr = expr;
|
|
57
76
|
}
|
|
77
|
+
toDriverValue(value) {
|
|
78
|
+
return value;
|
|
79
|
+
}
|
|
80
|
+
toSQLValue(value) {
|
|
81
|
+
return SqlFn._numericToSQL(value);
|
|
82
|
+
}
|
|
83
|
+
fromDriverValue(value) {
|
|
84
|
+
return SqlFn._numericFromDriver(value);
|
|
85
|
+
}
|
|
58
86
|
/** Appends `count(DISTINCT expr)` to the query SQL. */
|
|
59
87
|
toQuery(query, ctx) {
|
|
60
88
|
query.sql += "count(DISTINCT ";
|
|
@@ -96,6 +124,17 @@ var SumFn = class extends SqlFn {
|
|
|
96
124
|
super();
|
|
97
125
|
this.expr = expr;
|
|
98
126
|
}
|
|
127
|
+
toDriverValue(value) {
|
|
128
|
+
return value;
|
|
129
|
+
}
|
|
130
|
+
toSQLValue(value) {
|
|
131
|
+
return SqlFn._numericToSQL(value);
|
|
132
|
+
}
|
|
133
|
+
fromDriverValue(value) {
|
|
134
|
+
if (value === null) return null;
|
|
135
|
+
if (typeof value === "bigint") return value;
|
|
136
|
+
return Number(value);
|
|
137
|
+
}
|
|
99
138
|
/** Appends `sum(expr)` to the query SQL. */
|
|
100
139
|
toQuery(query, ctx) {
|
|
101
140
|
query.sql += "sum(";
|
|
@@ -133,12 +172,16 @@ var AvgFn = class extends SqlFn {
|
|
|
133
172
|
super();
|
|
134
173
|
this.expr = expr;
|
|
135
174
|
}
|
|
175
|
+
toDriverValue(value) {
|
|
176
|
+
return value;
|
|
177
|
+
}
|
|
178
|
+
toSQLValue(value) {
|
|
179
|
+
return SqlFn._stringToSQL(value);
|
|
180
|
+
}
|
|
136
181
|
/**
|
|
137
182
|
* Preserves the raw PostgreSQL `numeric` string (e.g. `"2.5000000000"`).
|
|
138
|
-
* The default `SqlFn.fromDriver` would coerce numeric strings to `number`,
|
|
139
|
-
* which contradicts the declared `string | null` return type.
|
|
140
183
|
*/
|
|
141
|
-
|
|
184
|
+
fromDriverValue(value) {
|
|
142
185
|
if (value === null) return null;
|
|
143
186
|
return value;
|
|
144
187
|
}
|
|
@@ -180,13 +223,21 @@ var MinFn = class extends SqlFn {
|
|
|
180
223
|
super();
|
|
181
224
|
this.expr = expr;
|
|
182
225
|
}
|
|
226
|
+
toDriverValue(value) {
|
|
227
|
+
return value;
|
|
228
|
+
}
|
|
229
|
+
toSQLValue(value) {
|
|
230
|
+
if (isCol(this.expr)) return this.expr.toSQLScalar(value);
|
|
231
|
+
return this.expr.toSQLValue(value);
|
|
232
|
+
}
|
|
183
233
|
/**
|
|
184
|
-
* Delegates to the inner expression's own
|
|
234
|
+
* Delegates to the inner expression's own conversion so that the result
|
|
185
235
|
* is deserialized to the same TypeScript type as the wrapped column/function.
|
|
186
236
|
*/
|
|
187
|
-
|
|
237
|
+
fromDriverValue(value) {
|
|
188
238
|
if (value === null) return null;
|
|
189
|
-
return this.expr.
|
|
239
|
+
if (isCol(this.expr)) return this.expr.fromDriverScalar(value);
|
|
240
|
+
return this.expr.fromDriverValue(value);
|
|
190
241
|
}
|
|
191
242
|
/** Appends `min(expr)` to the query SQL. */
|
|
192
243
|
toQuery(query, ctx) {
|
|
@@ -226,13 +277,21 @@ var MaxFn = class extends SqlFn {
|
|
|
226
277
|
super();
|
|
227
278
|
this.expr = expr;
|
|
228
279
|
}
|
|
280
|
+
toDriverValue(value) {
|
|
281
|
+
return value;
|
|
282
|
+
}
|
|
283
|
+
toSQLValue(value) {
|
|
284
|
+
if (isCol(this.expr)) return this.expr.toSQLScalar(value);
|
|
285
|
+
return this.expr.toSQLValue(value);
|
|
286
|
+
}
|
|
229
287
|
/**
|
|
230
|
-
* Delegates to the inner expression's own
|
|
288
|
+
* Delegates to the inner expression's own conversion so that the result
|
|
231
289
|
* is deserialized to the same TypeScript type as the wrapped column/function.
|
|
232
290
|
*/
|
|
233
|
-
|
|
291
|
+
fromDriverValue(value) {
|
|
234
292
|
if (value === null) return null;
|
|
235
|
-
return this.expr.
|
|
293
|
+
if (isCol(this.expr)) return this.expr.fromDriverScalar(value);
|
|
294
|
+
return this.expr.fromDriverValue(value);
|
|
236
295
|
}
|
|
237
296
|
/** Appends `max(expr)` to the query SQL. */
|
|
238
297
|
toQuery(query, ctx) {
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { Or } from "../types.mjs";
|
|
2
|
+
import { AnySqlFn, ExprColumns, HasArg, SqlFn } from "./index.mjs";
|
|
3
|
+
import { AnyScalarColumn } from "../table.mjs";
|
|
4
|
+
import { Arg, IsArg } from "../query-builders/pre.mjs";
|
|
5
|
+
import { Query, QueryContext } from "../query-builders/query.mjs";
|
|
6
|
+
|
|
7
|
+
//#region src/functions/arithmetic.d.ts
|
|
8
|
+
/**
|
|
9
|
+
* Union of every valid operand for arithmetic operators:
|
|
10
|
+
* a numeric column or SqlFn, a plain number literal, or an `Arg<number>`.
|
|
11
|
+
*/
|
|
12
|
+
type NumericOperand = ((AnyScalarColumn | AnySqlFn) & {
|
|
13
|
+
$: {
|
|
14
|
+
PgType: "numeric";
|
|
15
|
+
};
|
|
16
|
+
}) | number | Arg<number>;
|
|
17
|
+
/**
|
|
18
|
+
* Computes the `THasArg` slot for a two-operand arithmetic expression.
|
|
19
|
+
* Resolves to `true` if either operand embeds an `Arg` or is itself an `Arg`.
|
|
20
|
+
*/
|
|
21
|
+
type BinaryOpHasArg<TLeft extends NumericOperand, TRight extends NumericOperand> = Or<Or<HasArg<TLeft>, IsArg<TLeft>>, Or<HasArg<TRight>, IsArg<TRight>>>;
|
|
22
|
+
declare class AddFn<TLeft extends NumericOperand, TRight extends NumericOperand> extends SqlFn<ExprColumns<TLeft> | ExprColumns<TRight>, BinaryOpHasArg<TLeft, TRight>, "scalar", "numeric", number> {
|
|
23
|
+
private readonly left;
|
|
24
|
+
private readonly right;
|
|
25
|
+
constructor(left: TLeft, right: TRight);
|
|
26
|
+
toDriverValue(value: number | null): unknown;
|
|
27
|
+
toSQLValue(value: number | null): string;
|
|
28
|
+
fromDriverValue(value: unknown): number | null;
|
|
29
|
+
toQuery(query: Query, ctx?: QueryContext): void;
|
|
30
|
+
}
|
|
31
|
+
/** Returns the sum of two numeric expressions. */
|
|
32
|
+
declare function add<TLeft extends NumericOperand, TRight extends NumericOperand>(left: TLeft, right: TRight): AddFn<TLeft, TRight>;
|
|
33
|
+
declare class SubFn<TLeft extends NumericOperand, TRight extends NumericOperand> extends SqlFn<ExprColumns<TLeft> | ExprColumns<TRight>, BinaryOpHasArg<TLeft, TRight>, "scalar", "numeric", number> {
|
|
34
|
+
private readonly left;
|
|
35
|
+
private readonly right;
|
|
36
|
+
constructor(left: TLeft, right: TRight);
|
|
37
|
+
toDriverValue(value: number | null): unknown;
|
|
38
|
+
toSQLValue(value: number | null): string;
|
|
39
|
+
fromDriverValue(value: unknown): number | null;
|
|
40
|
+
toQuery(query: Query, ctx?: QueryContext): void;
|
|
41
|
+
}
|
|
42
|
+
/** Returns the difference of two numeric expressions. */
|
|
43
|
+
declare function sub<TLeft extends NumericOperand, TRight extends NumericOperand>(left: TLeft, right: TRight): SubFn<TLeft, TRight>;
|
|
44
|
+
declare class MulFn<TLeft extends NumericOperand, TRight extends NumericOperand> extends SqlFn<ExprColumns<TLeft> | ExprColumns<TRight>, BinaryOpHasArg<TLeft, TRight>, "scalar", "numeric", number> {
|
|
45
|
+
private readonly left;
|
|
46
|
+
private readonly right;
|
|
47
|
+
constructor(left: TLeft, right: TRight);
|
|
48
|
+
toDriverValue(value: number | null): unknown;
|
|
49
|
+
toSQLValue(value: number | null): string;
|
|
50
|
+
fromDriverValue(value: unknown): number | null;
|
|
51
|
+
toQuery(query: Query, ctx?: QueryContext): void;
|
|
52
|
+
}
|
|
53
|
+
/** Returns the product of two numeric expressions. */
|
|
54
|
+
declare function mul<TLeft extends NumericOperand, TRight extends NumericOperand>(left: TLeft, right: TRight): MulFn<TLeft, TRight>;
|
|
55
|
+
declare class DivFn<TLeft extends NumericOperand, TRight extends NumericOperand> extends SqlFn<ExprColumns<TLeft> | ExprColumns<TRight>, BinaryOpHasArg<TLeft, TRight>, "scalar", "numeric", number> {
|
|
56
|
+
private readonly left;
|
|
57
|
+
private readonly right;
|
|
58
|
+
constructor(left: TLeft, right: TRight);
|
|
59
|
+
toDriverValue(value: number | null): unknown;
|
|
60
|
+
toSQLValue(value: number | null): string;
|
|
61
|
+
fromDriverValue(value: unknown): number | null;
|
|
62
|
+
toQuery(query: Query, ctx?: QueryContext): void;
|
|
63
|
+
}
|
|
64
|
+
/** Returns the quotient of two numeric expressions. */
|
|
65
|
+
declare function div<TLeft extends NumericOperand, TRight extends NumericOperand>(left: TLeft, right: TRight): DivFn<TLeft, TRight>;
|
|
66
|
+
//#endregion
|
|
67
|
+
export { add, div, mul, sub };
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { SqlFn } from "./index.mjs";
|
|
2
|
+
import { Arg } from "../query-builders/pre.mjs";
|
|
3
|
+
import { is } from "../entity.mjs";
|
|
4
|
+
//#region src/functions/arithmetic.ts
|
|
5
|
+
/**
|
|
6
|
+
* Appends a single numeric operand fragment to the query.
|
|
7
|
+
* Handles `Arg<number>`, literal `number`, and column/SqlFn operands.
|
|
8
|
+
*/
|
|
9
|
+
function numericExprToQuery(query, ctx, operand) {
|
|
10
|
+
if (is(operand, Arg)) query.addArg(operand);
|
|
11
|
+
else if (typeof operand === "number") query.sql += operand.toString();
|
|
12
|
+
else operand.toQuery(query, ctx);
|
|
13
|
+
}
|
|
14
|
+
var AddFn = class extends SqlFn {
|
|
15
|
+
constructor(left, right) {
|
|
16
|
+
super();
|
|
17
|
+
this.left = left;
|
|
18
|
+
this.right = right;
|
|
19
|
+
}
|
|
20
|
+
toDriverValue(value) {
|
|
21
|
+
return value;
|
|
22
|
+
}
|
|
23
|
+
toSQLValue(value) {
|
|
24
|
+
return SqlFn._numericToSQL(value);
|
|
25
|
+
}
|
|
26
|
+
fromDriverValue(value) {
|
|
27
|
+
return SqlFn._numericFromDriver(value);
|
|
28
|
+
}
|
|
29
|
+
toQuery(query, ctx) {
|
|
30
|
+
query.sql += "(";
|
|
31
|
+
numericExprToQuery(query, ctx, this.left);
|
|
32
|
+
query.sql += " + ";
|
|
33
|
+
numericExprToQuery(query, ctx, this.right);
|
|
34
|
+
query.sql += ")";
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
/** Returns the sum of two numeric expressions. */
|
|
38
|
+
function add(left, right) {
|
|
39
|
+
return new AddFn(left, right);
|
|
40
|
+
}
|
|
41
|
+
var SubFn = class extends SqlFn {
|
|
42
|
+
constructor(left, right) {
|
|
43
|
+
super();
|
|
44
|
+
this.left = left;
|
|
45
|
+
this.right = right;
|
|
46
|
+
}
|
|
47
|
+
toDriverValue(value) {
|
|
48
|
+
return value;
|
|
49
|
+
}
|
|
50
|
+
toSQLValue(value) {
|
|
51
|
+
return SqlFn._numericToSQL(value);
|
|
52
|
+
}
|
|
53
|
+
fromDriverValue(value) {
|
|
54
|
+
return SqlFn._numericFromDriver(value);
|
|
55
|
+
}
|
|
56
|
+
toQuery(query, ctx) {
|
|
57
|
+
query.sql += "(";
|
|
58
|
+
numericExprToQuery(query, ctx, this.left);
|
|
59
|
+
query.sql += " - ";
|
|
60
|
+
numericExprToQuery(query, ctx, this.right);
|
|
61
|
+
query.sql += ")";
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
/** Returns the difference of two numeric expressions. */
|
|
65
|
+
function sub(left, right) {
|
|
66
|
+
return new SubFn(left, right);
|
|
67
|
+
}
|
|
68
|
+
var MulFn = class extends SqlFn {
|
|
69
|
+
constructor(left, right) {
|
|
70
|
+
super();
|
|
71
|
+
this.left = left;
|
|
72
|
+
this.right = right;
|
|
73
|
+
}
|
|
74
|
+
toDriverValue(value) {
|
|
75
|
+
return value;
|
|
76
|
+
}
|
|
77
|
+
toSQLValue(value) {
|
|
78
|
+
return SqlFn._numericToSQL(value);
|
|
79
|
+
}
|
|
80
|
+
fromDriverValue(value) {
|
|
81
|
+
return SqlFn._numericFromDriver(value);
|
|
82
|
+
}
|
|
83
|
+
toQuery(query, ctx) {
|
|
84
|
+
query.sql += "(";
|
|
85
|
+
numericExprToQuery(query, ctx, this.left);
|
|
86
|
+
query.sql += " * ";
|
|
87
|
+
numericExprToQuery(query, ctx, this.right);
|
|
88
|
+
query.sql += ")";
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
/** Returns the product of two numeric expressions. */
|
|
92
|
+
function mul(left, right) {
|
|
93
|
+
return new MulFn(left, right);
|
|
94
|
+
}
|
|
95
|
+
var DivFn = class extends SqlFn {
|
|
96
|
+
constructor(left, right) {
|
|
97
|
+
super();
|
|
98
|
+
this.left = left;
|
|
99
|
+
this.right = right;
|
|
100
|
+
}
|
|
101
|
+
toDriverValue(value) {
|
|
102
|
+
return value;
|
|
103
|
+
}
|
|
104
|
+
toSQLValue(value) {
|
|
105
|
+
return SqlFn._numericToSQL(value);
|
|
106
|
+
}
|
|
107
|
+
fromDriverValue(value) {
|
|
108
|
+
return SqlFn._numericFromDriver(value);
|
|
109
|
+
}
|
|
110
|
+
toQuery(query, ctx) {
|
|
111
|
+
query.sql += "(";
|
|
112
|
+
numericExprToQuery(query, ctx, this.left);
|
|
113
|
+
query.sql += " / ";
|
|
114
|
+
numericExprToQuery(query, ctx, this.right);
|
|
115
|
+
query.sql += ")";
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
/** Returns the quotient of two numeric expressions. */
|
|
119
|
+
function div(left, right) {
|
|
120
|
+
return new DivFn(left, right);
|
|
121
|
+
}
|
|
122
|
+
//#endregion
|
|
123
|
+
export { add, div, mul, sub };
|
|
@@ -7,14 +7,10 @@ import { Sql } from "../sql.mjs";
|
|
|
7
7
|
* Abstract base class for typed SQL functions.
|
|
8
8
|
*
|
|
9
9
|
* Analogous to `Filter` but for expressions that produce a **value** rather
|
|
10
|
-
* than a boolean predicate.
|
|
11
|
-
* - `.select({ alias: sqlFn })` — adds a computed column to the result
|
|
12
|
-
* - `.orderBy(asc(sqlFn))` — orders by a computed expression
|
|
13
|
-
* - `.where(lt(sqlFn, value))` — compares the expression in a WHERE clause
|
|
10
|
+
* than a boolean predicate.
|
|
14
11
|
*
|
|
15
12
|
* @template TColumn - The scoped table column(s) this expression references.
|
|
16
13
|
* @template THasArg - `true` when this expression embeds at least one `Arg` placeholder.
|
|
17
|
-
* Set to `true` in concrete subclasses that accept `Arg` values; defaults to `false`.
|
|
18
14
|
* Arg-bearing expressions are only accepted in prepared queries (`db.prepare()`).
|
|
19
15
|
* @template TFnType - `"aggregate"` for aggregate functions (e.g. `count`, `sum`),
|
|
20
16
|
* `"scalar"` for scalar functions (e.g. `lower`, `abs`). Defaults to the union.
|
|
@@ -46,19 +42,20 @@ declare abstract class SqlFn<TColumn extends AnyColumn, THasArg extends boolean
|
|
|
46
42
|
/** Appends the SQL fragment for this expression to the query (no trailing semicolon). */
|
|
47
43
|
abstract toQuery(query: Query, ctx?: QueryContext): void;
|
|
48
44
|
toSQL(): string;
|
|
49
|
-
/**
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
45
|
+
/** Converts a TypeScript value to a raw driver value (write path). */
|
|
46
|
+
abstract toDriverValue(value: TTsType | null): unknown;
|
|
47
|
+
/** Converts a TypeScript value to a SQL literal string. */
|
|
48
|
+
abstract toSQLValue(value: TTsType | null): string;
|
|
49
|
+
/** Converts a raw PostgreSQL driver value to the TypeScript type `TTsType`. */
|
|
50
|
+
abstract fromDriverValue(value: unknown): TTsType | null;
|
|
51
|
+
/** Default implementation for numeric-returning functions. */
|
|
52
|
+
protected static _numericFromDriver(value: unknown): number | null;
|
|
53
|
+
/** Default implementation for string-returning functions. */
|
|
54
|
+
protected static _stringFromDriver(value: unknown): string | null;
|
|
55
|
+
/** Default SQL literal for a numeric value. */
|
|
56
|
+
protected static _numericToSQL(value: number | bigint | null): string;
|
|
57
|
+
/** Default SQL literal for a string value. */
|
|
58
|
+
protected static _stringToSQL(value: string | null): string;
|
|
62
59
|
}
|
|
63
60
|
type AnySqlFn = SqlFn<any, any, any, any, any>;
|
|
64
61
|
type AnyScalarSqlFn = SqlFn<any, any, "scalar", any, any>;
|