sumak 0.0.7 → 0.0.9
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/README.md +302 -126
- package/dist/builder/eb.d.mts +0 -1
- package/dist/builder/eb.mjs +1 -5
- package/dist/builder/typed-delete.d.mts +2 -0
- package/dist/builder/typed-delete.mjs +15 -2
- package/dist/builder/typed-insert.d.mts +3 -6
- package/dist/builder/typed-insert.mjs +34 -29
- package/dist/builder/typed-merge.d.mts +1 -2
- package/dist/builder/typed-merge.mjs +9 -22
- package/dist/builder/typed-select.d.mts +24 -2
- package/dist/builder/typed-select.mjs +107 -52
- package/dist/builder/typed-update.d.mts +3 -2
- package/dist/builder/typed-update.mjs +26 -18
- package/dist/index.d.mts +6 -1
- package/dist/index.mjs +6 -1
- package/dist/plugin/audit-timestamp.d.mts +31 -0
- package/dist/plugin/audit-timestamp.mjs +54 -0
- package/dist/plugin/data-masking.d.mts +31 -0
- package/dist/plugin/data-masking.mjs +49 -0
- package/dist/plugin/multi-tenant.d.mts +37 -0
- package/dist/plugin/multi-tenant.mjs +66 -0
- package/dist/plugin/optimistic-lock.d.mts +38 -0
- package/dist/plugin/optimistic-lock.mjs +35 -0
- package/dist/plugin/query-limit.d.mts +20 -0
- package/dist/plugin/query-limit.mjs +23 -0
- package/dist/plugin/soft-delete.d.mts +13 -4
- package/dist/plugin/soft-delete.mjs +21 -4
- package/dist/sumak.d.mts +6 -0
- package/dist/sumak.mjs +24 -4
- package/package.json +1 -1
package/dist/builder/eb.d.mts
CHANGED
package/dist/builder/eb.mjs
CHANGED
|
@@ -209,12 +209,8 @@ export class Col {
|
|
|
209
209
|
}
|
|
210
210
|
}
|
|
211
211
|
|
|
212
|
-
let _paramIdx = 0;
|
|
213
|
-
export function resetParams() {
|
|
214
|
-
_paramIdx = 0;
|
|
215
|
-
}
|
|
216
212
|
function autoParam(value) {
|
|
217
|
-
return rawParam(
|
|
213
|
+
return rawParam(0, value);
|
|
218
214
|
}
|
|
219
215
|
function binOp(op, left, right) {
|
|
220
216
|
return {
|
|
@@ -37,6 +37,8 @@ export declare class TypedDeleteBuilder<
|
|
|
37
37
|
$if(condition: boolean, fn: (qb: TypedDeleteBuilder<DB, TB>) => TypedDeleteBuilder<DB, TB>): TypedDeleteBuilder<DB, TB>;
|
|
38
38
|
build(): DeleteNode;
|
|
39
39
|
compile(printer: Printer): CompiledQuery;
|
|
40
|
+
/** Compile to SQL using the dialect's printer. */
|
|
41
|
+
toSQL(): CompiledQuery;
|
|
40
42
|
/** EXPLAIN this query. */
|
|
41
43
|
explain(options?: {
|
|
42
44
|
analyze?: boolean;
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import { star } from "../ast/expression.mjs";
|
|
2
2
|
import { unwrap } from "../ast/typed-expression.mjs";
|
|
3
3
|
import { DeleteBuilder } from "./delete.mjs";
|
|
4
|
-
import { createColumnProxies
|
|
4
|
+
import { createColumnProxies } from "./eb.mjs";
|
|
5
5
|
|
|
6
6
|
export class TypedDeleteBuilder {
|
|
7
7
|
|
|
8
8
|
_builder;
|
|
9
|
+
|
|
10
|
+
_printer;
|
|
11
|
+
|
|
12
|
+
_compile;
|
|
9
13
|
constructor(table) {
|
|
10
14
|
this._builder = new DeleteBuilder().from(table);
|
|
11
15
|
}
|
|
@@ -13,12 +17,13 @@ export class TypedDeleteBuilder {
|
|
|
13
17
|
_with(builder) {
|
|
14
18
|
const t = new TypedDeleteBuilder("");
|
|
15
19
|
t._builder = builder;
|
|
20
|
+
t._printer = this._printer;
|
|
21
|
+
t._compile = this._compile;
|
|
16
22
|
return t;
|
|
17
23
|
}
|
|
18
24
|
|
|
19
25
|
where(exprOrCallback) {
|
|
20
26
|
if (typeof exprOrCallback === "function") {
|
|
21
|
-
resetParams();
|
|
22
27
|
const table = this._builder.build().table.name;
|
|
23
28
|
const cols = createColumnProxies(table);
|
|
24
29
|
const result = exprOrCallback(cols);
|
|
@@ -74,6 +79,14 @@ export class TypedDeleteBuilder {
|
|
|
74
79
|
return printer.print(this.build());
|
|
75
80
|
}
|
|
76
81
|
|
|
82
|
+
toSQL() {
|
|
83
|
+
if (this._compile) return this._compile(this.build());
|
|
84
|
+
if (!this._printer) {
|
|
85
|
+
throw new Error("toSQL() requires a printer. Use db.deleteFrom() or pass a printer to compile().");
|
|
86
|
+
}
|
|
87
|
+
return this._printer.print(this.build());
|
|
88
|
+
}
|
|
89
|
+
|
|
77
90
|
explain(options) {
|
|
78
91
|
const node = this.build();
|
|
79
92
|
const explainNode = {
|
|
@@ -11,8 +11,7 @@ export declare class TypedInsertBuilder<
|
|
|
11
11
|
DB,
|
|
12
12
|
TB extends keyof DB
|
|
13
13
|
> {
|
|
14
|
-
|
|
15
|
-
constructor(table: TB & string, paramIdx?: number);
|
|
14
|
+
constructor(table: TB & string);
|
|
16
15
|
/**
|
|
17
16
|
* Insert a single row. Columns/values inferred from Insertable<DB[TB]>.
|
|
18
17
|
*/
|
|
@@ -46,10 +45,6 @@ export declare class TypedInsertBuilder<
|
|
|
46
45
|
}[]): TypedInsertBuilder<DB, TB>;
|
|
47
46
|
/**
|
|
48
47
|
* ON CONFLICT DO UPDATE — with plain object (auto-parameterized).
|
|
49
|
-
*
|
|
50
|
-
* ```ts
|
|
51
|
-
* .onConflictDoUpdateSet(["email"], { name: "Alice Updated" })
|
|
52
|
-
* ```
|
|
53
48
|
*/
|
|
54
49
|
onConflictDoUpdateSet(columns: (keyof DB[TB] & string)[], values: Partial<Insertable<DB[TB]>>): TypedInsertBuilder<DB, TB>;
|
|
55
50
|
/** ON CONFLICT ON CONSTRAINT name DO NOTHING */
|
|
@@ -78,6 +73,8 @@ export declare class TypedInsertBuilder<
|
|
|
78
73
|
$if(condition: boolean, fn: (qb: TypedInsertBuilder<DB, TB>) => TypedInsertBuilder<DB, TB>): TypedInsertBuilder<DB, TB>;
|
|
79
74
|
build(): InsertNode;
|
|
80
75
|
compile(printer: Printer): CompiledQuery;
|
|
76
|
+
/** Compile to SQL using the full pipeline. */
|
|
77
|
+
toSQL(): CompiledQuery;
|
|
81
78
|
/** EXPLAIN this query. */
|
|
82
79
|
explain(options?: {
|
|
83
80
|
analyze?: boolean;
|
|
@@ -6,27 +6,26 @@ import { InsertBuilder } from "./insert.mjs";
|
|
|
6
6
|
export class TypedInsertBuilder {
|
|
7
7
|
|
|
8
8
|
_builder;
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
|
|
10
|
+
_printer;
|
|
11
|
+
|
|
12
|
+
_compile;
|
|
13
|
+
constructor(table) {
|
|
11
14
|
this._builder = new InsertBuilder().into(table);
|
|
12
|
-
this._paramIdx = paramIdx;
|
|
13
15
|
}
|
|
14
16
|
|
|
15
|
-
_withBuilder(builder
|
|
17
|
+
_withBuilder(builder) {
|
|
16
18
|
const t = new TypedInsertBuilder("");
|
|
17
19
|
t._builder = builder;
|
|
18
|
-
t.
|
|
20
|
+
t._printer = this._printer;
|
|
21
|
+
t._compile = this._compile;
|
|
19
22
|
return t;
|
|
20
23
|
}
|
|
21
24
|
|
|
22
25
|
values(row) {
|
|
23
26
|
const entries = Object.entries(row);
|
|
24
27
|
const cols = entries.map(([k]) => k);
|
|
25
|
-
const vals = entries.map(([_, v]) =>
|
|
26
|
-
const p = param(this._paramIdx, v);
|
|
27
|
-
this._paramIdx++;
|
|
28
|
-
return p;
|
|
29
|
-
});
|
|
28
|
+
const vals = entries.map(([_, v]) => param(0, v));
|
|
30
29
|
let builder = this._builder;
|
|
31
30
|
|
|
32
31
|
if (builder.build().columns.length === 0) {
|
|
@@ -35,8 +34,8 @@ export class TypedInsertBuilder {
|
|
|
35
34
|
builder = new InsertBuilder({
|
|
36
35
|
...builder.build(),
|
|
37
36
|
values: [...builder.build().values, vals]
|
|
38
|
-
}
|
|
39
|
-
return this._withBuilder(builder
|
|
37
|
+
});
|
|
38
|
+
return this._withBuilder(builder);
|
|
40
39
|
}
|
|
41
40
|
|
|
42
41
|
valuesMany(rows) {
|
|
@@ -55,7 +54,7 @@ export class TypedInsertBuilder {
|
|
|
55
54
|
const builder = new InsertBuilder({
|
|
56
55
|
...this._builder.build(),
|
|
57
56
|
returning: exprs
|
|
58
|
-
}
|
|
57
|
+
});
|
|
59
58
|
return new TypedInsertReturningBuilder(builder);
|
|
60
59
|
}
|
|
61
60
|
|
|
@@ -69,7 +68,7 @@ export class TypedInsertBuilder {
|
|
|
69
68
|
const builder = new InsertBuilder({
|
|
70
69
|
...this._builder.build(),
|
|
71
70
|
returning: [...this._builder.build().returning, aliased]
|
|
72
|
-
}
|
|
71
|
+
});
|
|
73
72
|
return new TypedInsertReturningBuilder(builder);
|
|
74
73
|
}
|
|
75
74
|
|
|
@@ -77,72 +76,70 @@ export class TypedInsertBuilder {
|
|
|
77
76
|
const builder = new InsertBuilder({
|
|
78
77
|
...this._builder.build(),
|
|
79
78
|
returning: [star()]
|
|
80
|
-
}
|
|
79
|
+
});
|
|
81
80
|
return new TypedInsertReturningBuilder(builder);
|
|
82
81
|
}
|
|
83
82
|
|
|
84
83
|
onConflictDoNothing(...columns) {
|
|
85
|
-
return this._withBuilder(this._builder.onConflictDoNothing(...columns)
|
|
84
|
+
return this._withBuilder(this._builder.onConflictDoNothing(...columns));
|
|
86
85
|
}
|
|
87
86
|
|
|
88
87
|
onConflictDoUpdate(columns, set) {
|
|
89
88
|
return this._withBuilder(this._builder.onConflictDoUpdate(columns, set.map((s) => ({
|
|
90
89
|
column: s.column,
|
|
91
90
|
value: unwrap(s.value)
|
|
92
|
-
})))
|
|
91
|
+
}))));
|
|
93
92
|
}
|
|
94
93
|
|
|
95
94
|
onConflictDoUpdateSet(columns, values) {
|
|
96
95
|
const set = [];
|
|
97
|
-
let idx = this._paramIdx;
|
|
98
96
|
for (const [col, val] of Object.entries(values)) {
|
|
99
97
|
if (val !== undefined) {
|
|
100
98
|
set.push({
|
|
101
99
|
column: col,
|
|
102
|
-
value: param(
|
|
100
|
+
value: param(0, val)
|
|
103
101
|
});
|
|
104
|
-
idx++;
|
|
105
102
|
}
|
|
106
103
|
}
|
|
107
|
-
return this._withBuilder(this._builder.onConflictDoUpdate(columns, set)
|
|
104
|
+
return this._withBuilder(this._builder.onConflictDoUpdate(columns, set));
|
|
108
105
|
}
|
|
109
106
|
|
|
110
107
|
onConflictConstraintDoNothing(constraint) {
|
|
111
|
-
return this._withBuilder(this._builder.onConflictConstraintDoNothing(constraint)
|
|
108
|
+
return this._withBuilder(this._builder.onConflictConstraintDoNothing(constraint));
|
|
112
109
|
}
|
|
113
110
|
|
|
114
111
|
onConflictConstraintDoUpdate(constraint, set) {
|
|
115
112
|
return this._withBuilder(this._builder.onConflictConstraintDoUpdate(constraint, set.map((s) => ({
|
|
116
113
|
column: s.column,
|
|
117
114
|
value: unwrap(s.value)
|
|
118
|
-
})))
|
|
115
|
+
}))));
|
|
119
116
|
}
|
|
120
117
|
|
|
121
118
|
orIgnore() {
|
|
122
|
-
return this._withBuilder(this._builder.orIgnore()
|
|
119
|
+
return this._withBuilder(this._builder.orIgnore());
|
|
123
120
|
}
|
|
124
121
|
|
|
125
122
|
orReplace() {
|
|
126
|
-
return this._withBuilder(this._builder.orReplace()
|
|
123
|
+
return this._withBuilder(this._builder.orReplace());
|
|
127
124
|
}
|
|
128
125
|
|
|
129
126
|
onDuplicateKeyUpdate(set) {
|
|
130
127
|
return this._withBuilder(this._builder.onDuplicateKeyUpdate(set.map((s) => ({
|
|
131
128
|
column: s.column,
|
|
132
129
|
value: unwrap(s.value)
|
|
133
|
-
})))
|
|
130
|
+
}))));
|
|
134
131
|
}
|
|
135
132
|
|
|
136
133
|
fromSelect(query) {
|
|
137
|
-
return this._withBuilder(this._builder.fromSelect(query)
|
|
134
|
+
return this._withBuilder(this._builder.fromSelect(query));
|
|
138
135
|
}
|
|
139
136
|
|
|
140
137
|
defaultValues() {
|
|
141
|
-
return this._withBuilder(this._builder.defaultValues()
|
|
138
|
+
return this._withBuilder(this._builder.defaultValues());
|
|
142
139
|
}
|
|
143
140
|
|
|
144
141
|
with(name, query, recursive = false) {
|
|
145
|
-
return this._withBuilder(this._builder.with(name, query, recursive)
|
|
142
|
+
return this._withBuilder(this._builder.with(name, query, recursive));
|
|
146
143
|
}
|
|
147
144
|
|
|
148
145
|
$if(condition, fn) {
|
|
@@ -158,6 +155,14 @@ export class TypedInsertBuilder {
|
|
|
158
155
|
return printer.print(this.build());
|
|
159
156
|
}
|
|
160
157
|
|
|
158
|
+
toSQL() {
|
|
159
|
+
if (this._compile) return this._compile(this.build());
|
|
160
|
+
if (!this._printer) {
|
|
161
|
+
throw new Error("toSQL() requires a printer. Use db.insertInto() or pass a printer to compile().");
|
|
162
|
+
}
|
|
163
|
+
return this._printer.print(this.build());
|
|
164
|
+
}
|
|
165
|
+
|
|
161
166
|
explain(options) {
|
|
162
167
|
const node = this.build();
|
|
163
168
|
const explainNode = {
|
|
@@ -19,8 +19,7 @@ export declare class TypedMergeBuilder<
|
|
|
19
19
|
> {
|
|
20
20
|
private _targetTable;
|
|
21
21
|
private _sourceAlias;
|
|
22
|
-
|
|
23
|
-
constructor(targetTable: Target & string, sourceTable: Source & string, sourceAlias: string, on: Expression<boolean>, paramIdx?: number);
|
|
22
|
+
constructor(targetTable: Target & string, sourceTable: Source & string, sourceAlias: string, on: Expression<boolean>);
|
|
24
23
|
whenMatchedThenUpdate(values: Updateable<DB[Target]>, condition?: (proxies: MergeProxies<DB, Target, Source>) => Expression<boolean>): TypedMergeBuilder<DB, Target, Source>;
|
|
25
24
|
whenMatchedThenDelete(condition?: (proxies: MergeProxies<DB, Target, Source>) => Expression<boolean>): TypedMergeBuilder<DB, Target, Source>;
|
|
26
25
|
whenNotMatchedThenInsert(row: Insertable<DB[Target]>, condition?: (proxies: MergeProxies<DB, Target, Source>) => Expression<boolean>): TypedMergeBuilder<DB, Target, Source>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { param } from "../ast/expression.mjs";
|
|
2
2
|
import { unwrap } from "../ast/typed-expression.mjs";
|
|
3
|
-
import { Col
|
|
3
|
+
import { Col } from "./eb.mjs";
|
|
4
4
|
import { MergeBuilder } from "./merge.mjs";
|
|
5
5
|
function createMergeProxies(targetTable, sourceAlias) {
|
|
6
6
|
const makeProxy = (prefix) => new Proxy({}, { get(_t, colName) {
|
|
@@ -16,15 +16,13 @@ export class TypedMergeBuilder {
|
|
|
16
16
|
_builder;
|
|
17
17
|
_targetTable;
|
|
18
18
|
_sourceAlias;
|
|
19
|
-
|
|
20
|
-
constructor(targetTable, sourceTable, sourceAlias, on, paramIdx = 0) {
|
|
19
|
+
constructor(targetTable, sourceTable, sourceAlias, on) {
|
|
21
20
|
this._targetTable = targetTable;
|
|
22
21
|
this._sourceAlias = sourceAlias;
|
|
23
|
-
this._paramIdx = paramIdx;
|
|
24
22
|
this._builder = new MergeBuilder().into(targetTable).using(sourceTable, sourceAlias).on(unwrap(on));
|
|
25
23
|
}
|
|
26
24
|
|
|
27
|
-
_with(builder
|
|
25
|
+
_with(builder) {
|
|
28
26
|
const t = new TypedMergeBuilder("", "", "", { node: {
|
|
29
27
|
type: "literal",
|
|
30
28
|
value: true
|
|
@@ -32,57 +30,46 @@ export class TypedMergeBuilder {
|
|
|
32
30
|
t._builder = builder;
|
|
33
31
|
t._targetTable = this._targetTable;
|
|
34
32
|
t._sourceAlias = this._sourceAlias;
|
|
35
|
-
t._paramIdx = paramIdx;
|
|
36
33
|
return t;
|
|
37
34
|
}
|
|
38
35
|
whenMatchedThenUpdate(values, condition) {
|
|
39
|
-
let idx = this._paramIdx;
|
|
40
36
|
const set = [];
|
|
41
37
|
for (const [col, val] of Object.entries(values)) {
|
|
42
38
|
if (val !== undefined) {
|
|
43
39
|
set.push({
|
|
44
40
|
column: col,
|
|
45
|
-
value: param(
|
|
41
|
+
value: param(0, val)
|
|
46
42
|
});
|
|
47
|
-
idx++;
|
|
48
43
|
}
|
|
49
44
|
}
|
|
50
45
|
let condExpr;
|
|
51
46
|
if (condition) {
|
|
52
|
-
resetParams();
|
|
53
47
|
const proxies = createMergeProxies(this._targetTable, this._sourceAlias);
|
|
54
48
|
condExpr = unwrap(condition(proxies));
|
|
55
49
|
}
|
|
56
|
-
return this._with(this._builder.whenMatchedUpdate(set, condExpr)
|
|
50
|
+
return this._with(this._builder.whenMatchedUpdate(set, condExpr));
|
|
57
51
|
}
|
|
58
52
|
whenMatchedThenDelete(condition) {
|
|
59
53
|
let condExpr;
|
|
60
54
|
if (condition) {
|
|
61
|
-
resetParams();
|
|
62
55
|
const proxies = createMergeProxies(this._targetTable, this._sourceAlias);
|
|
63
56
|
condExpr = unwrap(condition(proxies));
|
|
64
57
|
}
|
|
65
|
-
return this._with(this._builder.whenMatchedDelete(condExpr)
|
|
58
|
+
return this._with(this._builder.whenMatchedDelete(condExpr));
|
|
66
59
|
}
|
|
67
60
|
whenNotMatchedThenInsert(row, condition) {
|
|
68
|
-
let idx = this._paramIdx;
|
|
69
61
|
const entries = Object.entries(row);
|
|
70
62
|
const columns = entries.map(([k]) => k);
|
|
71
|
-
const values = entries.map(([_, v]) =>
|
|
72
|
-
const p = param(idx, v);
|
|
73
|
-
idx++;
|
|
74
|
-
return p;
|
|
75
|
-
});
|
|
63
|
+
const values = entries.map(([_, v]) => param(0, v));
|
|
76
64
|
let condExpr;
|
|
77
65
|
if (condition) {
|
|
78
|
-
resetParams();
|
|
79
66
|
const proxies = createMergeProxies(this._targetTable, this._sourceAlias);
|
|
80
67
|
condExpr = unwrap(condition(proxies));
|
|
81
68
|
}
|
|
82
|
-
return this._with(this._builder.whenNotMatchedInsert(columns, values, condExpr)
|
|
69
|
+
return this._with(this._builder.whenNotMatchedInsert(columns, values, condExpr));
|
|
83
70
|
}
|
|
84
71
|
with(name, query, recursive = false) {
|
|
85
|
-
return this._with(this._builder.with(name, query, recursive)
|
|
72
|
+
return this._with(this._builder.with(name, query, recursive));
|
|
86
73
|
}
|
|
87
74
|
build() {
|
|
88
75
|
return this._builder.build();
|
|
@@ -18,7 +18,8 @@ export declare class TypedSelectBuilder<
|
|
|
18
18
|
O
|
|
19
19
|
> {
|
|
20
20
|
private _table;
|
|
21
|
-
|
|
21
|
+
private _printer?;
|
|
22
|
+
constructor(builder: SelectBuilder, table?: string, printer?: Printer, compile?: (node: import("../ast/nodes.ts").ASTNode) => CompiledQuery);
|
|
22
23
|
/** Select specific columns. Narrows O. */
|
|
23
24
|
select<K extends keyof O & string>(...cols: K[]): TypedSelectBuilder<DB, TB, Pick<O, K>>;
|
|
24
25
|
/** Select all columns. */
|
|
@@ -164,10 +165,31 @@ export declare class TypedSelectBuilder<
|
|
|
164
165
|
$call<R>(fn: (qb: TypedSelectBuilder<DB, TB, O>) => R): R;
|
|
165
166
|
/** Conditionally apply a transformation. */
|
|
166
167
|
$if<O2>(condition: boolean, fn: (qb: TypedSelectBuilder<DB, TB, O>) => TypedSelectBuilder<DB, TB, O2>): TypedSelectBuilder<DB, TB, O | O2>;
|
|
168
|
+
/**
|
|
169
|
+
* Cursor-based (keyset) pagination.
|
|
170
|
+
*
|
|
171
|
+
* Adds WHERE column > cursor (ASC) or column < cursor (DESC),
|
|
172
|
+
* ORDER BY column, and LIMIT pageSize + 1 (for hasNextPage detection).
|
|
173
|
+
*
|
|
174
|
+
* ```ts
|
|
175
|
+
* db.selectFrom("users")
|
|
176
|
+
* .select("id", "name")
|
|
177
|
+
* .cursorPaginate({ column: "id", after: 42, pageSize: 20 })
|
|
178
|
+
* .toSQL()
|
|
179
|
+
* ```
|
|
180
|
+
*/
|
|
181
|
+
cursorPaginate(options: {
|
|
182
|
+
column: keyof O & string;
|
|
183
|
+
after?: unknown;
|
|
184
|
+
before?: unknown;
|
|
185
|
+
pageSize: number;
|
|
186
|
+
}): TypedSelectBuilder<DB, TB, O>;
|
|
167
187
|
/** Build the AST node. */
|
|
168
188
|
build(): SelectNode;
|
|
169
|
-
/** Compile to SQL. */
|
|
189
|
+
/** Compile to SQL with explicit printer. */
|
|
170
190
|
compile(printer: Printer): CompiledQuery;
|
|
191
|
+
/** Compile to SQL using the dialect's printer. */
|
|
192
|
+
toSQL(): CompiledQuery;
|
|
171
193
|
/** EXPLAIN this query. */
|
|
172
194
|
explain(options?: {
|
|
173
195
|
analyze?: boolean;
|