@stamhoofd/sql 2.45.0 → 2.48.0
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/src/SQLExpressions.d.ts +6 -2
- package/dist/src/SQLExpressions.d.ts.map +1 -1
- package/dist/src/SQLExpressions.js +25 -24
- package/dist/src/SQLExpressions.js.map +1 -1
- package/dist/src/SQLJsonExpressions.d.ts +4 -2
- package/dist/src/SQLJsonExpressions.d.ts.map +1 -1
- package/dist/src/SQLJsonExpressions.js +37 -18
- package/dist/src/SQLJsonExpressions.js.map +1 -1
- package/dist/src/SQLSelect.d.ts +4 -2
- package/dist/src/SQLSelect.d.ts.map +1 -1
- package/dist/src/SQLSelect.js +11 -3
- package/dist/src/SQLSelect.js.map +1 -1
- package/dist/src/filters/SQLFilter.d.ts.map +1 -1
- package/dist/src/filters/SQLFilter.js +10 -10
- package/dist/src/filters/SQLFilter.js.map +1 -1
- package/package.json +2 -2
- package/src/SQLExpressions.ts +91 -95
- package/src/SQLJsonExpressions.ts +80 -59
- package/src/SQLSelect.ts +78 -66
- package/src/filters/SQLFilter.ts +21 -11
package/src/SQLSelect.ts
CHANGED
|
@@ -1,54 +1,57 @@
|
|
|
1
|
-
import { Database, SQLResultNamespacedRow } from
|
|
2
|
-
import { SQLExpression, SQLExpressionOptions, SQLQuery, joinSQLQuery, normalizeSQLQuery } from
|
|
3
|
-
import { SQLAlias, SQLColumnExpression, SQLCount, SQLSelectAs, SQLSum, SQLTableExpression } from
|
|
1
|
+
import { Database, SQLResultNamespacedRow } from '@simonbackx/simple-database';
|
|
2
|
+
import { SQLExpression, SQLExpressionOptions, SQLQuery, joinSQLQuery, normalizeSQLQuery } from './SQLExpression';
|
|
3
|
+
import { SQLAlias, SQLColumnExpression, SQLCount, SQLSelectAs, SQLSum, SQLTableExpression } from './SQLExpressions';
|
|
4
4
|
import { SQLJoin } from './SQLJoin';
|
|
5
|
-
import { Orderable } from
|
|
6
|
-
import { Whereable } from
|
|
5
|
+
import { Orderable } from './SQLOrderBy';
|
|
6
|
+
import { Whereable } from './SQLWhere';
|
|
7
7
|
|
|
8
8
|
class EmptyClass {}
|
|
9
9
|
|
|
10
|
-
export function parseTable(tableOrExpressiongOrNamespace: SQLExpression|string, table?: string): SQLExpression {
|
|
10
|
+
export function parseTable(tableOrExpressiongOrNamespace: SQLExpression | string, table?: string): SQLExpression {
|
|
11
11
|
if (table !== undefined && typeof tableOrExpressiongOrNamespace === 'string') {
|
|
12
|
-
return new SQLTableExpression(tableOrExpressiongOrNamespace, table)
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
return new SQLTableExpression(tableOrExpressiongOrNamespace, table);
|
|
13
|
+
}
|
|
14
|
+
else if (typeof tableOrExpressiongOrNamespace === 'string') {
|
|
15
|
+
return new SQLTableExpression(tableOrExpressiongOrNamespace);
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
16
18
|
return tableOrExpressiongOrNamespace;
|
|
17
19
|
}
|
|
18
20
|
}
|
|
19
21
|
|
|
20
22
|
export class SQLSelect<T = SQLResultNamespacedRow> extends Whereable(Orderable(EmptyClass)) implements SQLExpression {
|
|
21
|
-
_columns: SQLExpression[]
|
|
23
|
+
_columns: SQLExpression[];
|
|
22
24
|
_from: SQLExpression;
|
|
23
25
|
|
|
24
|
-
_limit: number|null = null;
|
|
25
|
-
_offset: number|null = null;
|
|
26
|
+
_limit: number | null = null;
|
|
27
|
+
_offset: number | null = null;
|
|
26
28
|
_groupBy: SQLExpression[] = [];
|
|
27
29
|
_joins: (InstanceType<typeof SQLJoin>)[] = [];
|
|
30
|
+
_max_execution_time: number | null = null;
|
|
28
31
|
|
|
29
|
-
_transformer: ((row: SQLResultNamespacedRow) => T)|null = null;
|
|
32
|
+
_transformer: ((row: SQLResultNamespacedRow) => T) | null = null;
|
|
30
33
|
|
|
31
|
-
constructor(...columns: (SQLExpression|string)[])
|
|
32
|
-
constructor(transformer: ((row: SQLResultNamespacedRow) => T)
|
|
33
|
-
constructor(...columns: (SQLExpression|string|((row: SQLResultNamespacedRow) => T))[]) {
|
|
34
|
+
constructor(...columns: (SQLExpression | string)[]);
|
|
35
|
+
constructor(transformer: ((row: SQLResultNamespacedRow) => T), ...columns: (SQLExpression | string)[]);
|
|
36
|
+
constructor(...columns: (SQLExpression | string | ((row: SQLResultNamespacedRow) => T))[]) {
|
|
34
37
|
super();
|
|
35
|
-
|
|
38
|
+
|
|
36
39
|
if (typeof columns[0] === 'function') {
|
|
37
40
|
this._transformer = columns.shift() as any;
|
|
38
41
|
}
|
|
39
|
-
this._columns = columns.map(c => typeof c === 'string' ? new SQLColumnExpression(c) : c
|
|
42
|
+
this._columns = columns.map(c => typeof c === 'string' ? new SQLColumnExpression(c) : c) as any;
|
|
40
43
|
}
|
|
41
44
|
|
|
42
45
|
clone(): this {
|
|
43
|
-
const c = new SQLSelect(...this._columns)
|
|
46
|
+
const c = new SQLSelect(...this._columns);
|
|
44
47
|
Object.assign(c, this);
|
|
45
48
|
return c as any;
|
|
46
49
|
}
|
|
47
50
|
|
|
48
|
-
from(namespace: string, table: string): this
|
|
49
|
-
from(table: string): this
|
|
50
|
-
from(expression: SQLExpression): this
|
|
51
|
-
from(tableOrExpressiongOrNamespace: SQLExpression|string, table?: string): this {
|
|
51
|
+
from(namespace: string, table: string): this;
|
|
52
|
+
from(table: string): this;
|
|
53
|
+
from(expression: SQLExpression): this;
|
|
54
|
+
from(tableOrExpressiongOrNamespace: SQLExpression | string, table?: string): this {
|
|
52
55
|
this._from = parseTable(tableOrExpressiongOrNamespace, table);
|
|
53
56
|
|
|
54
57
|
return this;
|
|
@@ -64,68 +67,77 @@ export class SQLSelect<T = SQLResultNamespacedRow> extends Whereable(Orderable(E
|
|
|
64
67
|
return this;
|
|
65
68
|
}
|
|
66
69
|
|
|
70
|
+
setMaxExecutionTime(ms: number): this {
|
|
71
|
+
this._max_execution_time = ms;
|
|
72
|
+
return this;
|
|
73
|
+
}
|
|
74
|
+
|
|
67
75
|
getSQL(options?: SQLExpressionOptions): SQLQuery {
|
|
68
76
|
const query: SQLQuery[] = [
|
|
69
|
-
'SELECT'
|
|
70
|
-
]
|
|
77
|
+
'SELECT',
|
|
78
|
+
];
|
|
79
|
+
|
|
80
|
+
if (this._max_execution_time !== null) {
|
|
81
|
+
query.push('/*+ MAX_EXECUTION_TIME(' + this._max_execution_time + ') */');
|
|
82
|
+
}
|
|
71
83
|
|
|
72
|
-
options = options ?? {}
|
|
84
|
+
options = options ?? {};
|
|
73
85
|
options.defaultNamespace = (this._from as any).namespace ?? (this._from as any).table ?? undefined;
|
|
74
86
|
|
|
75
|
-
const columns = this._columns.map(c => c.getSQL(options))
|
|
87
|
+
const columns = this._columns.map(c => c.getSQL(options));
|
|
76
88
|
query.push(
|
|
77
|
-
joinSQLQuery(columns, ', ')
|
|
78
|
-
)
|
|
89
|
+
joinSQLQuery(columns, ', '),
|
|
90
|
+
);
|
|
79
91
|
|
|
80
92
|
query.push(
|
|
81
|
-
'FROM'
|
|
82
|
-
)
|
|
93
|
+
'FROM',
|
|
94
|
+
);
|
|
83
95
|
|
|
84
96
|
query.push(this._from.getSQL(options));
|
|
85
97
|
|
|
86
|
-
query.push(...this._joins.map(j => j.getSQL(options)))
|
|
98
|
+
query.push(...this._joins.map(j => j.getSQL(options)));
|
|
87
99
|
|
|
88
100
|
if (this._where) {
|
|
89
|
-
query.push('WHERE')
|
|
90
|
-
query.push(this._where.getSQL(options))
|
|
101
|
+
query.push('WHERE');
|
|
102
|
+
query.push(this._where.getSQL(options));
|
|
91
103
|
}
|
|
92
104
|
|
|
93
105
|
if (this._groupBy.length > 0) {
|
|
94
|
-
query.push('GROUP BY')
|
|
106
|
+
query.push('GROUP BY');
|
|
95
107
|
query.push(
|
|
96
108
|
joinSQLQuery(
|
|
97
|
-
this._groupBy.map(c => c.getSQL(options)),
|
|
98
|
-
', '
|
|
99
|
-
)
|
|
100
|
-
)
|
|
109
|
+
this._groupBy.map(c => c.getSQL(options)),
|
|
110
|
+
', ',
|
|
111
|
+
),
|
|
112
|
+
);
|
|
101
113
|
}
|
|
102
114
|
|
|
103
115
|
if (this._orderBy) {
|
|
104
|
-
query.push(this._orderBy.getSQL(options))
|
|
116
|
+
query.push(this._orderBy.getSQL(options));
|
|
105
117
|
}
|
|
106
|
-
|
|
118
|
+
|
|
107
119
|
if (this._limit !== null) {
|
|
108
|
-
query.push('LIMIT ' + this._limit)
|
|
120
|
+
query.push('LIMIT ' + this._limit);
|
|
109
121
|
if (this._offset !== null && this._offset !== 0) {
|
|
110
|
-
query.push('OFFSET ' + this._offset)
|
|
122
|
+
query.push('OFFSET ' + this._offset);
|
|
111
123
|
}
|
|
112
124
|
}
|
|
113
|
-
|
|
125
|
+
|
|
114
126
|
return joinSQLQuery(query, ' ');
|
|
115
127
|
}
|
|
116
128
|
|
|
117
|
-
limit(limit: number|null, offset: number|null = null): this {
|
|
129
|
+
limit(limit: number | null, offset: number | null = null): this {
|
|
118
130
|
this._limit = limit;
|
|
119
131
|
this._offset = offset;
|
|
120
132
|
return this;
|
|
121
133
|
}
|
|
122
134
|
|
|
123
135
|
async fetch(): Promise<T[]> {
|
|
124
|
-
const {query, params} = normalizeSQLQuery(this.getSQL())
|
|
136
|
+
const { query, params } = normalizeSQLQuery(this.getSQL());
|
|
125
137
|
|
|
126
138
|
// when debugging: log all queries
|
|
127
139
|
console.log(query, params);
|
|
128
|
-
const [rows] = await Database.select(query, params, {nestTables: true});
|
|
140
|
+
const [rows] = await Database.select(query, params, { nestTables: true });
|
|
129
141
|
|
|
130
142
|
// Now map aggregated queries to the correct namespace
|
|
131
143
|
for (const row of rows) {
|
|
@@ -133,7 +145,7 @@ export class SQLSelect<T = SQLResultNamespacedRow> extends Whereable(Orderable(E
|
|
|
133
145
|
for (const column in row['']) {
|
|
134
146
|
const splitted = column.split('__');
|
|
135
147
|
if (splitted.length <= 1) {
|
|
136
|
-
console.warn('Aggregated column without namespace', column)
|
|
148
|
+
console.warn('Aggregated column without namespace', column);
|
|
137
149
|
continue;
|
|
138
150
|
}
|
|
139
151
|
const namespace = splitted[0];
|
|
@@ -151,35 +163,35 @@ export class SQLSelect<T = SQLResultNamespacedRow> extends Whereable(Orderable(E
|
|
|
151
163
|
return rows as T[];
|
|
152
164
|
}
|
|
153
165
|
|
|
154
|
-
first(required: false): Promise<T|null
|
|
155
|
-
first(required: true): Promise<T
|
|
156
|
-
async first(required = true): Promise<T|null>
|
|
166
|
+
first(required: false): Promise<T | null>;
|
|
167
|
+
first(required: true): Promise<T>;
|
|
168
|
+
async first(required = true): Promise<T | null> {
|
|
157
169
|
const rows = await this.limit(1).fetch();
|
|
158
170
|
if (rows.length === 0) {
|
|
159
171
|
if (required) {
|
|
160
|
-
throw new Error('Required ' + this._from)
|
|
172
|
+
throw new Error('Required ' + this._from);
|
|
161
173
|
}
|
|
162
174
|
return null;
|
|
163
175
|
}
|
|
164
176
|
|
|
165
|
-
return rows[0]
|
|
177
|
+
return rows[0];
|
|
166
178
|
}
|
|
167
179
|
|
|
168
180
|
async count(): Promise<number> {
|
|
169
181
|
this._columns = [
|
|
170
182
|
new SQLSelectAs(
|
|
171
|
-
new SQLCount(),
|
|
172
|
-
new SQLAlias('c')
|
|
173
|
-
)
|
|
174
|
-
]
|
|
183
|
+
new SQLCount(),
|
|
184
|
+
new SQLAlias('c'),
|
|
185
|
+
),
|
|
186
|
+
];
|
|
175
187
|
this._offset = null;
|
|
176
188
|
this._limit = null;
|
|
177
189
|
this._orderBy = null;
|
|
178
190
|
|
|
179
|
-
const {query, params} = normalizeSQLQuery(this.getSQL());
|
|
191
|
+
const { query, params } = normalizeSQLQuery(this.getSQL());
|
|
180
192
|
console.log(query, params);
|
|
181
193
|
|
|
182
|
-
const [rows] = await Database.select(query, params, {nestTables: true});
|
|
194
|
+
const [rows] = await Database.select(query, params, { nestTables: true });
|
|
183
195
|
if (rows.length === 1) {
|
|
184
196
|
const row = rows[0];
|
|
185
197
|
if ('' in row) {
|
|
@@ -199,18 +211,18 @@ export class SQLSelect<T = SQLResultNamespacedRow> extends Whereable(Orderable(E
|
|
|
199
211
|
async sum(expression: SQLExpression): Promise<number> {
|
|
200
212
|
this._columns = [
|
|
201
213
|
new SQLSelectAs(
|
|
202
|
-
new SQLSum(expression),
|
|
203
|
-
new SQLAlias('c')
|
|
204
|
-
)
|
|
205
|
-
]
|
|
214
|
+
new SQLSum(expression),
|
|
215
|
+
new SQLAlias('c'),
|
|
216
|
+
),
|
|
217
|
+
];
|
|
206
218
|
this._offset = null;
|
|
207
219
|
this._limit = null;
|
|
208
220
|
this._orderBy = null;
|
|
209
221
|
|
|
210
|
-
const {query, params} = normalizeSQLQuery(this.getSQL());
|
|
222
|
+
const { query, params } = normalizeSQLQuery(this.getSQL());
|
|
211
223
|
console.log(query, params);
|
|
212
224
|
|
|
213
|
-
const [rows] = await Database.select(query, params, {nestTables: true});
|
|
225
|
+
const [rows] = await Database.select(query, params, { nestTables: true });
|
|
214
226
|
if (rows.length === 1) {
|
|
215
227
|
const row = rows[0];
|
|
216
228
|
if ('' in row) {
|
package/src/filters/SQLFilter.ts
CHANGED
|
@@ -2,8 +2,8 @@ import { SimpleError } from '@simonbackx/simple-errors';
|
|
|
2
2
|
import { StamhoofdCompareValue, StamhoofdFilter } from '@stamhoofd/structures';
|
|
3
3
|
import { SQL } from '../SQL';
|
|
4
4
|
import { SQLExpression } from '../SQLExpression';
|
|
5
|
-
import { SQLArray, SQLCast, SQLColumnExpression, SQLNull, SQLSafeValue, SQLScalarValue, scalarToSQLExpression
|
|
6
|
-
import { SQLJsonContains, SQLJsonOverlaps, SQLJsonSearch, SQLJsonUnquote } from '../SQLJsonExpressions';
|
|
5
|
+
import { SQLArray, SQLCast, SQLColumnExpression, SQLLower, SQLNull, SQLSafeValue, SQLScalarValue, scalarToSQLExpression } from '../SQLExpressions';
|
|
6
|
+
import { SQLJsonContains, SQLJsonOverlaps, SQLJsonSearch, SQLJsonUnquote, scalarToSQLJSONExpression } from '../SQLJsonExpressions';
|
|
7
7
|
import { SQLSelect } from '../SQLSelect';
|
|
8
8
|
import { SQLWhere, SQLWhereAnd, SQLWhereEqual, SQLWhereExists, SQLWhereLike, SQLWhereNot, SQLWhereOr, SQLWhereSign } from '../SQLWhere';
|
|
9
9
|
|
|
@@ -61,6 +61,9 @@ function doNormalizeValue(val: StamhoofdCompareValue, options?: SQLExpressionFil
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
if (typeof val === 'string') {
|
|
64
|
+
if (options?.isJSONObject) {
|
|
65
|
+
return val;
|
|
66
|
+
}
|
|
64
67
|
return val.toLocaleLowerCase();
|
|
65
68
|
}
|
|
66
69
|
|
|
@@ -181,18 +184,25 @@ export function createSQLExpressionFilterCompiler(sqlExpression: SQLExpression,
|
|
|
181
184
|
if (isJSONObject) {
|
|
182
185
|
const v = norm(f.$eq);
|
|
183
186
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
// new SQLJsonSearch(sqlExpression, 'one', convertToExpression(v)),
|
|
187
|
-
// SQLWhereSign.NotEqual,
|
|
188
|
-
// new SQLNull()
|
|
189
|
-
// );
|
|
190
|
-
// }
|
|
187
|
+
if (typeof v === 'string') {
|
|
188
|
+
// Custom query to support case insensitive comparing
|
|
191
189
|
|
|
190
|
+
return new SQLWhereEqual(
|
|
191
|
+
new SQLJsonSearch(
|
|
192
|
+
new SQLLower(sqlExpression),
|
|
193
|
+
'one',
|
|
194
|
+
convertToExpression(
|
|
195
|
+
SQLWhereLike.escape(v.toLocaleLowerCase()),
|
|
196
|
+
),
|
|
197
|
+
),
|
|
198
|
+
SQLWhereSign.NotEqual,
|
|
199
|
+
new SQLNull(),
|
|
200
|
+
);
|
|
201
|
+
}
|
|
192
202
|
// else
|
|
193
203
|
return new SQLJsonContains(
|
|
194
204
|
sqlExpression,
|
|
195
|
-
convertToExpression(
|
|
205
|
+
convertToExpression(v),
|
|
196
206
|
);
|
|
197
207
|
}
|
|
198
208
|
|
|
@@ -361,7 +371,7 @@ export function createSQLExpressionFilterCompiler(sqlExpression: SQLExpression,
|
|
|
361
371
|
if (isJSONObject) {
|
|
362
372
|
return new SQLWhereEqual(
|
|
363
373
|
new SQLJsonSearch(
|
|
364
|
-
sqlExpression,
|
|
374
|
+
new SQLLower(sqlExpression),
|
|
365
375
|
'one',
|
|
366
376
|
convertToExpression(
|
|
367
377
|
'%' + SQLWhereLike.escape(needle) + '%',
|