pqb 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/dist/index.d.ts +22 -17
- package/dist/index.esm.js +74 -23
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +77 -22
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/columnSchema/columnsSchema.ts +4 -0
- package/src/errors.ts +12 -2
- package/src/queryMethods/select.ts +3 -0
- package/src/queryMethods/where.test.ts +14 -2
- package/src/queryMethods/where.ts +3 -0
- package/src/relations.ts +1 -1
- package/src/sql/aggregate.ts +1 -4
- package/src/sql/having.ts +2 -8
- package/src/sql/insert.ts +2 -8
- package/src/sql/join.ts +19 -15
- package/src/sql/select.ts +36 -15
- package/src/sql/types.ts +6 -2
- package/src/sql/where.ts +9 -15
package/package.json
CHANGED
|
@@ -38,6 +38,10 @@ export class ArrayOfColumnsObjects<
|
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
export abstract class PluckResultColumnType<
|
|
42
|
+
C extends ColumnType,
|
|
43
|
+
> extends ColumnType<C['type'][], typeof Operators.any> {}
|
|
44
|
+
|
|
41
45
|
type UnionKeyofToOvlds<S, U> = UnionToIntersection<
|
|
42
46
|
U extends keyof S ? (f: U) => void : never
|
|
43
47
|
>;
|
package/src/errors.ts
CHANGED
|
@@ -1,7 +1,17 @@
|
|
|
1
|
-
export class
|
|
1
|
+
export class PormError extends Error {}
|
|
2
|
+
|
|
3
|
+
export class NotFoundError extends PormError {
|
|
2
4
|
constructor(message = 'Record is not found') {
|
|
3
5
|
super(message);
|
|
4
6
|
}
|
|
5
7
|
}
|
|
6
8
|
|
|
7
|
-
export class MoreThanOneRowError extends
|
|
9
|
+
export class MoreThanOneRowError extends PormError {}
|
|
10
|
+
|
|
11
|
+
export class PormInternalError extends Error {}
|
|
12
|
+
|
|
13
|
+
export class UnhandledTypeError extends PormInternalError {
|
|
14
|
+
constructor(value: never) {
|
|
15
|
+
super(`Unhandled type: ${JSON.stringify(value)} received`);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
ArrayOfColumnsObjects,
|
|
11
11
|
ColumnsObject,
|
|
12
12
|
NullableColumn,
|
|
13
|
+
PluckResultColumnType,
|
|
13
14
|
} from '../columnSchema';
|
|
14
15
|
import { getQueryParsers, isRaw, RawExpression } from '../common';
|
|
15
16
|
import { pushQueryArray } from '../queryDataUtils';
|
|
@@ -59,6 +60,8 @@ type SelectResult<
|
|
|
59
60
|
? ArrayOfColumnsObjects<Arg['result']>
|
|
60
61
|
: Arg['returnType'] extends 'valueOrThrow'
|
|
61
62
|
? Arg['result']['value']
|
|
63
|
+
: Arg['returnType'] extends 'pluck'
|
|
64
|
+
? PluckResultColumnType<Arg['result']['pluck']>
|
|
62
65
|
: Arg[isRequiredRelationKey] extends true
|
|
63
66
|
? ColumnsObject<Arg['result']>
|
|
64
67
|
: NullableColumn<ColumnsObject<Arg['result']>>
|
|
@@ -1546,7 +1546,11 @@ export const testJoin = (
|
|
|
1546
1546
|
describe('relation', () => {
|
|
1547
1547
|
const withRelation = q as Query & {
|
|
1548
1548
|
relations: {
|
|
1549
|
-
message: {
|
|
1549
|
+
message: {
|
|
1550
|
+
key: 'message';
|
|
1551
|
+
query: typeof Message;
|
|
1552
|
+
joinQuery(fromQuery: Query, toQuery: Query): Query;
|
|
1553
|
+
};
|
|
1550
1554
|
};
|
|
1551
1555
|
};
|
|
1552
1556
|
|
|
@@ -1554,7 +1558,15 @@ export const testJoin = (
|
|
|
1554
1558
|
message: {
|
|
1555
1559
|
key: 'message',
|
|
1556
1560
|
query: Message,
|
|
1557
|
-
joinQuery
|
|
1561
|
+
joinQuery(fromQuery, toQuery) {
|
|
1562
|
+
return pushQueryOn(
|
|
1563
|
+
toQuery.clone(),
|
|
1564
|
+
toQuery,
|
|
1565
|
+
fromQuery,
|
|
1566
|
+
'authorId',
|
|
1567
|
+
'id',
|
|
1568
|
+
);
|
|
1569
|
+
},
|
|
1558
1570
|
},
|
|
1559
1571
|
};
|
|
1560
1572
|
|
|
@@ -440,6 +440,9 @@ export class WhereQueryBuilder<Q extends QueryBase = QueryBase>
|
|
|
440
440
|
constructor(public table: Q['table'], public tableAlias: Q['tableAlias']) {
|
|
441
441
|
super();
|
|
442
442
|
this.__model = this as unknown as Query;
|
|
443
|
+
if (tableAlias) {
|
|
444
|
+
this.query.as = tableAlias;
|
|
445
|
+
}
|
|
443
446
|
}
|
|
444
447
|
|
|
445
448
|
clone<T extends this>(this: T): T {
|
package/src/relations.ts
CHANGED
package/src/sql/aggregate.ts
CHANGED
|
@@ -7,10 +7,7 @@ import { whereToSql } from './where';
|
|
|
7
7
|
import { Query } from '../query';
|
|
8
8
|
|
|
9
9
|
export const aggregateToSql = (
|
|
10
|
-
model:
|
|
11
|
-
Query,
|
|
12
|
-
'whereQueryBuilder' | 'onQueryBuilder' | 'as' | 'shape' | 'relations'
|
|
13
|
-
>,
|
|
10
|
+
model: Query,
|
|
14
11
|
values: unknown[],
|
|
15
12
|
item: AggregateItem,
|
|
16
13
|
quotedAs?: string,
|
package/src/sql/having.ts
CHANGED
|
@@ -15,10 +15,7 @@ const aggregateOptionNames: (keyof AggregateItemOptions)[] = [
|
|
|
15
15
|
|
|
16
16
|
export const pushHavingSql = (
|
|
17
17
|
sql: string[],
|
|
18
|
-
model:
|
|
19
|
-
Query,
|
|
20
|
-
'whereQueryBuilder' | 'onQueryBuilder' | 'as' | 'shape' | 'relations'
|
|
21
|
-
>,
|
|
18
|
+
model: Query,
|
|
22
19
|
query: SelectQueryData,
|
|
23
20
|
values: unknown[],
|
|
24
21
|
quotedAs?: string,
|
|
@@ -28,10 +25,7 @@ export const pushHavingSql = (
|
|
|
28
25
|
};
|
|
29
26
|
|
|
30
27
|
export const havingToSql = (
|
|
31
|
-
model:
|
|
32
|
-
Query,
|
|
33
|
-
'whereQueryBuilder' | 'onQueryBuilder' | 'as' | 'shape' | 'relations'
|
|
34
|
-
>,
|
|
28
|
+
model: Query,
|
|
35
29
|
query: SelectQueryData,
|
|
36
30
|
values: unknown[],
|
|
37
31
|
quotedAs?: string,
|
package/src/sql/insert.ts
CHANGED
|
@@ -8,10 +8,7 @@ import { selectToSql } from './select';
|
|
|
8
8
|
export const pushInsertSql = (
|
|
9
9
|
sql: string[],
|
|
10
10
|
values: unknown[],
|
|
11
|
-
model:
|
|
12
|
-
Query,
|
|
13
|
-
'whereQueryBuilder' | 'onQueryBuilder' | 'as' | 'shape' | 'relations'
|
|
14
|
-
>,
|
|
11
|
+
model: Query,
|
|
15
12
|
query: InsertQueryData,
|
|
16
13
|
quotedAs: string,
|
|
17
14
|
) => {
|
|
@@ -88,10 +85,7 @@ export const pushInsertSql = (
|
|
|
88
85
|
|
|
89
86
|
export const pushReturningSql = (
|
|
90
87
|
sql: string[],
|
|
91
|
-
model:
|
|
92
|
-
Query,
|
|
93
|
-
'whereQueryBuilder' | 'onQueryBuilder' | 'as' | 'shape' | 'relations'
|
|
94
|
-
>,
|
|
88
|
+
model: Query,
|
|
95
89
|
query: QueryData,
|
|
96
90
|
values: unknown[],
|
|
97
91
|
quotedAs: string,
|
package/src/sql/join.ts
CHANGED
|
@@ -19,10 +19,7 @@ type ItemOf3Or4Length =
|
|
|
19
19
|
];
|
|
20
20
|
|
|
21
21
|
export const processJoinItem = (
|
|
22
|
-
model:
|
|
23
|
-
Query,
|
|
24
|
-
'whereQueryBuilder' | 'onQueryBuilder' | 'table' | 'shape' | 'relations'
|
|
25
|
-
>,
|
|
22
|
+
model: Query,
|
|
26
23
|
query: Pick<QueryData, 'as'>,
|
|
27
24
|
values: unknown[],
|
|
28
25
|
args: JoinItem['args'],
|
|
@@ -31,33 +28,40 @@ export const processJoinItem = (
|
|
|
31
28
|
const [first] = args;
|
|
32
29
|
if (typeof first === 'string') {
|
|
33
30
|
if (first in model.relations) {
|
|
34
|
-
const {
|
|
35
|
-
|
|
36
|
-
|
|
31
|
+
const {
|
|
32
|
+
key,
|
|
33
|
+
query: toQuery,
|
|
34
|
+
joinQuery,
|
|
35
|
+
} = (model.relations as Record<string, Relation>)[first];
|
|
36
|
+
|
|
37
|
+
const joinedQuery = joinQuery(model, toQuery);
|
|
38
|
+
const joinedQueryData = joinedQuery.query;
|
|
37
39
|
|
|
38
40
|
const table = (
|
|
39
|
-
typeof
|
|
40
|
-
?
|
|
41
|
-
:
|
|
41
|
+
typeof joinedQueryData.from === 'string'
|
|
42
|
+
? joinedQueryData.from
|
|
43
|
+
: joinedQuery.table
|
|
42
44
|
) as string;
|
|
43
45
|
|
|
44
|
-
let target = quoteSchemaAndTable(
|
|
46
|
+
let target = quoteSchemaAndTable(joinedQueryData.schema, table);
|
|
45
47
|
|
|
46
|
-
const as =
|
|
48
|
+
const as = joinedQueryData.as || key;
|
|
47
49
|
if (as !== table) {
|
|
48
50
|
target += ` AS ${q(as as string)}`;
|
|
49
51
|
}
|
|
50
52
|
|
|
51
53
|
const queryData = {
|
|
54
|
+
as: joinedQuery.query.as,
|
|
52
55
|
and: [],
|
|
53
56
|
or: [],
|
|
54
57
|
} as {
|
|
58
|
+
as?: string;
|
|
55
59
|
and: Exclude<QueryData['and'], undefined>;
|
|
56
60
|
or: Exclude<QueryData['or'], undefined>;
|
|
57
61
|
};
|
|
58
62
|
|
|
59
|
-
if (
|
|
60
|
-
if (
|
|
63
|
+
if (joinedQueryData.and) queryData.and.push(...joinedQueryData.and);
|
|
64
|
+
if (joinedQueryData.or) queryData.or.push(...joinedQueryData.or);
|
|
61
65
|
|
|
62
66
|
const arg = (args[1] as ((q: unknown) => QueryBase) | undefined)?.(
|
|
63
67
|
new model.onQueryBuilder({ table: model.table, query }, args[0]),
|
|
@@ -70,7 +74,7 @@ export const processJoinItem = (
|
|
|
70
74
|
|
|
71
75
|
const joinAs = q(as as string);
|
|
72
76
|
const onConditions = whereToSql(
|
|
73
|
-
|
|
77
|
+
joinedQuery,
|
|
74
78
|
queryData,
|
|
75
79
|
values,
|
|
76
80
|
quotedAs,
|
package/src/sql/select.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { JsonItem, SelectFunctionItem, SelectQueryData } from './types';
|
|
2
|
-
import { Expression, getRaw, isRaw } from '../common';
|
|
2
|
+
import { Expression, getRaw, isRaw, raw } from '../common';
|
|
3
3
|
import { Query } from '../query';
|
|
4
4
|
import { addValue, q, quoteFullColumn } from './common';
|
|
5
5
|
import { aggregateToSql } from './aggregate';
|
|
6
6
|
import { getQueryAs } from '../utils';
|
|
7
7
|
import { RelationQuery, relationQueryKey } from '../relations';
|
|
8
|
+
import { PormInternalError, UnhandledTypeError } from '../errors';
|
|
8
9
|
|
|
9
10
|
const jsonColumnOrMethodToSql = (
|
|
10
11
|
column: string | JsonItem,
|
|
@@ -62,10 +63,7 @@ const jsonToSql = (
|
|
|
62
63
|
|
|
63
64
|
export const pushSelectSql = (
|
|
64
65
|
sql: string[],
|
|
65
|
-
model:
|
|
66
|
-
Query,
|
|
67
|
-
'whereQueryBuilder' | 'onQueryBuilder' | 'as' | 'shape' | 'relations'
|
|
68
|
-
>,
|
|
66
|
+
model: Query,
|
|
69
67
|
query: Pick<SelectQueryData, 'select' | 'join'>,
|
|
70
68
|
values: unknown[],
|
|
71
69
|
quotedAs?: string,
|
|
@@ -74,10 +72,7 @@ export const pushSelectSql = (
|
|
|
74
72
|
};
|
|
75
73
|
|
|
76
74
|
export const selectToSql = (
|
|
77
|
-
model:
|
|
78
|
-
Query,
|
|
79
|
-
'whereQueryBuilder' | 'onQueryBuilder' | 'as' | 'shape' | 'relations'
|
|
80
|
-
>,
|
|
75
|
+
model: Query,
|
|
81
76
|
query: Pick<SelectQueryData, 'select' | 'join'>,
|
|
82
77
|
values: unknown[],
|
|
83
78
|
quotedAs?: string,
|
|
@@ -99,12 +94,38 @@ export const selectToSql = (
|
|
|
99
94
|
relationQuery._as(relationQuery.query[relationQueryKey] as string);
|
|
100
95
|
|
|
101
96
|
const { returnType } = relationQuery.query;
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
97
|
+
switch (returnType) {
|
|
98
|
+
case 'all':
|
|
99
|
+
case 'one':
|
|
100
|
+
case 'oneOrThrow':
|
|
101
|
+
relationQuery =
|
|
102
|
+
relationQuery._json() as unknown as typeof relationQuery;
|
|
103
|
+
break;
|
|
104
|
+
case 'pluck': {
|
|
105
|
+
const first = relationQuery.query.select?.[0];
|
|
106
|
+
if (!first)
|
|
107
|
+
throw new PormInternalError(`Nothing was selected for pluck`);
|
|
108
|
+
|
|
109
|
+
const selection = selectToSql(
|
|
110
|
+
relationQuery.__model,
|
|
111
|
+
relationQuery.query,
|
|
112
|
+
values,
|
|
113
|
+
q(getQueryAs(relationQuery)),
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
relationQuery.query.select = [
|
|
117
|
+
raw(`COALESCE(json_agg(${selection}), '[]')`),
|
|
118
|
+
];
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
case 'rows':
|
|
122
|
+
case 'value':
|
|
123
|
+
case 'valueOrThrow':
|
|
124
|
+
case 'rowCount':
|
|
125
|
+
case 'void':
|
|
126
|
+
break;
|
|
127
|
+
default:
|
|
128
|
+
throw new UnhandledTypeError(returnType);
|
|
108
129
|
}
|
|
109
130
|
|
|
110
131
|
list.push(`(${relationQuery.toSql(values).text}) AS ${as}`);
|
package/src/sql/types.ts
CHANGED
|
@@ -277,13 +277,17 @@ export type WhereJsonPathEqualsItem = [
|
|
|
277
277
|
];
|
|
278
278
|
|
|
279
279
|
export type WhereOnItem = {
|
|
280
|
-
joinFrom:
|
|
281
|
-
joinTo:
|
|
280
|
+
joinFrom: WhereOnJoinItem;
|
|
281
|
+
joinTo: WhereOnJoinItem;
|
|
282
282
|
on:
|
|
283
283
|
| [leftFullColumn: string, rightFullColumn: string]
|
|
284
284
|
| [leftFullColumn: string, op: string, rightFullColumn: string];
|
|
285
285
|
};
|
|
286
286
|
|
|
287
|
+
export type WhereOnJoinItem =
|
|
288
|
+
| { table?: string; query: { as?: string } }
|
|
289
|
+
| string;
|
|
290
|
+
|
|
287
291
|
export type AggregateItemOptions = {
|
|
288
292
|
as?: string;
|
|
289
293
|
distinct?: boolean;
|
package/src/sql/where.ts
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
WhereItem,
|
|
7
7
|
WhereJsonPathEqualsItem,
|
|
8
8
|
WhereOnItem,
|
|
9
|
+
WhereOnJoinItem,
|
|
9
10
|
} from './types';
|
|
10
11
|
import { addValue, q, qc, quoteFullColumn } from './common';
|
|
11
12
|
import { EMPTY_OBJECT, getRaw, isRaw, RawExpression } from '../common';
|
|
@@ -14,10 +15,7 @@ import { processJoinItem } from './join';
|
|
|
14
15
|
|
|
15
16
|
export const pushWhereSql = (
|
|
16
17
|
sql: string[],
|
|
17
|
-
model:
|
|
18
|
-
Query,
|
|
19
|
-
'whereQueryBuilder' | 'onQueryBuilder' | 'as' | 'shape' | 'relations'
|
|
20
|
-
>,
|
|
18
|
+
model: Query,
|
|
21
19
|
query: Pick<QueryData, 'as' | 'and' | 'or'>,
|
|
22
20
|
values: unknown[],
|
|
23
21
|
quotedAs?: string,
|
|
@@ -36,10 +34,7 @@ export const pushWhereSql = (
|
|
|
36
34
|
};
|
|
37
35
|
|
|
38
36
|
export const whereToSql = (
|
|
39
|
-
model:
|
|
40
|
-
Query,
|
|
41
|
-
'whereQueryBuilder' | 'onQueryBuilder' | 'table' | 'shape' | 'relations'
|
|
42
|
-
>,
|
|
37
|
+
model: Query,
|
|
43
38
|
query: Pick<QueryData, 'as' | 'and' | 'or'>,
|
|
44
39
|
values: unknown[],
|
|
45
40
|
quotedAs?: string,
|
|
@@ -234,15 +229,10 @@ const whereHandlers: Record<
|
|
|
234
229
|
const item = value as WhereOnItem;
|
|
235
230
|
const leftColumn = quoteFullColumn(
|
|
236
231
|
item.on[0],
|
|
237
|
-
|
|
238
|
-
? q(item.joinTo)
|
|
239
|
-
: q(getQueryAs(item.joinTo)),
|
|
232
|
+
getJoinItemSource(item.joinTo),
|
|
240
233
|
);
|
|
241
234
|
|
|
242
|
-
const joinTo =
|
|
243
|
-
typeof item.joinFrom === 'string'
|
|
244
|
-
? item.joinFrom
|
|
245
|
-
: q(getQueryAs(item.joinFrom));
|
|
235
|
+
const joinTo = getJoinItemSource(item.joinFrom);
|
|
246
236
|
|
|
247
237
|
const [op, rightColumn] =
|
|
248
238
|
item.on.length === 2
|
|
@@ -275,6 +265,10 @@ const whereHandlers: Record<
|
|
|
275
265
|
},
|
|
276
266
|
};
|
|
277
267
|
|
|
268
|
+
const getJoinItemSource = (joinItem: WhereOnJoinItem) => {
|
|
269
|
+
return typeof joinItem === 'string' ? q(joinItem) : q(getQueryAs(joinItem));
|
|
270
|
+
};
|
|
271
|
+
|
|
278
272
|
const pushIn = (
|
|
279
273
|
ands: string[],
|
|
280
274
|
prefix: string,
|