@sqb/connect 4.12.0 → 4.12.1
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/cjs/index.js +1 -0
- package/cjs/orm/commands/command.helper.js +1 -1
- package/cjs/orm/commands/find.command.js +18 -34
- package/cjs/orm/decorators/column.decorator.js +6 -2
- package/cjs/orm/orm.const.js +2 -1
- package/cjs/orm/repository.class.js +21 -6
- package/cjs/orm/util/parse-fields-projection.js +66 -0
- package/esm/index.js +1 -0
- package/esm/orm/commands/command.helper.js +1 -1
- package/esm/orm/commands/find.command.js +18 -34
- package/esm/orm/decorators/column.decorator.js +5 -1
- package/esm/orm/orm.const.js +1 -0
- package/esm/orm/repository.class.js +21 -6
- package/esm/orm/util/parse-fields-projection.js +61 -0
- package/package.json +8 -5
- package/types/index.d.ts +1 -0
- package/types/orm/commands/find.command.d.ts +2 -3
- package/types/orm/decorators/column.decorator.d.ts +1 -0
- package/types/orm/model/field-metadata.d.ts +1 -1
- package/types/orm/orm.const.d.ts +1 -0
- package/types/orm/repository.class.d.ts +9 -7
- package/types/orm/util/parse-fields-projection.d.ts +10 -0
package/cjs/index.js
CHANGED
|
@@ -38,4 +38,5 @@ Object.defineProperty(exports, "isColumnField", { enumerable: true, get: functio
|
|
|
38
38
|
Object.defineProperty(exports, "isEmbeddedField", { enumerable: true, get: function () { return orm_helper_js_1.isEmbeddedField; } });
|
|
39
39
|
Object.defineProperty(exports, "isAssociationField", { enumerable: true, get: function () { return orm_helper_js_1.isAssociationField; } });
|
|
40
40
|
Object.defineProperty(exports, "isEntityClass", { enumerable: true, get: function () { return orm_helper_js_1.isEntityClass; } });
|
|
41
|
+
tslib_1.__exportStar(require("./orm/util/parse-fields-projection.js"), exports);
|
|
41
42
|
tslib_1.__exportStar(require("./orm/backward.js"), exports);
|
|
@@ -53,7 +53,7 @@ async function joinAssociation(joinInfos, association, parentAlias, innerJoin) {
|
|
|
53
53
|
exports.joinAssociation = joinAssociation;
|
|
54
54
|
async function prepareFilter(entityDef, filter, trgOp, tableAlias = 'T') {
|
|
55
55
|
let srcOp;
|
|
56
|
-
if ((0, builder_1.isLogicalOperator)(filter))
|
|
56
|
+
if ((0, builder_1.isLogicalOperator)(filter) && filter._operatorType === trgOp._operatorType)
|
|
57
57
|
srcOp = filter;
|
|
58
58
|
else {
|
|
59
59
|
srcOp = (0, builder_1.And)();
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.FindCommand = void 0;
|
|
4
4
|
const builder_1 = require("@sqb/builder");
|
|
5
|
-
const entity_decorator_js_1 = require("../decorators/entity.decorator.js");
|
|
6
5
|
const association_node_js_1 = require("../model/association-node.js");
|
|
7
6
|
const embedded_field_metadata_js_1 = require("../model/embedded-field-metadata.js");
|
|
8
7
|
const entity_metadata_js_1 = require("../model/entity-metadata.js");
|
|
9
8
|
const orm_helper_js_1 = require("../util/orm.helper.js");
|
|
9
|
+
const parse_fields_projection_js_1 = require("../util/parse-fields-projection.js");
|
|
10
10
|
const command_helper_js_1 = require("./command.helper.js");
|
|
11
11
|
const row_converter_js_1 = require("./row-converter.js");
|
|
12
12
|
const SORT_ORDER_PATTERN = /^([-+])?(.*)$/;
|
|
@@ -56,9 +56,7 @@ class FindCommand {
|
|
|
56
56
|
maxEagerFetch: args.maxEagerFetch,
|
|
57
57
|
});
|
|
58
58
|
await command.addFields({
|
|
59
|
-
|
|
60
|
-
include: args.include,
|
|
61
|
-
omit: args.omit,
|
|
59
|
+
projection: args.projection,
|
|
62
60
|
sort: args.sort,
|
|
63
61
|
});
|
|
64
62
|
if (args.filter)
|
|
@@ -71,22 +69,10 @@ class FindCommand {
|
|
|
71
69
|
const tableAlias = opts.tableAlias || this.resultAlias;
|
|
72
70
|
const entity = opts.entity || this._getEntityFromAlias(tableAlias);
|
|
73
71
|
const converter = opts.converter || this.converter;
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
if (_pick)
|
|
79
|
-
requestedFields = [..._pick];
|
|
80
|
-
else {
|
|
81
|
-
requestedFields = entity_decorator_js_1.Entity.getFieldNames(entity.ctor).reduce((a, x) => {
|
|
82
|
-
const f = entity_decorator_js_1.Entity.getField(entity.ctor, x);
|
|
83
|
-
if (f && !f.exclusive)
|
|
84
|
-
a.push(x.toLowerCase());
|
|
85
|
-
return a;
|
|
86
|
-
}, []);
|
|
87
|
-
}
|
|
88
|
-
if (_include)
|
|
89
|
-
requestedFields.push(..._include);
|
|
72
|
+
const projection = typeof opts.projection === 'string' || Array.isArray(opts.projection)
|
|
73
|
+
? (0, parse_fields_projection_js_1.parseFieldsProjection)(opts.projection)
|
|
74
|
+
: opts.projection;
|
|
75
|
+
const defaultFields = !projection || !Object.values(projection).find(p => !p.sign);
|
|
90
76
|
const sortFields = opts.sort && opts.sort.length ? opts.sort.map(x => x.toLowerCase()) : undefined;
|
|
91
77
|
const prefix = opts.prefix || '';
|
|
92
78
|
const suffix = opts.suffix || '';
|
|
@@ -95,12 +81,16 @@ class FindCommand {
|
|
|
95
81
|
if (!col || col.hidden)
|
|
96
82
|
continue;
|
|
97
83
|
const colNameLower = col.name.toLowerCase();
|
|
98
|
-
|
|
99
|
-
if (
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
84
|
+
const p = projection?.[colNameLower];
|
|
85
|
+
if (
|
|
86
|
+
/** Ignore if field is omitted */
|
|
87
|
+
p?.sign === '-' ||
|
|
88
|
+
/** Ignore if default fields and field is not in projection */
|
|
89
|
+
(!defaultFields && !p) ||
|
|
90
|
+
/** Ignore if default fields enabled and fields is exclusive */
|
|
91
|
+
(defaultFields && col.exclusive && !p)) {
|
|
103
92
|
continue;
|
|
93
|
+
}
|
|
104
94
|
// Add field to select list if field is a column
|
|
105
95
|
if ((0, orm_helper_js_1.isColumnField)(col)) {
|
|
106
96
|
const fieldAlias = this._selectColumn(tableAlias, col, prefix, suffix);
|
|
@@ -125,9 +115,7 @@ class FindCommand {
|
|
|
125
115
|
entity: typ,
|
|
126
116
|
prefix: col.fieldNamePrefix,
|
|
127
117
|
suffix: col.fieldNameSuffix,
|
|
128
|
-
|
|
129
|
-
include: extractSubFields(colNameLower, _include),
|
|
130
|
-
omit: extractSubFields(colNameLower, _omit),
|
|
118
|
+
projection: p?.projection,
|
|
131
119
|
sort: extractSubFields(colNameLower, sortFields),
|
|
132
120
|
});
|
|
133
121
|
continue;
|
|
@@ -145,9 +133,7 @@ class FindCommand {
|
|
|
145
133
|
tableAlias: joinInfo.joinAlias,
|
|
146
134
|
converter: subConverter,
|
|
147
135
|
entity: joinInfo.targetEntity,
|
|
148
|
-
|
|
149
|
-
include: extractSubFields(colNameLower, _include),
|
|
150
|
-
omit: extractSubFields(colNameLower, _omit),
|
|
136
|
+
projection: p?.projection,
|
|
151
137
|
sort: extractSubFields(colNameLower, sortFields),
|
|
152
138
|
});
|
|
153
139
|
continue;
|
|
@@ -167,9 +153,7 @@ class FindCommand {
|
|
|
167
153
|
await findCommand.filter((0, builder_1.In)(targetCol.name, (0, builder_1.Param)(parentField)));
|
|
168
154
|
const sort = sortFields && extractSubFields(colNameLower, sortFields);
|
|
169
155
|
await findCommand.addFields({
|
|
170
|
-
|
|
171
|
-
include: extractSubFields(colNameLower, _include),
|
|
172
|
-
omit: extractSubFields(colNameLower, _omit),
|
|
156
|
+
projection: p?.projection,
|
|
173
157
|
sort,
|
|
174
158
|
});
|
|
175
159
|
if (sort)
|
|
@@ -2,7 +2,12 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Column = void 0;
|
|
4
4
|
const entity_metadata_js_1 = require("../model/entity-metadata.js");
|
|
5
|
+
const orm_const_js_1 = require("../orm.const.js");
|
|
5
6
|
function Column(arg0) {
|
|
7
|
+
return Column[orm_const_js_1.DECORATOR_FACTORY](arg0);
|
|
8
|
+
}
|
|
9
|
+
exports.Column = Column;
|
|
10
|
+
Column[orm_const_js_1.DECORATOR_FACTORY] = function (arg0) {
|
|
6
11
|
return (target, propertyKey) => {
|
|
7
12
|
if (typeof propertyKey !== 'string')
|
|
8
13
|
throw new Error('Symbol properties are not accepted');
|
|
@@ -19,5 +24,4 @@ function Column(arg0) {
|
|
|
19
24
|
}
|
|
20
25
|
entity_metadata_js_1.EntityMetadata.defineColumnField(entity, propertyKey, options);
|
|
21
26
|
};
|
|
22
|
-
}
|
|
23
|
-
exports.Column = Column;
|
|
27
|
+
};
|
package/cjs/orm/orm.const.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.REPOSITORY_KEY = exports.ENTITY_METADATA_KEY = void 0;
|
|
3
|
+
exports.DECORATOR_FACTORY = exports.REPOSITORY_KEY = exports.ENTITY_METADATA_KEY = void 0;
|
|
4
4
|
exports.ENTITY_METADATA_KEY = Symbol.for('SQB_ENTITY_METADATA');
|
|
5
5
|
exports.REPOSITORY_KEY = Symbol.for('SQB_REPOSITORY');
|
|
6
|
+
exports.DECORATOR_FACTORY = Symbol.for('decorator.factory');
|
|
@@ -41,15 +41,16 @@ class Repository extends (0, strict_typed_events_1.TypedEventEmitterClass)(stric
|
|
|
41
41
|
return this._exists(keyValue, { ...options, connection });
|
|
42
42
|
}, options);
|
|
43
43
|
}
|
|
44
|
+
existsOne(options) {
|
|
45
|
+
return this._execute(async (connection) => {
|
|
46
|
+
return this._existsOne({ ...options, connection });
|
|
47
|
+
}, options);
|
|
48
|
+
}
|
|
44
49
|
count(options) {
|
|
45
50
|
return this._execute(async (connection) => {
|
|
46
51
|
return this._count({ ...options, connection });
|
|
47
52
|
}, options);
|
|
48
53
|
}
|
|
49
|
-
/** @deprecated - Use findById instead */
|
|
50
|
-
find(keyValue, options) {
|
|
51
|
-
return this.findById(keyValue, options);
|
|
52
|
-
}
|
|
53
54
|
findById(keyValue, options) {
|
|
54
55
|
return this._execute(async (connection) => {
|
|
55
56
|
return this._find(keyValue, { ...options, connection });
|
|
@@ -132,11 +133,25 @@ class Repository extends (0, strict_typed_events_1.TypedEventEmitterClass)(stric
|
|
|
132
133
|
else
|
|
133
134
|
filter.push(options.filter);
|
|
134
135
|
}
|
|
135
|
-
return
|
|
136
|
+
return this._existsOne({
|
|
137
|
+
...options,
|
|
138
|
+
filter,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
async _existsOne(options) {
|
|
142
|
+
const filter = [];
|
|
143
|
+
if (options && options.filter) {
|
|
144
|
+
if (Array.isArray(options.filter))
|
|
145
|
+
filter.push(...options.filter);
|
|
146
|
+
else
|
|
147
|
+
filter.push(options.filter);
|
|
148
|
+
}
|
|
149
|
+
const resp = await find_command_js_1.FindCommand.execute({
|
|
136
150
|
...options,
|
|
137
151
|
filter,
|
|
138
152
|
entity: this._entity,
|
|
139
|
-
})
|
|
153
|
+
});
|
|
154
|
+
return resp.length > 0;
|
|
140
155
|
}
|
|
141
156
|
async _count(options) {
|
|
142
157
|
return count_command_js_1.CountCommand.execute({
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseFieldsProjection = exports.FieldsProjection = void 0;
|
|
4
|
+
const fast_tokenizer_1 = require("fast-tokenizer");
|
|
5
|
+
const FIELD_PATTERN = /^([+-])?([a-z_$]\w*)$/i;
|
|
6
|
+
const NO_DOT_BRACKET_PATTERN = /[^.]\(/g;
|
|
7
|
+
class FieldsProjection {
|
|
8
|
+
}
|
|
9
|
+
exports.FieldsProjection = FieldsProjection;
|
|
10
|
+
(function (FieldsProjection) {
|
|
11
|
+
class Item {
|
|
12
|
+
}
|
|
13
|
+
FieldsProjection.Item = Item;
|
|
14
|
+
})(FieldsProjection || (exports.FieldsProjection = FieldsProjection = {}));
|
|
15
|
+
function parseFieldsProjection(projection, keepCase) {
|
|
16
|
+
const arr = Array.isArray(projection) ? projection : [projection];
|
|
17
|
+
if (!(arr && arr.length))
|
|
18
|
+
return;
|
|
19
|
+
const out = new FieldsProjection();
|
|
20
|
+
for (let s of arr) {
|
|
21
|
+
if (!keepCase)
|
|
22
|
+
s = s.toLowerCase();
|
|
23
|
+
parse(s, out);
|
|
24
|
+
}
|
|
25
|
+
return out;
|
|
26
|
+
}
|
|
27
|
+
exports.parseFieldsProjection = parseFieldsProjection;
|
|
28
|
+
function parse(input, target) {
|
|
29
|
+
/** Add dot before brackets which is required to split fields */
|
|
30
|
+
input = input.replace(NO_DOT_BRACKET_PATTERN, s => {
|
|
31
|
+
return s.charAt(0) + '.' + s.substring(1);
|
|
32
|
+
});
|
|
33
|
+
const fields = (0, fast_tokenizer_1.splitString)(input, {
|
|
34
|
+
delimiters: '.',
|
|
35
|
+
brackets: true,
|
|
36
|
+
keepBrackets: false,
|
|
37
|
+
});
|
|
38
|
+
for (let i = 0; i < fields.length; i++) {
|
|
39
|
+
const f = fields[i];
|
|
40
|
+
if (f.includes(',')) {
|
|
41
|
+
const subFields = (0, fast_tokenizer_1.splitString)(f, {
|
|
42
|
+
delimiters: ',',
|
|
43
|
+
brackets: true,
|
|
44
|
+
keepBrackets: true,
|
|
45
|
+
});
|
|
46
|
+
for (const n of subFields) {
|
|
47
|
+
parse(n, target);
|
|
48
|
+
}
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
const m = FIELD_PATTERN.exec(f);
|
|
52
|
+
/* istanbul ignore next */
|
|
53
|
+
if (!m)
|
|
54
|
+
throw new TypeError(`Invalid field path (${input})`);
|
|
55
|
+
const fieldName = m[2];
|
|
56
|
+
const treeItem = (target[fieldName] = target[fieldName] || new FieldsProjection.Item());
|
|
57
|
+
if (m[1])
|
|
58
|
+
treeItem.sign = m[1];
|
|
59
|
+
if (i === fields.length - 1) {
|
|
60
|
+
delete treeItem.projection;
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
target = treeItem.projection = treeItem.projection || new FieldsProjection();
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
package/esm/index.js
CHANGED
|
@@ -28,4 +28,5 @@ export * from './orm/decorators/link.decorator.js';
|
|
|
28
28
|
export * from './orm/decorators/primarykey.decorator.js';
|
|
29
29
|
export * from './orm/decorators/transform.decorator.js';
|
|
30
30
|
export { isColumnField, isEmbeddedField, isAssociationField, isEntityClass } from './orm/util/orm.helper.js';
|
|
31
|
+
export * from './orm/util/parse-fields-projection.js';
|
|
31
32
|
export * from './orm/backward.js';
|
|
@@ -47,7 +47,7 @@ export async function joinAssociation(joinInfos, association, parentAlias, inner
|
|
|
47
47
|
}
|
|
48
48
|
export async function prepareFilter(entityDef, filter, trgOp, tableAlias = 'T') {
|
|
49
49
|
let srcOp;
|
|
50
|
-
if (isLogicalOperator(filter))
|
|
50
|
+
if (isLogicalOperator(filter) && filter._operatorType === trgOp._operatorType)
|
|
51
51
|
srcOp = filter;
|
|
52
52
|
else {
|
|
53
53
|
srcOp = And();
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { And, In, Param, Select } from '@sqb/builder';
|
|
2
|
-
import { Entity } from '../decorators/entity.decorator.js';
|
|
3
2
|
import { AssociationNode } from '../model/association-node.js';
|
|
4
3
|
import { EmbeddedFieldMetadata } from '../model/embedded-field-metadata.js';
|
|
5
4
|
import { EntityMetadata } from '../model/entity-metadata.js';
|
|
6
5
|
import { isAssociationField, isColumnField, isEmbeddedField } from '../util/orm.helper.js';
|
|
6
|
+
import { parseFieldsProjection } from '../util/parse-fields-projection.js';
|
|
7
7
|
import { joinAssociationGetLast, prepareFilter } from './command.helper.js';
|
|
8
8
|
import { RowConverter } from './row-converter.js';
|
|
9
9
|
const SORT_ORDER_PATTERN = /^([-+])?(.*)$/;
|
|
@@ -53,9 +53,7 @@ export class FindCommand {
|
|
|
53
53
|
maxEagerFetch: args.maxEagerFetch,
|
|
54
54
|
});
|
|
55
55
|
await command.addFields({
|
|
56
|
-
|
|
57
|
-
include: args.include,
|
|
58
|
-
omit: args.omit,
|
|
56
|
+
projection: args.projection,
|
|
59
57
|
sort: args.sort,
|
|
60
58
|
});
|
|
61
59
|
if (args.filter)
|
|
@@ -68,22 +66,10 @@ export class FindCommand {
|
|
|
68
66
|
const tableAlias = opts.tableAlias || this.resultAlias;
|
|
69
67
|
const entity = opts.entity || this._getEntityFromAlias(tableAlias);
|
|
70
68
|
const converter = opts.converter || this.converter;
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
if (_pick)
|
|
76
|
-
requestedFields = [..._pick];
|
|
77
|
-
else {
|
|
78
|
-
requestedFields = Entity.getFieldNames(entity.ctor).reduce((a, x) => {
|
|
79
|
-
const f = Entity.getField(entity.ctor, x);
|
|
80
|
-
if (f && !f.exclusive)
|
|
81
|
-
a.push(x.toLowerCase());
|
|
82
|
-
return a;
|
|
83
|
-
}, []);
|
|
84
|
-
}
|
|
85
|
-
if (_include)
|
|
86
|
-
requestedFields.push(..._include);
|
|
69
|
+
const projection = typeof opts.projection === 'string' || Array.isArray(opts.projection)
|
|
70
|
+
? parseFieldsProjection(opts.projection)
|
|
71
|
+
: opts.projection;
|
|
72
|
+
const defaultFields = !projection || !Object.values(projection).find(p => !p.sign);
|
|
87
73
|
const sortFields = opts.sort && opts.sort.length ? opts.sort.map(x => x.toLowerCase()) : undefined;
|
|
88
74
|
const prefix = opts.prefix || '';
|
|
89
75
|
const suffix = opts.suffix || '';
|
|
@@ -92,12 +78,16 @@ export class FindCommand {
|
|
|
92
78
|
if (!col || col.hidden)
|
|
93
79
|
continue;
|
|
94
80
|
const colNameLower = col.name.toLowerCase();
|
|
95
|
-
|
|
96
|
-
if (
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
81
|
+
const p = projection?.[colNameLower];
|
|
82
|
+
if (
|
|
83
|
+
/** Ignore if field is omitted */
|
|
84
|
+
p?.sign === '-' ||
|
|
85
|
+
/** Ignore if default fields and field is not in projection */
|
|
86
|
+
(!defaultFields && !p) ||
|
|
87
|
+
/** Ignore if default fields enabled and fields is exclusive */
|
|
88
|
+
(defaultFields && col.exclusive && !p)) {
|
|
100
89
|
continue;
|
|
90
|
+
}
|
|
101
91
|
// Add field to select list if field is a column
|
|
102
92
|
if (isColumnField(col)) {
|
|
103
93
|
const fieldAlias = this._selectColumn(tableAlias, col, prefix, suffix);
|
|
@@ -122,9 +112,7 @@ export class FindCommand {
|
|
|
122
112
|
entity: typ,
|
|
123
113
|
prefix: col.fieldNamePrefix,
|
|
124
114
|
suffix: col.fieldNameSuffix,
|
|
125
|
-
|
|
126
|
-
include: extractSubFields(colNameLower, _include),
|
|
127
|
-
omit: extractSubFields(colNameLower, _omit),
|
|
115
|
+
projection: p?.projection,
|
|
128
116
|
sort: extractSubFields(colNameLower, sortFields),
|
|
129
117
|
});
|
|
130
118
|
continue;
|
|
@@ -142,9 +130,7 @@ export class FindCommand {
|
|
|
142
130
|
tableAlias: joinInfo.joinAlias,
|
|
143
131
|
converter: subConverter,
|
|
144
132
|
entity: joinInfo.targetEntity,
|
|
145
|
-
|
|
146
|
-
include: extractSubFields(colNameLower, _include),
|
|
147
|
-
omit: extractSubFields(colNameLower, _omit),
|
|
133
|
+
projection: p?.projection,
|
|
148
134
|
sort: extractSubFields(colNameLower, sortFields),
|
|
149
135
|
});
|
|
150
136
|
continue;
|
|
@@ -164,9 +150,7 @@ export class FindCommand {
|
|
|
164
150
|
await findCommand.filter(In(targetCol.name, Param(parentField)));
|
|
165
151
|
const sort = sortFields && extractSubFields(colNameLower, sortFields);
|
|
166
152
|
await findCommand.addFields({
|
|
167
|
-
|
|
168
|
-
include: extractSubFields(colNameLower, _include),
|
|
169
|
-
omit: extractSubFields(colNameLower, _omit),
|
|
153
|
+
projection: p?.projection,
|
|
170
154
|
sort,
|
|
171
155
|
});
|
|
172
156
|
if (sort)
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { EntityMetadata } from '../model/entity-metadata.js';
|
|
2
|
+
import { DECORATOR_FACTORY } from '../orm.const.js';
|
|
2
3
|
export function Column(arg0) {
|
|
4
|
+
return Column[DECORATOR_FACTORY](arg0);
|
|
5
|
+
}
|
|
6
|
+
Column[DECORATOR_FACTORY] = function (arg0) {
|
|
3
7
|
return (target, propertyKey) => {
|
|
4
8
|
if (typeof propertyKey !== 'string')
|
|
5
9
|
throw new Error('Symbol properties are not accepted');
|
|
@@ -16,4 +20,4 @@ export function Column(arg0) {
|
|
|
16
20
|
}
|
|
17
21
|
EntityMetadata.defineColumnField(entity, propertyKey, options);
|
|
18
22
|
};
|
|
19
|
-
}
|
|
23
|
+
};
|
package/esm/orm/orm.const.js
CHANGED
|
@@ -38,15 +38,16 @@ export class Repository extends TypedEventEmitterClass(AsyncEventEmitter) {
|
|
|
38
38
|
return this._exists(keyValue, { ...options, connection });
|
|
39
39
|
}, options);
|
|
40
40
|
}
|
|
41
|
+
existsOne(options) {
|
|
42
|
+
return this._execute(async (connection) => {
|
|
43
|
+
return this._existsOne({ ...options, connection });
|
|
44
|
+
}, options);
|
|
45
|
+
}
|
|
41
46
|
count(options) {
|
|
42
47
|
return this._execute(async (connection) => {
|
|
43
48
|
return this._count({ ...options, connection });
|
|
44
49
|
}, options);
|
|
45
50
|
}
|
|
46
|
-
/** @deprecated - Use findById instead */
|
|
47
|
-
find(keyValue, options) {
|
|
48
|
-
return this.findById(keyValue, options);
|
|
49
|
-
}
|
|
50
51
|
findById(keyValue, options) {
|
|
51
52
|
return this._execute(async (connection) => {
|
|
52
53
|
return this._find(keyValue, { ...options, connection });
|
|
@@ -129,11 +130,25 @@ export class Repository extends TypedEventEmitterClass(AsyncEventEmitter) {
|
|
|
129
130
|
else
|
|
130
131
|
filter.push(options.filter);
|
|
131
132
|
}
|
|
132
|
-
return
|
|
133
|
+
return this._existsOne({
|
|
134
|
+
...options,
|
|
135
|
+
filter,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
async _existsOne(options) {
|
|
139
|
+
const filter = [];
|
|
140
|
+
if (options && options.filter) {
|
|
141
|
+
if (Array.isArray(options.filter))
|
|
142
|
+
filter.push(...options.filter);
|
|
143
|
+
else
|
|
144
|
+
filter.push(options.filter);
|
|
145
|
+
}
|
|
146
|
+
const resp = await FindCommand.execute({
|
|
133
147
|
...options,
|
|
134
148
|
filter,
|
|
135
149
|
entity: this._entity,
|
|
136
|
-
})
|
|
150
|
+
});
|
|
151
|
+
return resp.length > 0;
|
|
137
152
|
}
|
|
138
153
|
async _count(options) {
|
|
139
154
|
return CountCommand.execute({
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { splitString } from 'fast-tokenizer';
|
|
2
|
+
const FIELD_PATTERN = /^([+-])?([a-z_$]\w*)$/i;
|
|
3
|
+
const NO_DOT_BRACKET_PATTERN = /[^.]\(/g;
|
|
4
|
+
export class FieldsProjection {
|
|
5
|
+
}
|
|
6
|
+
(function (FieldsProjection) {
|
|
7
|
+
class Item {
|
|
8
|
+
}
|
|
9
|
+
FieldsProjection.Item = Item;
|
|
10
|
+
})(FieldsProjection || (FieldsProjection = {}));
|
|
11
|
+
export function parseFieldsProjection(projection, keepCase) {
|
|
12
|
+
const arr = Array.isArray(projection) ? projection : [projection];
|
|
13
|
+
if (!(arr && arr.length))
|
|
14
|
+
return;
|
|
15
|
+
const out = new FieldsProjection();
|
|
16
|
+
for (let s of arr) {
|
|
17
|
+
if (!keepCase)
|
|
18
|
+
s = s.toLowerCase();
|
|
19
|
+
parse(s, out);
|
|
20
|
+
}
|
|
21
|
+
return out;
|
|
22
|
+
}
|
|
23
|
+
function parse(input, target) {
|
|
24
|
+
/** Add dot before brackets which is required to split fields */
|
|
25
|
+
input = input.replace(NO_DOT_BRACKET_PATTERN, s => {
|
|
26
|
+
return s.charAt(0) + '.' + s.substring(1);
|
|
27
|
+
});
|
|
28
|
+
const fields = splitString(input, {
|
|
29
|
+
delimiters: '.',
|
|
30
|
+
brackets: true,
|
|
31
|
+
keepBrackets: false,
|
|
32
|
+
});
|
|
33
|
+
for (let i = 0; i < fields.length; i++) {
|
|
34
|
+
const f = fields[i];
|
|
35
|
+
if (f.includes(',')) {
|
|
36
|
+
const subFields = splitString(f, {
|
|
37
|
+
delimiters: ',',
|
|
38
|
+
brackets: true,
|
|
39
|
+
keepBrackets: true,
|
|
40
|
+
});
|
|
41
|
+
for (const n of subFields) {
|
|
42
|
+
parse(n, target);
|
|
43
|
+
}
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
const m = FIELD_PATTERN.exec(f);
|
|
47
|
+
/* istanbul ignore next */
|
|
48
|
+
if (!m)
|
|
49
|
+
throw new TypeError(`Invalid field path (${input})`);
|
|
50
|
+
const fieldName = m[2];
|
|
51
|
+
const treeItem = (target[fieldName] = target[fieldName] || new FieldsProjection.Item());
|
|
52
|
+
if (m[1])
|
|
53
|
+
treeItem.sign = m[1];
|
|
54
|
+
if (i === fields.length - 1) {
|
|
55
|
+
delete treeItem.projection;
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
target = treeItem.projection = treeItem.projection || new FieldsProjection();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sqb/connect",
|
|
3
3
|
"description": "Multi-dialect database connection framework written with TypeScript",
|
|
4
|
-
"version": "4.12.
|
|
4
|
+
"version": "4.12.1",
|
|
5
5
|
"author": "Panates",
|
|
6
6
|
"contributors": [
|
|
7
7
|
"Eray Hanoglu <e.hanoglu@panates.com>",
|
|
@@ -25,16 +25,18 @@
|
|
|
25
25
|
"build:esm": "tsc -b tsconfig-build-esm.json",
|
|
26
26
|
"postbuild": "cp README.md package.json ../../LICENSE ../../build/connect && cp ../../package.cjs.json ../../build/connect/cjs/package.json",
|
|
27
27
|
"lint": "eslint . --max-warnings=0",
|
|
28
|
+
"lint:fix": "eslint . --max-warnings=0 --fix",
|
|
29
|
+
"format": "prettier . --write --log-level=warn",
|
|
28
30
|
"test": "jest",
|
|
29
31
|
"cover": "jest --collect-coverage",
|
|
30
32
|
"clean": "npm run clean:src | npm run clean:dist | npm run clean:cover",
|
|
31
33
|
"clean:src": "ts-cleanup -s src --all",
|
|
32
34
|
"clean:dist": "rimraf ../../build/connectt",
|
|
33
|
-
"clean:cover": "rimraf ../../coverage/connect"
|
|
34
|
-
"format": "prettier . --write --log-level=warn"
|
|
35
|
+
"clean:cover": "rimraf ../../coverage/connect"
|
|
35
36
|
},
|
|
36
37
|
"dependencies": {
|
|
37
38
|
"debug": "^4.3.5",
|
|
39
|
+
"fast-tokenizer": "^1.3.0",
|
|
38
40
|
"lightning-pool": "^4.2.2",
|
|
39
41
|
"lodash": "^4.17.21",
|
|
40
42
|
"power-tasks": "^1.7.3",
|
|
@@ -47,10 +49,11 @@
|
|
|
47
49
|
},
|
|
48
50
|
"devDependencies": {
|
|
49
51
|
"@types/debug": "^4.1.12",
|
|
50
|
-
"@types/lodash": "^4.17.
|
|
52
|
+
"@types/lodash": "^4.17.5",
|
|
53
|
+
"postgresql-client": "^2.11.2"
|
|
51
54
|
},
|
|
52
55
|
"peerDependencies": {
|
|
53
|
-
"@sqb/builder": "^4.12.
|
|
56
|
+
"@sqb/builder": "^4.12.1",
|
|
54
57
|
"reflect-metadata": "^0.2.2"
|
|
55
58
|
},
|
|
56
59
|
"engines": {
|
package/types/index.d.ts
CHANGED
|
@@ -28,4 +28,5 @@ export * from './orm/decorators/link.decorator.js';
|
|
|
28
28
|
export * from './orm/decorators/primarykey.decorator.js';
|
|
29
29
|
export * from './orm/decorators/transform.decorator.js';
|
|
30
30
|
export { isColumnField, isEmbeddedField, isAssociationField, isEntityClass } from './orm/util/orm.helper.js';
|
|
31
|
+
export * from './orm/util/parse-fields-projection.js';
|
|
31
32
|
export * from './orm/backward.js';
|
|
@@ -2,6 +2,7 @@ import { SqbConnection } from '../../client/sqb-connection.js';
|
|
|
2
2
|
import { AssociationNode } from '../model/association-node.js';
|
|
3
3
|
import { EntityMetadata } from '../model/entity-metadata.js';
|
|
4
4
|
import { Repository } from '../repository.class.js';
|
|
5
|
+
import { FieldsProjection } from '../util/parse-fields-projection.js';
|
|
5
6
|
import { RowConverter } from './row-converter.js';
|
|
6
7
|
export type FindCommandArgs = {
|
|
7
8
|
entity: EntityMetadata;
|
|
@@ -29,9 +30,7 @@ export declare class FindCommand {
|
|
|
29
30
|
tableAlias?: string;
|
|
30
31
|
converter?: RowConverter;
|
|
31
32
|
entity?: EntityMetadata;
|
|
32
|
-
|
|
33
|
-
omit?: string[];
|
|
34
|
-
include?: string[];
|
|
33
|
+
projection?: FieldsProjection | string | string[];
|
|
35
34
|
sort?: string[];
|
|
36
35
|
prefix?: string;
|
|
37
36
|
suffix?: string;
|
|
@@ -2,3 +2,4 @@ import { DataType } from '@sqb/builder';
|
|
|
2
2
|
import { ColumnFieldOptions } from '../model/column-field-metadata.js';
|
|
3
3
|
export declare function Column(type?: DataType): PropertyDecorator;
|
|
4
4
|
export declare function Column(options?: ColumnFieldOptions): PropertyDecorator;
|
|
5
|
+
export declare namespace Column { }
|
|
@@ -10,7 +10,7 @@ export interface FieldMetadata {
|
|
|
10
10
|
hidden?: boolean;
|
|
11
11
|
/**
|
|
12
12
|
* Indicates whether or not to include this field by default when making queries.
|
|
13
|
-
* If this set to "true" the field must be requested using "
|
|
13
|
+
* If this set to "true" the field must be requested using "projection" option.
|
|
14
14
|
*/
|
|
15
15
|
exclusive?: boolean;
|
|
16
16
|
}
|
package/types/orm/orm.const.d.ts
CHANGED
|
@@ -6,9 +6,7 @@ import { SqbConnection } from '../client/sqb-connection.js';
|
|
|
6
6
|
import { QueryRequest, TransactionFunction } from '../client/types.js';
|
|
7
7
|
import { EntityMetadata } from './model/entity-metadata.js';
|
|
8
8
|
interface Projection {
|
|
9
|
-
|
|
10
|
-
omit?: string[];
|
|
11
|
-
include?: string[];
|
|
9
|
+
projection?: string | string[];
|
|
12
10
|
}
|
|
13
11
|
interface Filtering {
|
|
14
12
|
filter?: LogicalOperator | LogicalOperator[] | object | object[];
|
|
@@ -31,7 +29,7 @@ export declare namespace Repository {
|
|
|
31
29
|
}
|
|
32
30
|
interface FindOptions extends CommandOptions, Projection, Filtering {
|
|
33
31
|
}
|
|
34
|
-
interface FindOneOptions extends
|
|
32
|
+
interface FindOneOptions extends FindOptions {
|
|
35
33
|
sort?: string[];
|
|
36
34
|
offset?: number;
|
|
37
35
|
}
|
|
@@ -44,6 +42,8 @@ export declare namespace Repository {
|
|
|
44
42
|
}
|
|
45
43
|
interface UpdateOptions extends CommandOptions, Projection, Filtering {
|
|
46
44
|
}
|
|
45
|
+
interface UpdateOnlyOptions extends CommandOptions, Filtering {
|
|
46
|
+
}
|
|
47
47
|
interface UpdateManyOptions extends CommandOptions, Filtering {
|
|
48
48
|
}
|
|
49
49
|
}
|
|
@@ -63,16 +63,15 @@ export declare class Repository<T> extends Repository_base {
|
|
|
63
63
|
create(values: PartialDTO<T>, options?: Repository.CreateOptions): Promise<PartialDTO<T>>;
|
|
64
64
|
createOnly(values: PartialDTO<T>, options?: StrictOmit<Repository.CreateOptions, keyof Projection>): Promise<void>;
|
|
65
65
|
exists(keyValue: any | Record<string, any>, options?: Repository.ExistsOptions): Promise<boolean>;
|
|
66
|
+
existsOne(options?: Repository.ExistsOptions): Promise<boolean>;
|
|
66
67
|
count(options?: Repository.CountOptions): Promise<number>;
|
|
67
|
-
/** @deprecated - Use findById instead */
|
|
68
|
-
find(keyValue: any | Record<string, any>, options?: Repository.FindOptions): Promise<PartialDTO<T> | undefined>;
|
|
69
68
|
findById(keyValue: any | Record<string, any>, options?: Repository.FindOptions): Promise<PartialDTO<T> | undefined>;
|
|
70
69
|
findOne(options?: Repository.FindOneOptions): Promise<PartialDTO<T> | undefined>;
|
|
71
70
|
findMany(options?: Repository.FindManyOptions): Promise<PartialDTO<T>[]>;
|
|
72
71
|
delete(keyValue: any | Record<string, any>, options?: Repository.DeleteOptions): Promise<boolean>;
|
|
73
72
|
deleteMany(options?: Repository.DeleteManyOptions): Promise<number>;
|
|
74
73
|
update(keyValue: any | Record<string, any>, values: PatchDTO<T>, options?: Repository.UpdateOptions): Promise<PartialDTO<T> | undefined>;
|
|
75
|
-
updateOnly(keyValue: any | Record<string, any>, values: PatchDTO<T>, options?:
|
|
74
|
+
updateOnly(keyValue: any | Record<string, any>, values: PatchDTO<T>, options?: Repository.UpdateOnlyOptions): Promise<boolean>;
|
|
76
75
|
updateMany(values: PartialDTO<T>, options?: Repository.UpdateManyOptions): Promise<number>;
|
|
77
76
|
protected _execute(fn: TransactionFunction, opts?: Repository.CommandOptions): Promise<any>;
|
|
78
77
|
protected _create(values: PartialDTO<T>, options: Repository.CreateOptions & {
|
|
@@ -82,6 +81,9 @@ export declare class Repository<T> extends Repository_base {
|
|
|
82
81
|
protected _exists(keyValue: any | Record<string, any>, options: Repository.ExistsOptions & {
|
|
83
82
|
connection: SqbConnection;
|
|
84
83
|
}): Promise<boolean>;
|
|
84
|
+
protected _existsOne(options: Repository.ExistsOptions & {
|
|
85
|
+
connection: SqbConnection;
|
|
86
|
+
}): Promise<boolean>;
|
|
85
87
|
protected _count(options: Repository.CountOptions & {
|
|
86
88
|
connection: SqbConnection;
|
|
87
89
|
}): Promise<number>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare class FieldsProjection {
|
|
2
|
+
[key: string]: FieldsProjection.Item;
|
|
3
|
+
}
|
|
4
|
+
export declare namespace FieldsProjection {
|
|
5
|
+
class Item {
|
|
6
|
+
sign?: string;
|
|
7
|
+
projection?: FieldsProjection;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
export declare function parseFieldsProjection(projection: string | string[], keepCase?: boolean): FieldsProjection | undefined;
|