@sqb/connect 4.19.4 → 4.19.6
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 +7 -7
- package/cjs/client/cursor.js +3 -1
- package/cjs/client/helpers.js +8 -2
- package/cjs/client/sqb-client.js +5 -1
- package/cjs/orm/commands/command.helper.js +2 -1
- package/cjs/orm/commands/create.command.js +4 -1
- package/cjs/orm/commands/find.command.js +6 -2
- package/cjs/orm/commands/row-converter.js +3 -1
- package/cjs/orm/decorators/column.decorator.js +3 -1
- package/cjs/orm/decorators/entity.decorator.js +3 -1
- package/cjs/orm/model/association.js +16 -4
- package/cjs/orm/model/entity-metadata.js +4 -1
- package/cjs/orm/repository.class.js +10 -2
- package/cjs/orm/util/apply-mixins.js +2 -1
- package/cjs/orm/util/parse-fields-projection.js +4 -2
- package/cjs/orm/util/serialize-field.js +10 -3
- package/esm/client/cursor.js +4 -2
- package/esm/client/helpers.js +8 -2
- package/esm/client/sqb-client.js +6 -2
- package/esm/client/sqb-connection.js +2 -2
- package/esm/index.js +1 -1
- package/esm/orm/commands/command.helper.js +3 -2
- package/esm/orm/commands/create.command.js +4 -1
- package/esm/orm/commands/find.command.js +9 -5
- package/esm/orm/commands/row-converter.js +3 -1
- package/esm/orm/decorators/column.decorator.js +3 -1
- package/esm/orm/decorators/entity.decorator.js +4 -2
- package/esm/orm/model/association.js +16 -4
- package/esm/orm/model/entity-metadata.js +8 -5
- package/esm/orm/repository.class.js +10 -2
- package/esm/orm/util/apply-mixins.js +2 -1
- package/esm/orm/util/parse-fields-projection.js +4 -2
- package/esm/orm/util/serialize-field.js +10 -3
- package/package.json +8 -5
- package/types/index.d.cts +1 -1
- package/types/index.d.ts +1 -1
- package/types/orm/commands/command.helper.d.ts +1 -0
package/README.md
CHANGED
|
@@ -18,12 +18,12 @@ SQB is an extensible, multi-dialect SQL query builder and Database connection wr
|
|
|
18
18
|
|
|
19
19
|
## Main goals
|
|
20
20
|
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
-
|
|
21
|
+
- Single code base for any sql based database
|
|
22
|
+
- Powerful and simplified query coding scheme
|
|
23
|
+
- Fast applications with low memory requirements
|
|
24
|
+
- Let applications work with large data tables efficiently
|
|
25
|
+
- Support latest JavaScript language standards
|
|
26
|
+
- Lightweight and extensible framework.
|
|
27
27
|
|
|
28
28
|
You can report bugs and discuss features on the [GitHub issues](https://github.com/sqbjs/sqb/issues) page
|
|
29
29
|
|
|
@@ -39,7 +39,7 @@ $ npm install @sqb/connect --save
|
|
|
39
39
|
|
|
40
40
|
## Node Compatibility
|
|
41
41
|
|
|
42
|
-
-
|
|
42
|
+
- node >= 16.x
|
|
43
43
|
|
|
44
44
|
### License
|
|
45
45
|
|
package/cjs/client/cursor.js
CHANGED
|
@@ -195,7 +195,9 @@ class Cursor extends (0, strict_typed_events_1.TypedEventEmitterClass)(strict_ty
|
|
|
195
195
|
if (_this.isEof)
|
|
196
196
|
return;
|
|
197
197
|
/* Seek cache */
|
|
198
|
-
while (step > 0 &&
|
|
198
|
+
while (step > 0 &&
|
|
199
|
+
_this._cache &&
|
|
200
|
+
(_this._row = _this._cache.next())) {
|
|
199
201
|
_this._rowNum++;
|
|
200
202
|
step--;
|
|
201
203
|
}
|
package/cjs/client/helpers.js
CHANGED
|
@@ -49,10 +49,16 @@ function wrapAdapterFields(oldFields, fieldNaming) {
|
|
|
49
49
|
return result;
|
|
50
50
|
}
|
|
51
51
|
function normalizeRowsToObjectRows(fields, rowType, oldRows, options) {
|
|
52
|
-
return normalizeRows(fields, rowType, oldRows, {
|
|
52
|
+
return normalizeRows(fields, rowType, oldRows, {
|
|
53
|
+
...options,
|
|
54
|
+
objectRows: true,
|
|
55
|
+
});
|
|
53
56
|
}
|
|
54
57
|
function normalizeRowsToArrayRows(fields, rowType, oldRows, options) {
|
|
55
|
-
return normalizeRows(fields, rowType, oldRows, {
|
|
58
|
+
return normalizeRows(fields, rowType, oldRows, {
|
|
59
|
+
...options,
|
|
60
|
+
objectRows: false,
|
|
61
|
+
});
|
|
56
62
|
}
|
|
57
63
|
function normalizeRows(fields, rowType, oldRows, options) {
|
|
58
64
|
const ignoreNulls = options.ignoreNulls && options.objectRows;
|
package/cjs/client/sqb-client.js
CHANGED
|
@@ -159,7 +159,11 @@ class SqbClient extends (0, strict_typed_events_1.TypedEventEmitterClass)(strict
|
|
|
159
159
|
return this._entities[name];
|
|
160
160
|
}
|
|
161
161
|
toString() {
|
|
162
|
-
return '[object ' +
|
|
162
|
+
return ('[object ' +
|
|
163
|
+
Object.getPrototypeOf(this).constructor.name +
|
|
164
|
+
'(' +
|
|
165
|
+
this.dialect +
|
|
166
|
+
')]');
|
|
163
167
|
}
|
|
164
168
|
[inspect]() {
|
|
165
169
|
return this.toString();
|
|
@@ -21,7 +21,7 @@ async function joinAssociation(joinInfos, association, parentAlias, innerJoin) {
|
|
|
21
21
|
let node = association;
|
|
22
22
|
const result = [];
|
|
23
23
|
while (node) {
|
|
24
|
-
joinInfo = joinInfos.find(j => j.association === node);
|
|
24
|
+
joinInfo = joinInfos.find(j => j.association === node && j.parentAlias === parentAlias);
|
|
25
25
|
if (!joinInfo) {
|
|
26
26
|
const targetEntity = await node.resolveTarget();
|
|
27
27
|
const sourceEntity = await node.resolveSource();
|
|
@@ -38,6 +38,7 @@ async function joinAssociation(joinInfos, association, parentAlias, innerJoin) {
|
|
|
38
38
|
association: node,
|
|
39
39
|
sourceEntity,
|
|
40
40
|
targetEntity,
|
|
41
|
+
parentAlias,
|
|
41
42
|
joinAlias,
|
|
42
43
|
join,
|
|
43
44
|
};
|
|
@@ -58,7 +58,10 @@ class CreateCommand {
|
|
|
58
58
|
if (col.noInsert)
|
|
59
59
|
continue;
|
|
60
60
|
if (v == null && col.default !== undefined) {
|
|
61
|
-
v =
|
|
61
|
+
v =
|
|
62
|
+
typeof col.default === 'function'
|
|
63
|
+
? col.default(values)
|
|
64
|
+
: col.default;
|
|
62
65
|
}
|
|
63
66
|
if (typeof col.serialize === 'function')
|
|
64
67
|
v = col.serialize(v, col.name);
|
|
@@ -73,7 +73,9 @@ class FindCommand {
|
|
|
73
73
|
? (0, parse_fields_projection_js_1.parseFieldsProjection)(opts.projection)
|
|
74
74
|
: opts.projection;
|
|
75
75
|
const defaultFields = !projection || !Object.values(projection).find(p => !p.sign);
|
|
76
|
-
const sortFields = opts.sort && opts.sort.length
|
|
76
|
+
const sortFields = opts.sort && opts.sort.length
|
|
77
|
+
? opts.sort.map(x => x.toLowerCase())
|
|
78
|
+
: undefined;
|
|
77
79
|
const prefix = opts.prefix || '';
|
|
78
80
|
const suffix = opts.suffix || '';
|
|
79
81
|
for (const key of Object.keys(entity.fields)) {
|
|
@@ -173,7 +175,9 @@ class FindCommand {
|
|
|
173
175
|
}
|
|
174
176
|
}
|
|
175
177
|
_selectColumn(tableAlias, el, prefix, suffix) {
|
|
176
|
-
const fieldName = (prefix || '').toLowerCase() +
|
|
178
|
+
const fieldName = (prefix || '').toLowerCase() +
|
|
179
|
+
el.fieldName.toUpperCase() +
|
|
180
|
+
(suffix || '').toLowerCase();
|
|
177
181
|
const fieldAlias = (tableAlias + '_' + fieldName).substring(0, 30);
|
|
178
182
|
this._selectColumns[fieldAlias] = {
|
|
179
183
|
field: el,
|
|
@@ -135,7 +135,9 @@ class RowConverter {
|
|
|
135
135
|
fld = fld || _fields.get('' + p.keyField);
|
|
136
136
|
const keyValue = fld && row[fld.index];
|
|
137
137
|
if (keyValue != null) {
|
|
138
|
-
const keyValues = Array.isArray(keyValue)
|
|
138
|
+
const keyValues = Array.isArray(keyValue)
|
|
139
|
+
? keyValue
|
|
140
|
+
: [keyValue];
|
|
139
141
|
keyValues.forEach(k => {
|
|
140
142
|
let arr = map.get(k);
|
|
141
143
|
if (!arr) {
|
|
@@ -22,7 +22,9 @@ Column[orm_const_js_1.DECORATOR_FACTORY] = function (arg0) {
|
|
|
22
22
|
else
|
|
23
23
|
options.type = typ;
|
|
24
24
|
}
|
|
25
|
-
if (!options.dataType &&
|
|
25
|
+
if (!options.dataType &&
|
|
26
|
+
typeof options.type === 'function' &&
|
|
27
|
+
entity_metadata_js_1.EntityMetadata.get(options.type)) {
|
|
26
28
|
options.dataType = builder_1.DataType.JSON;
|
|
27
29
|
}
|
|
28
30
|
entity_metadata_js_1.EntityMetadata.defineColumnField(entity, propertyKey, options);
|
|
@@ -167,7 +167,9 @@ function applyConstructorProperties(target, sourceClass, constructorArgs, isProp
|
|
|
167
167
|
for (const key of keys) {
|
|
168
168
|
const srcDesc = Object.getOwnPropertyDescriptor(tempInstance, key);
|
|
169
169
|
const trgDesc = Object.getOwnPropertyDescriptor(target, key);
|
|
170
|
-
if (!srcDesc ||
|
|
170
|
+
if (!srcDesc ||
|
|
171
|
+
trgDesc ||
|
|
172
|
+
(isPropertyInherited && !isPropertyInherited(key)))
|
|
171
173
|
continue;
|
|
172
174
|
Object.defineProperty(target, key, srcDesc);
|
|
173
175
|
}
|
|
@@ -79,11 +79,17 @@ class Association {
|
|
|
79
79
|
if (this.many) {
|
|
80
80
|
if (!sourceKey) {
|
|
81
81
|
const primaryIndexColumns = entity_metadata_js_1.EntityMetadata.getPrimaryIndexColumns(source);
|
|
82
|
-
sourceKey =
|
|
82
|
+
sourceKey =
|
|
83
|
+
primaryIndexColumns && primaryIndexColumns.length === 1
|
|
84
|
+
? primaryIndexColumns[0].name
|
|
85
|
+
: 'id';
|
|
83
86
|
}
|
|
84
87
|
if (!targetKey && sourceKey) {
|
|
85
88
|
// snake-case
|
|
86
|
-
let s = source.name[0].toLowerCase() +
|
|
89
|
+
let s = source.name[0].toLowerCase() +
|
|
90
|
+
source.name.substring(1) +
|
|
91
|
+
'_' +
|
|
92
|
+
sourceKey;
|
|
87
93
|
if (!entity_metadata_js_1.EntityMetadata.getColumnField(target, s))
|
|
88
94
|
s = (0, putil_varhelpers_1.camelCase)(s);
|
|
89
95
|
targetKey = s;
|
|
@@ -92,11 +98,17 @@ class Association {
|
|
|
92
98
|
else {
|
|
93
99
|
if (!targetKey) {
|
|
94
100
|
const primaryIndexColumns = entity_metadata_js_1.EntityMetadata.getPrimaryIndexColumns(target);
|
|
95
|
-
targetKey =
|
|
101
|
+
targetKey =
|
|
102
|
+
primaryIndexColumns && primaryIndexColumns.length === 1
|
|
103
|
+
? primaryIndexColumns[0].name
|
|
104
|
+
: 'id';
|
|
96
105
|
}
|
|
97
106
|
if (!sourceKey && targetKey) {
|
|
98
107
|
// snake-case
|
|
99
|
-
let s = target.name[0].toLowerCase() +
|
|
108
|
+
let s = target.name[0].toLowerCase() +
|
|
109
|
+
target.name.substring(1) +
|
|
110
|
+
'_' +
|
|
111
|
+
targetKey;
|
|
100
112
|
if (!entity_metadata_js_1.EntityMetadata.getColumnField(source, s))
|
|
101
113
|
s = (0, putil_varhelpers_1.camelCase)(s);
|
|
102
114
|
sourceKey = s;
|
|
@@ -298,7 +298,10 @@ var EntityMetadata;
|
|
|
298
298
|
derived.foreignKeys = derived.foreignKeys || [];
|
|
299
299
|
for (const fk of base.foreignKeys) {
|
|
300
300
|
if (!fk.sourceKey || hasField(fk.sourceKey)) {
|
|
301
|
-
const newFk = new association_js_1.Association(fk.name, {
|
|
301
|
+
const newFk = new association_js_1.Association(fk.name, {
|
|
302
|
+
...fk,
|
|
303
|
+
source: derived.ctor,
|
|
304
|
+
});
|
|
302
305
|
derived.foreignKeys.push(newFk);
|
|
303
306
|
}
|
|
304
307
|
}
|
|
@@ -29,7 +29,11 @@ class Repository extends (0, strict_typed_events_1.TypedEventEmitterClass)(stric
|
|
|
29
29
|
}
|
|
30
30
|
create(input, options) {
|
|
31
31
|
return this._execute(async (connection) => {
|
|
32
|
-
const keyValue = await this._create(input, {
|
|
32
|
+
const keyValue = await this._create(input, {
|
|
33
|
+
...options,
|
|
34
|
+
connection,
|
|
35
|
+
returning: true,
|
|
36
|
+
});
|
|
33
37
|
const result = keyValue && (await this._find(keyValue, { ...options, connection }));
|
|
34
38
|
if (!result)
|
|
35
39
|
throw new Error('Unable to insert new row');
|
|
@@ -46,7 +50,11 @@ class Repository extends (0, strict_typed_events_1.TypedEventEmitterClass)(stric
|
|
|
46
50
|
*/
|
|
47
51
|
createOnly(input, options) {
|
|
48
52
|
return this._execute(async (connection) => {
|
|
49
|
-
const r = await this._create(input, {
|
|
53
|
+
const r = await this._create(input, {
|
|
54
|
+
...options,
|
|
55
|
+
connection,
|
|
56
|
+
returning: true,
|
|
57
|
+
});
|
|
50
58
|
const primaryIndex = entity_metadata_js_1.EntityMetadata.getPrimaryIndex(this.entity);
|
|
51
59
|
if (!primaryIndex || primaryIndex.columns.length > 1)
|
|
52
60
|
return r;
|
|
@@ -10,6 +10,7 @@ function applyMixins(derivedCtor, baseCtor, filter) {
|
|
|
10
10
|
(filter && !filter(name))) {
|
|
11
11
|
continue;
|
|
12
12
|
}
|
|
13
|
-
Object.defineProperty(derivedCtor.prototype, name, Object.getOwnPropertyDescriptor(baseCtor.prototype, name) ||
|
|
13
|
+
Object.defineProperty(derivedCtor.prototype, name, Object.getOwnPropertyDescriptor(baseCtor.prototype, name) ||
|
|
14
|
+
Object.create(null));
|
|
14
15
|
}
|
|
15
16
|
}
|
|
@@ -51,14 +51,16 @@ function parse(input, target) {
|
|
|
51
51
|
if (!m)
|
|
52
52
|
throw new TypeError(`Invalid field path (${input})`);
|
|
53
53
|
const fieldName = m[2];
|
|
54
|
-
const treeItem = (target[fieldName] =
|
|
54
|
+
const treeItem = (target[fieldName] =
|
|
55
|
+
target[fieldName] || new FieldsProjection.Item());
|
|
55
56
|
if (m[1])
|
|
56
57
|
treeItem.sign = m[1];
|
|
57
58
|
if (i === fields.length - 1) {
|
|
58
59
|
delete treeItem.projection;
|
|
59
60
|
}
|
|
60
61
|
else {
|
|
61
|
-
target = treeItem.projection =
|
|
62
|
+
target = treeItem.projection =
|
|
63
|
+
treeItem.projection || new FieldsProjection();
|
|
62
64
|
}
|
|
63
65
|
}
|
|
64
66
|
}
|
|
@@ -20,19 +20,26 @@ const padZero = (n) => (n < 9 ? '0' : '') + n;
|
|
|
20
20
|
function serializeDataValue(dataType, v) {
|
|
21
21
|
if (v == null)
|
|
22
22
|
return;
|
|
23
|
-
if (v instanceof Date &&
|
|
23
|
+
if (v instanceof Date &&
|
|
24
|
+
(dataType === builder_1.DataType.DATE || dataType === builder_1.DataType.TIMESTAMP)) {
|
|
24
25
|
return (v.getFullYear() +
|
|
25
26
|
'-' +
|
|
26
27
|
padZero(v.getMonth() + 1) +
|
|
27
28
|
'-' +
|
|
28
29
|
padZero(v.getDate()) +
|
|
29
30
|
(dataType === builder_1.DataType.TIMESTAMP
|
|
30
|
-
? 'T' +
|
|
31
|
+
? 'T' +
|
|
32
|
+
padZero(v.getHours()) +
|
|
33
|
+
':' +
|
|
34
|
+
padZero(v.getMinutes()) +
|
|
35
|
+
':' +
|
|
36
|
+
padZero(v.getSeconds())
|
|
31
37
|
: ''));
|
|
32
38
|
}
|
|
33
39
|
if (v instanceof Buffer)
|
|
34
40
|
return v.toString('base64');
|
|
35
|
-
if (typeof v === 'number' &&
|
|
41
|
+
if (typeof v === 'number' &&
|
|
42
|
+
(dataType === builder_1.DataType.SMALLINT || dataType === builder_1.DataType.INTEGER))
|
|
36
43
|
return Math.trunc(v);
|
|
37
44
|
if (typeof v === 'bigint')
|
|
38
45
|
return v.toString();
|
package/esm/client/cursor.js
CHANGED
|
@@ -4,7 +4,7 @@ import { TaskQueue } from 'power-tasks';
|
|
|
4
4
|
import { coerceToInt } from 'putil-varhelpers';
|
|
5
5
|
import { AsyncEventEmitter, TypedEventEmitterClass } from 'strict-typed-events';
|
|
6
6
|
import { CursorStream } from './cursor-stream.js';
|
|
7
|
-
import { callFetchHooks, normalizeRowsToArrayRows, normalizeRowsToObjectRows } from './helpers.js';
|
|
7
|
+
import { callFetchHooks, normalizeRowsToArrayRows, normalizeRowsToObjectRows, } from './helpers.js';
|
|
8
8
|
const debug = _debug('sqb:cursor');
|
|
9
9
|
export class Cursor extends TypedEventEmitterClass(AsyncEventEmitter) {
|
|
10
10
|
constructor(connection, fields, adapterCursor, request) {
|
|
@@ -191,7 +191,9 @@ export class Cursor extends TypedEventEmitterClass(AsyncEventEmitter) {
|
|
|
191
191
|
if (_this.isEof)
|
|
192
192
|
return;
|
|
193
193
|
/* Seek cache */
|
|
194
|
-
while (step > 0 &&
|
|
194
|
+
while (step > 0 &&
|
|
195
|
+
_this._cache &&
|
|
196
|
+
(_this._row = _this._cache.next())) {
|
|
195
197
|
_this._rowNum++;
|
|
196
198
|
step--;
|
|
197
199
|
}
|
package/esm/client/helpers.js
CHANGED
|
@@ -42,10 +42,16 @@ export function wrapAdapterFields(oldFields, fieldNaming) {
|
|
|
42
42
|
return result;
|
|
43
43
|
}
|
|
44
44
|
export function normalizeRowsToObjectRows(fields, rowType, oldRows, options) {
|
|
45
|
-
return normalizeRows(fields, rowType, oldRows, {
|
|
45
|
+
return normalizeRows(fields, rowType, oldRows, {
|
|
46
|
+
...options,
|
|
47
|
+
objectRows: true,
|
|
48
|
+
});
|
|
46
49
|
}
|
|
47
50
|
export function normalizeRowsToArrayRows(fields, rowType, oldRows, options) {
|
|
48
|
-
return normalizeRows(fields, rowType, oldRows, {
|
|
51
|
+
return normalizeRows(fields, rowType, oldRows, {
|
|
52
|
+
...options,
|
|
53
|
+
objectRows: false,
|
|
54
|
+
});
|
|
49
55
|
}
|
|
50
56
|
function normalizeRows(fields, rowType, oldRows, options) {
|
|
51
57
|
const ignoreNulls = options.ignoreNulls && options.objectRows;
|
package/esm/client/sqb-client.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import _debug from 'debug';
|
|
2
|
-
import { createPool, PoolState } from 'lightning-pool';
|
|
2
|
+
import { createPool, PoolState, } from 'lightning-pool';
|
|
3
3
|
import { coerceToBoolean, coerceToInt } from 'putil-varhelpers';
|
|
4
4
|
import { AsyncEventEmitter, TypedEventEmitterClass } from 'strict-typed-events';
|
|
5
5
|
import { EntityMetadata } from '../orm/model/entity-metadata.js';
|
|
@@ -155,7 +155,11 @@ export class SqbClient extends TypedEventEmitterClass(AsyncEventEmitter) {
|
|
|
155
155
|
return this._entities[name];
|
|
156
156
|
}
|
|
157
157
|
toString() {
|
|
158
|
-
return '[object ' +
|
|
158
|
+
return ('[object ' +
|
|
159
|
+
Object.getPrototypeOf(this).constructor.name +
|
|
160
|
+
'(' +
|
|
161
|
+
this.dialect +
|
|
162
|
+
')]');
|
|
159
163
|
}
|
|
160
164
|
[inspect]() {
|
|
161
165
|
return this.toString();
|
|
@@ -2,12 +2,12 @@ import { classes } from '@sqb/builder';
|
|
|
2
2
|
import assert from 'assert';
|
|
3
3
|
import _debug from 'debug';
|
|
4
4
|
import { TaskQueue } from 'power-tasks';
|
|
5
|
-
import { coalesce, coerceToBoolean, coerceToInt, coerceToString } from 'putil-varhelpers';
|
|
5
|
+
import { coalesce, coerceToBoolean, coerceToInt, coerceToString, } from 'putil-varhelpers';
|
|
6
6
|
import { AsyncEventEmitter, TypedEventEmitterClass } from 'strict-typed-events';
|
|
7
7
|
import { EntityMetadata } from '../orm/model/entity-metadata.js';
|
|
8
8
|
import { Repository } from '../orm/repository.class.js';
|
|
9
9
|
import { Cursor } from './cursor.js';
|
|
10
|
-
import { callFetchHooks, normalizeRowsToArrayRows, normalizeRowsToObjectRows, wrapAdapterFields } from './helpers.js';
|
|
10
|
+
import { callFetchHooks, normalizeRowsToArrayRows, normalizeRowsToObjectRows, wrapAdapterFields, } from './helpers.js';
|
|
11
11
|
const debug = _debug('sqb:connection');
|
|
12
12
|
export class SqbConnection extends TypedEventEmitterClass(AsyncEventEmitter) {
|
|
13
13
|
constructor(client, adapterConnection, options) {
|
package/esm/index.js
CHANGED
|
@@ -28,5 +28,5 @@ export * from './orm/model/link-chain.js';
|
|
|
28
28
|
export * from './orm/orm.const.js';
|
|
29
29
|
export * from './orm/orm.type.js';
|
|
30
30
|
export * from './orm/repository.class.js';
|
|
31
|
-
export { isAssociationField, isColumnField, isEmbeddedField, isEntityClass } from './orm/util/orm.helper.js';
|
|
31
|
+
export { isAssociationField, isColumnField, isEmbeddedField, isEntityClass, } from './orm/util/orm.helper.js';
|
|
32
32
|
export * from './orm/util/parse-fields-projection.js';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { And, Eq, Exists, Field, InnerJoin, isCompOperator, isLogicalOperator, LeftOuterJoin, op, OperatorType, Raw, Select, } from '@sqb/builder';
|
|
2
2
|
import { EmbeddedFieldMetadata } from '../model/embedded-field-metadata.js';
|
|
3
3
|
import { EntityMetadata } from '../model/entity-metadata.js';
|
|
4
|
-
import { isAssociationField, isColumnField, isEmbeddedField } from '../util/orm.helper.js';
|
|
4
|
+
import { isAssociationField, isColumnField, isEmbeddedField, } from '../util/orm.helper.js';
|
|
5
5
|
export async function joinAssociationGetFirst(joinInfos, association, parentAlias, innerJoin) {
|
|
6
6
|
const joins = await joinAssociation(joinInfos, association, parentAlias, innerJoin);
|
|
7
7
|
return joins[0];
|
|
@@ -15,7 +15,7 @@ export async function joinAssociation(joinInfos, association, parentAlias, inner
|
|
|
15
15
|
let node = association;
|
|
16
16
|
const result = [];
|
|
17
17
|
while (node) {
|
|
18
|
-
joinInfo = joinInfos.find(j => j.association === node);
|
|
18
|
+
joinInfo = joinInfos.find(j => j.association === node && j.parentAlias === parentAlias);
|
|
19
19
|
if (!joinInfo) {
|
|
20
20
|
const targetEntity = await node.resolveTarget();
|
|
21
21
|
const sourceEntity = await node.resolveSource();
|
|
@@ -32,6 +32,7 @@ export async function joinAssociation(joinInfos, association, parentAlias, inner
|
|
|
32
32
|
association: node,
|
|
33
33
|
sourceEntity,
|
|
34
34
|
targetEntity,
|
|
35
|
+
parentAlias,
|
|
35
36
|
joinAlias,
|
|
36
37
|
join,
|
|
37
38
|
};
|
|
@@ -55,7 +55,10 @@ export class CreateCommand {
|
|
|
55
55
|
if (col.noInsert)
|
|
56
56
|
continue;
|
|
57
57
|
if (v == null && col.default !== undefined) {
|
|
58
|
-
v =
|
|
58
|
+
v =
|
|
59
|
+
typeof col.default === 'function'
|
|
60
|
+
? col.default(values)
|
|
61
|
+
: col.default;
|
|
59
62
|
}
|
|
60
63
|
if (typeof col.serialize === 'function')
|
|
61
64
|
v = col.serialize(v, col.name);
|
|
@@ -2,9 +2,9 @@ import { And, In, Param, Select } from '@sqb/builder';
|
|
|
2
2
|
import { AssociationNode } from '../model/association-node.js';
|
|
3
3
|
import { EmbeddedFieldMetadata } from '../model/embedded-field-metadata.js';
|
|
4
4
|
import { EntityMetadata } from '../model/entity-metadata.js';
|
|
5
|
-
import { isAssociationField, isColumnField, isEmbeddedField } from '../util/orm.helper.js';
|
|
6
|
-
import { parseFieldsProjection } from '../util/parse-fields-projection.js';
|
|
7
|
-
import { joinAssociationGetLast, prepareFilter } from './command.helper.js';
|
|
5
|
+
import { isAssociationField, isColumnField, isEmbeddedField, } from '../util/orm.helper.js';
|
|
6
|
+
import { parseFieldsProjection, } from '../util/parse-fields-projection.js';
|
|
7
|
+
import { joinAssociationGetLast, prepareFilter, } from './command.helper.js';
|
|
8
8
|
import { RowConverter } from './row-converter.js';
|
|
9
9
|
const SORT_ORDER_PATTERN = /^([-+])?(.*)$/;
|
|
10
10
|
export class FindCommand {
|
|
@@ -70,7 +70,9 @@ export class FindCommand {
|
|
|
70
70
|
? parseFieldsProjection(opts.projection)
|
|
71
71
|
: opts.projection;
|
|
72
72
|
const defaultFields = !projection || !Object.values(projection).find(p => !p.sign);
|
|
73
|
-
const sortFields = opts.sort && opts.sort.length
|
|
73
|
+
const sortFields = opts.sort && opts.sort.length
|
|
74
|
+
? opts.sort.map(x => x.toLowerCase())
|
|
75
|
+
: undefined;
|
|
74
76
|
const prefix = opts.prefix || '';
|
|
75
77
|
const suffix = opts.suffix || '';
|
|
76
78
|
for (const key of Object.keys(entity.fields)) {
|
|
@@ -170,7 +172,9 @@ export class FindCommand {
|
|
|
170
172
|
}
|
|
171
173
|
}
|
|
172
174
|
_selectColumn(tableAlias, el, prefix, suffix) {
|
|
173
|
-
const fieldName = (prefix || '').toLowerCase() +
|
|
175
|
+
const fieldName = (prefix || '').toLowerCase() +
|
|
176
|
+
el.fieldName.toUpperCase() +
|
|
177
|
+
(suffix || '').toLowerCase();
|
|
174
178
|
const fieldAlias = (tableAlias + '_' + fieldName).substring(0, 30);
|
|
175
179
|
this._selectColumns[fieldAlias] = {
|
|
176
180
|
field: el,
|
|
@@ -132,7 +132,9 @@ export class RowConverter {
|
|
|
132
132
|
fld = fld || _fields.get('' + p.keyField);
|
|
133
133
|
const keyValue = fld && row[fld.index];
|
|
134
134
|
if (keyValue != null) {
|
|
135
|
-
const keyValues = Array.isArray(keyValue)
|
|
135
|
+
const keyValues = Array.isArray(keyValue)
|
|
136
|
+
? keyValue
|
|
137
|
+
: [keyValue];
|
|
136
138
|
keyValues.forEach(k => {
|
|
137
139
|
let arr = map.get(k);
|
|
138
140
|
if (!arr) {
|
|
@@ -19,7 +19,9 @@ Column[DECORATOR_FACTORY] = function (arg0) {
|
|
|
19
19
|
else
|
|
20
20
|
options.type = typ;
|
|
21
21
|
}
|
|
22
|
-
if (!options.dataType &&
|
|
22
|
+
if (!options.dataType &&
|
|
23
|
+
typeof options.type === 'function' &&
|
|
24
|
+
EntityMetadata.get(options.type)) {
|
|
23
25
|
options.dataType = DataType.JSON;
|
|
24
26
|
}
|
|
25
27
|
EntityMetadata.defineColumnField(entity, propertyKey, options);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { EntityMetadata } from '../model/entity-metadata.js';
|
|
1
|
+
import { EntityMetadata, } from '../model/entity-metadata.js';
|
|
2
2
|
import { applyMixins } from '../util/apply-mixins.js';
|
|
3
3
|
export function Entity(options) {
|
|
4
4
|
return function (target) {
|
|
@@ -164,7 +164,9 @@ function applyConstructorProperties(target, sourceClass, constructorArgs, isProp
|
|
|
164
164
|
for (const key of keys) {
|
|
165
165
|
const srcDesc = Object.getOwnPropertyDescriptor(tempInstance, key);
|
|
166
166
|
const trgDesc = Object.getOwnPropertyDescriptor(target, key);
|
|
167
|
-
if (!srcDesc ||
|
|
167
|
+
if (!srcDesc ||
|
|
168
|
+
trgDesc ||
|
|
169
|
+
(isPropertyInherited && !isPropertyInherited(key)))
|
|
168
170
|
continue;
|
|
169
171
|
Object.defineProperty(target, key, srcDesc);
|
|
170
172
|
}
|
|
@@ -76,11 +76,17 @@ export class Association {
|
|
|
76
76
|
if (this.many) {
|
|
77
77
|
if (!sourceKey) {
|
|
78
78
|
const primaryIndexColumns = EntityMetadata.getPrimaryIndexColumns(source);
|
|
79
|
-
sourceKey =
|
|
79
|
+
sourceKey =
|
|
80
|
+
primaryIndexColumns && primaryIndexColumns.length === 1
|
|
81
|
+
? primaryIndexColumns[0].name
|
|
82
|
+
: 'id';
|
|
80
83
|
}
|
|
81
84
|
if (!targetKey && sourceKey) {
|
|
82
85
|
// snake-case
|
|
83
|
-
let s = source.name[0].toLowerCase() +
|
|
86
|
+
let s = source.name[0].toLowerCase() +
|
|
87
|
+
source.name.substring(1) +
|
|
88
|
+
'_' +
|
|
89
|
+
sourceKey;
|
|
84
90
|
if (!EntityMetadata.getColumnField(target, s))
|
|
85
91
|
s = camelCase(s);
|
|
86
92
|
targetKey = s;
|
|
@@ -89,11 +95,17 @@ export class Association {
|
|
|
89
95
|
else {
|
|
90
96
|
if (!targetKey) {
|
|
91
97
|
const primaryIndexColumns = EntityMetadata.getPrimaryIndexColumns(target);
|
|
92
|
-
targetKey =
|
|
98
|
+
targetKey =
|
|
99
|
+
primaryIndexColumns && primaryIndexColumns.length === 1
|
|
100
|
+
? primaryIndexColumns[0].name
|
|
101
|
+
: 'id';
|
|
93
102
|
}
|
|
94
103
|
if (!sourceKey && targetKey) {
|
|
95
104
|
// snake-case
|
|
96
|
-
let s = target.name[0].toLowerCase() +
|
|
105
|
+
let s = target.name[0].toLowerCase() +
|
|
106
|
+
target.name.substring(1) +
|
|
107
|
+
'_' +
|
|
108
|
+
targetKey;
|
|
97
109
|
if (!EntityMetadata.getColumnField(source, s))
|
|
98
110
|
s = camelCase(s);
|
|
99
111
|
sourceKey = s;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { DataType } from '@sqb/builder';
|
|
2
2
|
import { ENTITY_METADATA_KEY } from '../orm.const.js';
|
|
3
|
-
import { isAssociationField, isColumnField, isEmbeddedField } from '../util/orm.helper.js';
|
|
3
|
+
import { isAssociationField, isColumnField, isEmbeddedField, } from '../util/orm.helper.js';
|
|
4
4
|
import { Association } from './association.js';
|
|
5
|
-
import { AssociationFieldMetadata } from './association-field-metadata.js';
|
|
6
|
-
import { ColumnFieldMetadata } from './column-field-metadata.js';
|
|
7
|
-
import { EmbeddedFieldMetadata } from './embedded-field-metadata.js';
|
|
5
|
+
import { AssociationFieldMetadata, } from './association-field-metadata.js';
|
|
6
|
+
import { ColumnFieldMetadata, } from './column-field-metadata.js';
|
|
7
|
+
import { EmbeddedFieldMetadata, } from './embedded-field-metadata.js';
|
|
8
8
|
export var EntityMetadata;
|
|
9
9
|
(function (EntityMetadata) {
|
|
10
10
|
function define(ctor) {
|
|
@@ -295,7 +295,10 @@ export var EntityMetadata;
|
|
|
295
295
|
derived.foreignKeys = derived.foreignKeys || [];
|
|
296
296
|
for (const fk of base.foreignKeys) {
|
|
297
297
|
if (!fk.sourceKey || hasField(fk.sourceKey)) {
|
|
298
|
-
const newFk = new Association(fk.name, {
|
|
298
|
+
const newFk = new Association(fk.name, {
|
|
299
|
+
...fk,
|
|
300
|
+
source: derived.ctor,
|
|
301
|
+
});
|
|
299
302
|
derived.foreignKeys.push(newFk);
|
|
300
303
|
}
|
|
301
304
|
}
|
|
@@ -26,7 +26,11 @@ export class Repository extends TypedEventEmitterClass(AsyncEventEmitter) {
|
|
|
26
26
|
}
|
|
27
27
|
create(input, options) {
|
|
28
28
|
return this._execute(async (connection) => {
|
|
29
|
-
const keyValue = await this._create(input, {
|
|
29
|
+
const keyValue = await this._create(input, {
|
|
30
|
+
...options,
|
|
31
|
+
connection,
|
|
32
|
+
returning: true,
|
|
33
|
+
});
|
|
30
34
|
const result = keyValue && (await this._find(keyValue, { ...options, connection }));
|
|
31
35
|
if (!result)
|
|
32
36
|
throw new Error('Unable to insert new row');
|
|
@@ -43,7 +47,11 @@ export class Repository extends TypedEventEmitterClass(AsyncEventEmitter) {
|
|
|
43
47
|
*/
|
|
44
48
|
createOnly(input, options) {
|
|
45
49
|
return this._execute(async (connection) => {
|
|
46
|
-
const r = await this._create(input, {
|
|
50
|
+
const r = await this._create(input, {
|
|
51
|
+
...options,
|
|
52
|
+
connection,
|
|
53
|
+
returning: true,
|
|
54
|
+
});
|
|
47
55
|
const primaryIndex = EntityMetadata.getPrimaryIndex(this.entity);
|
|
48
56
|
if (!primaryIndex || primaryIndex.columns.length > 1)
|
|
49
57
|
return r;
|
|
@@ -7,6 +7,7 @@ export function applyMixins(derivedCtor, baseCtor, filter) {
|
|
|
7
7
|
(filter && !filter(name))) {
|
|
8
8
|
continue;
|
|
9
9
|
}
|
|
10
|
-
Object.defineProperty(derivedCtor.prototype, name, Object.getOwnPropertyDescriptor(baseCtor.prototype, name) ||
|
|
10
|
+
Object.defineProperty(derivedCtor.prototype, name, Object.getOwnPropertyDescriptor(baseCtor.prototype, name) ||
|
|
11
|
+
Object.create(null));
|
|
11
12
|
}
|
|
12
13
|
}
|
|
@@ -46,14 +46,16 @@ function parse(input, target) {
|
|
|
46
46
|
if (!m)
|
|
47
47
|
throw new TypeError(`Invalid field path (${input})`);
|
|
48
48
|
const fieldName = m[2];
|
|
49
|
-
const treeItem = (target[fieldName] =
|
|
49
|
+
const treeItem = (target[fieldName] =
|
|
50
|
+
target[fieldName] || new FieldsProjection.Item());
|
|
50
51
|
if (m[1])
|
|
51
52
|
treeItem.sign = m[1];
|
|
52
53
|
if (i === fields.length - 1) {
|
|
53
54
|
delete treeItem.projection;
|
|
54
55
|
}
|
|
55
56
|
else {
|
|
56
|
-
target = treeItem.projection =
|
|
57
|
+
target = treeItem.projection =
|
|
58
|
+
treeItem.projection || new FieldsProjection();
|
|
57
59
|
}
|
|
58
60
|
}
|
|
59
61
|
}
|
|
@@ -17,19 +17,26 @@ const padZero = (n) => (n < 9 ? '0' : '') + n;
|
|
|
17
17
|
function serializeDataValue(dataType, v) {
|
|
18
18
|
if (v == null)
|
|
19
19
|
return;
|
|
20
|
-
if (v instanceof Date &&
|
|
20
|
+
if (v instanceof Date &&
|
|
21
|
+
(dataType === DataType.DATE || dataType === DataType.TIMESTAMP)) {
|
|
21
22
|
return (v.getFullYear() +
|
|
22
23
|
'-' +
|
|
23
24
|
padZero(v.getMonth() + 1) +
|
|
24
25
|
'-' +
|
|
25
26
|
padZero(v.getDate()) +
|
|
26
27
|
(dataType === DataType.TIMESTAMP
|
|
27
|
-
? 'T' +
|
|
28
|
+
? 'T' +
|
|
29
|
+
padZero(v.getHours()) +
|
|
30
|
+
':' +
|
|
31
|
+
padZero(v.getMinutes()) +
|
|
32
|
+
':' +
|
|
33
|
+
padZero(v.getSeconds())
|
|
28
34
|
: ''));
|
|
29
35
|
}
|
|
30
36
|
if (v instanceof Buffer)
|
|
31
37
|
return v.toString('base64');
|
|
32
|
-
if (typeof v === 'number' &&
|
|
38
|
+
if (typeof v === 'number' &&
|
|
39
|
+
(dataType === DataType.SMALLINT || dataType === DataType.INTEGER))
|
|
33
40
|
return Math.trunc(v);
|
|
34
41
|
if (typeof v === 'bigint')
|
|
35
42
|
return v.toString();
|
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.19.
|
|
4
|
+
"version": "4.19.6",
|
|
5
5
|
"author": "Panates",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"dependencies": {
|
|
@@ -16,11 +16,11 @@
|
|
|
16
16
|
"putil-promisify": "^1.10.1",
|
|
17
17
|
"putil-varhelpers": "^1.6.5",
|
|
18
18
|
"strict-typed-events": "^2.8.0",
|
|
19
|
-
"ts-gems": "^3.
|
|
20
|
-
"tslib": "^2.8.
|
|
19
|
+
"ts-gems": "^3.6.0",
|
|
20
|
+
"tslib": "^2.8.1"
|
|
21
21
|
},
|
|
22
22
|
"peerDependencies": {
|
|
23
|
-
"@sqb/builder": "^4.19.
|
|
23
|
+
"@sqb/builder": "^4.19.6",
|
|
24
24
|
"reflect-metadata": "^0.2.2"
|
|
25
25
|
},
|
|
26
26
|
"type": "module",
|
|
@@ -76,5 +76,8 @@
|
|
|
76
76
|
"mssql",
|
|
77
77
|
"sqlite",
|
|
78
78
|
"mysql"
|
|
79
|
-
]
|
|
79
|
+
],
|
|
80
|
+
"publishConfig": {
|
|
81
|
+
"access": "public"
|
|
82
|
+
}
|
|
80
83
|
}
|
package/types/index.d.cts
CHANGED
|
@@ -28,5 +28,5 @@ export * from './orm/model/link-chain.js';
|
|
|
28
28
|
export * from './orm/orm.const.js';
|
|
29
29
|
export * from './orm/orm.type.js';
|
|
30
30
|
export * from './orm/repository.class.js';
|
|
31
|
-
export { isAssociationField, isColumnField, isEmbeddedField, isEntityClass } from './orm/util/orm.helper.js';
|
|
31
|
+
export { isAssociationField, isColumnField, isEmbeddedField, isEntityClass, } from './orm/util/orm.helper.js';
|
|
32
32
|
export * from './orm/util/parse-fields-projection.js';
|
package/types/index.d.ts
CHANGED
|
@@ -28,5 +28,5 @@ export * from './orm/model/link-chain.js';
|
|
|
28
28
|
export * from './orm/orm.const.js';
|
|
29
29
|
export * from './orm/orm.type.js';
|
|
30
30
|
export * from './orm/repository.class.js';
|
|
31
|
-
export { isAssociationField, isColumnField, isEmbeddedField, isEntityClass } from './orm/util/orm.helper.js';
|
|
31
|
+
export { isAssociationField, isColumnField, isEmbeddedField, isEntityClass, } from './orm/util/orm.helper.js';
|
|
32
32
|
export * from './orm/util/parse-fields-projection.js';
|
|
@@ -6,6 +6,7 @@ export interface JoinInfo {
|
|
|
6
6
|
sourceEntity: EntityMetadata;
|
|
7
7
|
targetEntity: EntityMetadata;
|
|
8
8
|
joinAlias: string;
|
|
9
|
+
parentAlias: string;
|
|
9
10
|
join: JoinStatement;
|
|
10
11
|
}
|
|
11
12
|
export declare function joinAssociationGetFirst(joinInfos: JoinInfo[], association: AssociationNode, parentAlias: string, innerJoin?: boolean): Promise<JoinInfo>;
|