@sqb/connect 4.12.1 → 4.14.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.
Files changed (58) hide show
  1. package/cjs/client/cursor.js +1 -1
  2. package/cjs/client/extensions.js +38 -11
  3. package/cjs/client/helpers.js +7 -6
  4. package/cjs/client/sqb-client.js +2 -2
  5. package/cjs/client/sqb-connection.js +7 -4
  6. package/cjs/index.js +18 -20
  7. package/cjs/orm/backward.js +5 -5
  8. package/cjs/orm/commands/command.helper.js +38 -10
  9. package/cjs/orm/commands/create.command.js +2 -1
  10. package/cjs/orm/commands/find.command.js +3 -1
  11. package/cjs/orm/commands/row-converter.js +5 -10
  12. package/cjs/orm/decorators/column.decorator.js +1 -2
  13. package/cjs/orm/decorators/embedded.decorator.js +1 -2
  14. package/cjs/orm/decorators/entity.decorator.js +1 -2
  15. package/cjs/orm/decorators/events.decorator.js +6 -7
  16. package/cjs/orm/decorators/foreignkey.decorator.js +1 -2
  17. package/cjs/orm/decorators/index.decorator.js +1 -2
  18. package/cjs/orm/decorators/link.decorator.js +7 -5
  19. package/cjs/orm/decorators/primarykey.decorator.js +3 -3
  20. package/cjs/orm/decorators/transform.decorator.js +2 -3
  21. package/cjs/orm/model/association.js +9 -11
  22. package/cjs/orm/model/entity-metadata.js +4 -2
  23. package/cjs/orm/repository.class.js +13 -33
  24. package/cjs/orm/util/apply-mixins.js +3 -3
  25. package/cjs/orm/util/extract-keyvalues.js +7 -5
  26. package/cjs/orm/util/orm.helper.js +8 -12
  27. package/cjs/orm/util/parse-fields-projection.js +3 -5
  28. package/cjs/orm/util/serialize-field.js +1 -2
  29. package/esm/client/cursor.js +1 -1
  30. package/esm/client/extensions.js +36 -8
  31. package/esm/client/helpers.js +2 -0
  32. package/esm/client/sqb-client.js +3 -3
  33. package/esm/client/sqb-connection.js +7 -4
  34. package/esm/index.js +17 -17
  35. package/esm/orm/commands/command.helper.js +35 -6
  36. package/esm/orm/commands/create.command.js +2 -1
  37. package/esm/orm/commands/find.command.js +3 -1
  38. package/esm/orm/commands/row-converter.js +5 -10
  39. package/esm/orm/decorators/link.decorator.js +6 -3
  40. package/esm/orm/decorators/primarykey.decorator.js +2 -1
  41. package/esm/orm/model/association.js +9 -11
  42. package/esm/orm/model/entity-metadata.js +4 -2
  43. package/esm/orm/repository.class.js +13 -33
  44. package/esm/orm/util/apply-mixins.js +2 -1
  45. package/esm/orm/util/extract-keyvalues.js +6 -3
  46. package/esm/orm/util/orm.helper.js +2 -6
  47. package/esm/orm/util/parse-fields-projection.js +1 -3
  48. package/package.json +6 -5
  49. package/types/client/adapter.d.ts +1 -1
  50. package/types/client/cursor-stream.d.ts +0 -1
  51. package/types/client/extensions.d.ts +14 -3
  52. package/types/client/sqb-client.d.ts +1 -1
  53. package/types/client/sqb-connection.d.ts +1 -1
  54. package/types/client/types.d.ts +1 -1
  55. package/types/index.d.ts +17 -17
  56. package/types/orm/commands/find.command.d.ts +1 -1
  57. package/types/orm/commands/row-converter.d.ts +1 -1
  58. package/types/orm/repository.class.d.ts +2 -1
@@ -66,17 +66,15 @@ class Association {
66
66
  this._targetProperty = foreign._targetProperty;
67
67
  return;
68
68
  }
69
- else {
70
- // Try to determine key fields from foreign key from target to source
71
- foreign = await entity_metadata_js_1.EntityMetadata.getForeignKeyFor(target, source);
72
- if (foreign && foreign !== this) {
73
- await foreign._resolveKeys();
74
- this._sourceKey = foreign._targetKey;
75
- this._sourceProperty = foreign._targetProperty;
76
- this._targetKey = foreign._sourceKey;
77
- this._targetProperty = foreign._sourceProperty;
78
- return;
79
- }
69
+ // Try to determine key fields from foreign key from target to source
70
+ foreign = await entity_metadata_js_1.EntityMetadata.getForeignKeyFor(target, source);
71
+ if (foreign && foreign !== this) {
72
+ await foreign._resolveKeys();
73
+ this._sourceKey = foreign._targetKey;
74
+ this._sourceProperty = foreign._targetProperty;
75
+ this._targetKey = foreign._sourceKey;
76
+ this._targetProperty = foreign._sourceProperty;
77
+ return;
80
78
  }
81
79
  if (this.many) {
82
80
  if (!sourceKey) {
@@ -59,8 +59,9 @@ var EntityMetadata;
59
59
  EntityMetadata.getEmbeddedField = getEmbeddedField;
60
60
  function getAssociationField(entity, fieldName) {
61
61
  const el = getField(entity, fieldName);
62
- if (el && !(0, orm_helper_js_1.isAssociationField)(el))
62
+ if (el && !(0, orm_helper_js_1.isAssociationField)(el)) {
63
63
  throw new Error(`"${el.name}" requested as "association" but it is "${el.kind}"`);
64
+ }
64
65
  return el;
65
66
  }
66
67
  EntityMetadata.getAssociationField = getAssociationField;
@@ -88,13 +89,14 @@ var EntityMetadata;
88
89
  return out;
89
90
  }
90
91
  // Create a cached name array
91
- if (!Object.prototype.hasOwnProperty.call(entity, '_fieldNames'))
92
+ if (!Object.prototype.hasOwnProperty.call(entity, '_fieldNames')) {
92
93
  Object.defineProperty(entity, '_fieldNames', {
93
94
  enumerable: false,
94
95
  configurable: true,
95
96
  writable: true,
96
97
  value: Object.values(entity.fields).map(m => m.name),
97
98
  });
99
+ }
98
100
  return entity._fieldNames;
99
101
  }
100
102
  EntityMetadata.getFieldNames = getFieldNames;
@@ -37,47 +37,31 @@ class Repository extends (0, strict_typed_events_1.TypedEventEmitterClass)(stric
37
37
  }, options);
38
38
  }
39
39
  exists(keyValue, options) {
40
- return this._execute(async (connection) => {
41
- return this._exists(keyValue, { ...options, connection });
42
- }, options);
40
+ return this._execute(async (connection) => this._exists(keyValue, { ...options, connection }), options);
43
41
  }
44
42
  existsOne(options) {
45
- return this._execute(async (connection) => {
46
- return this._existsOne({ ...options, connection });
47
- }, options);
43
+ return this._execute(async (connection) => this._existsOne({ ...options, connection }), options);
48
44
  }
49
45
  count(options) {
50
- return this._execute(async (connection) => {
51
- return this._count({ ...options, connection });
52
- }, options);
46
+ return this._execute(async (connection) => this._count({ ...options, connection }), options);
53
47
  }
54
48
  findById(keyValue, options) {
55
- return this._execute(async (connection) => {
56
- return this._find(keyValue, { ...options, connection });
57
- }, options);
49
+ return this._execute(async (connection) => this._find(keyValue, { ...options, connection }), options);
58
50
  }
59
51
  findOne(options) {
60
- return this._execute(async (connection) => {
61
- return await this._findOne({
62
- ...options,
63
- connection,
64
- });
65
- }, options);
52
+ return this._execute(async (connection) => await this._findOne({
53
+ ...options,
54
+ connection,
55
+ }), options);
66
56
  }
67
57
  findMany(options) {
68
- return this._execute(async (connection) => {
69
- return this._findMany({ ...options, connection });
70
- }, options);
58
+ return this._execute(async (connection) => this._findMany({ ...options, connection }), options);
71
59
  }
72
60
  delete(keyValue, options) {
73
- return this._execute(async (connection) => {
74
- return this._delete(keyValue, { ...options, connection });
75
- }, options);
61
+ return this._execute(async (connection) => this._delete(keyValue, { ...options, connection }), options);
76
62
  }
77
63
  deleteMany(options) {
78
- return this._execute(async (connection) => {
79
- return this._deleteMany({ ...options, connection });
80
- }, options);
64
+ return this._execute(async (connection) => this._deleteMany({ ...options, connection }), options);
81
65
  }
82
66
  update(keyValue, values, options) {
83
67
  return this._execute(async (connection) => {
@@ -88,14 +72,10 @@ class Repository extends (0, strict_typed_events_1.TypedEventEmitterClass)(stric
88
72
  }, options);
89
73
  }
90
74
  updateOnly(keyValue, values, options) {
91
- return this._execute(async (connection) => {
92
- return !!(await this._update(keyValue, values, { ...options, connection }));
93
- }, options);
75
+ return this._execute(async (connection) => !!(await this._update(keyValue, values, { ...options, connection })), options);
94
76
  }
95
77
  updateMany(values, options) {
96
- return this._execute(async (connection) => {
97
- return this._updateMany(values, { ...options, connection });
98
- });
78
+ return this._execute(async (connection) => this._updateMany(values, { ...options, connection }));
99
79
  }
100
80
  async _execute(fn, opts) {
101
81
  let connection = opts?.connection;
@@ -1,15 +1,15 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.applyMixins = void 0;
3
+ exports.applyMixins = applyMixins;
4
4
  function applyMixins(derivedCtor, baseCtor, filter) {
5
5
  for (const name of Object.getOwnPropertyNames(baseCtor.prototype)) {
6
6
  if (name === 'constructor' ||
7
7
  name === '__proto__' ||
8
8
  name === 'toJSON' ||
9
9
  name === 'toString' ||
10
- (filter && !filter(name)))
10
+ (filter && !filter(name))) {
11
11
  continue;
12
+ }
12
13
  Object.defineProperty(derivedCtor.prototype, name, Object.getOwnPropertyDescriptor(baseCtor.prototype, name) || Object.create(null));
13
14
  }
14
15
  }
15
- exports.applyMixins = applyMixins;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.extractKeyValues = void 0;
3
+ exports.extractKeyValues = extractKeyValues;
4
4
  const entity_metadata_js_1 = require("../model/entity-metadata.js");
5
5
  const orm_helper_js_1 = require("./orm.helper.js");
6
6
  function extractKeyValues(entityDef, valueOrInstance, keepOther) {
@@ -11,14 +11,16 @@ function extractKeyValues(entityDef, valueOrInstance, keepOther) {
11
11
  const col = entity_metadata_js_1.EntityMetadata.getField(entityDef, k);
12
12
  if (!col)
13
13
  throw new Error(`Unknown column (${k}) defined as primary key in entity "${entityDef.name}"`);
14
- if (!(0, orm_helper_js_1.isColumnField)(col))
14
+ if (!(0, orm_helper_js_1.isColumnField)(col)) {
15
15
  throw new Error(`Column (${k}) defined as primary key in entity "${entityDef.name}" is not a data column`);
16
+ }
16
17
  };
17
18
  // if entity's primary key has more than one key field
18
19
  if (primaryIndex.columns.length > 1) {
19
- if (typeof valueOrInstance !== 'object')
20
+ if (typeof valueOrInstance !== 'object') {
20
21
  throw new Error(`"${entityDef.name}" entity` +
21
22
  ` has more than one primary key field and you must provide all values with an key/value pair`);
23
+ }
22
24
  const valueKeys = Object.keys(valueOrInstance);
23
25
  const valueKeysUpper = valueKeys.map(x => x.toUpperCase());
24
26
  const out = {};
@@ -44,8 +46,9 @@ function extractKeyValues(entityDef, valueOrInstance, keepOther) {
44
46
  const valueKeys = Object.keys(valueOrInstance);
45
47
  const valueKeysUpper = valueKeys.map(x => x.toUpperCase());
46
48
  const k = valueKeysUpper.indexOf(primaryColumnName.toUpperCase());
47
- if (k < 0)
49
+ if (k < 0) {
48
50
  throw new Error(`Value of key field "${entityDef.name}.${primaryColumnName}" required to perform this operation`);
51
+ }
49
52
  const out = { [primaryColumnName]: valueOrInstance[valueKeys[k]] };
50
53
  if (keepOther) {
51
54
  for (let i = 0; i < valueKeys.length; i++) {
@@ -58,4 +61,3 @@ function extractKeyValues(entityDef, valueOrInstance, keepOther) {
58
61
  }
59
62
  return { [primaryColumnName]: valueOrInstance };
60
63
  }
61
- exports.extractKeyValues = extractKeyValues;
@@ -1,26 +1,24 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.resolveEntityMeta = exports.resolveEntity = exports.isAssociationField = exports.isEmbeddedField = exports.isColumnField = exports.isEntityClass = exports.isClass = void 0;
3
+ exports.isAssociationField = exports.isEmbeddedField = void 0;
4
+ exports.isClass = isClass;
5
+ exports.isEntityClass = isEntityClass;
6
+ exports.isColumnField = isColumnField;
7
+ exports.resolveEntity = resolveEntity;
8
+ exports.resolveEntityMeta = resolveEntityMeta;
4
9
  const orm_const_js_1 = require("../orm.const.js");
5
10
  function isClass(fn) {
6
11
  return typeof fn === 'function' && /^\s*class/.test(fn.toString());
7
12
  }
8
- exports.isClass = isClass;
9
13
  function isEntityClass(fn) {
10
14
  return isClass(fn) && Reflect.hasMetadata(orm_const_js_1.ENTITY_METADATA_KEY, fn);
11
15
  }
12
- exports.isEntityClass = isEntityClass;
13
16
  function isColumnField(f) {
14
17
  return !!(f && f.name && f.kind === 'column');
15
18
  }
16
- exports.isColumnField = isColumnField;
17
- const isEmbeddedField = (f) => {
18
- return !!(f && f.name && f.kind === 'object');
19
- };
19
+ const isEmbeddedField = (f) => !!(f && f.name && f.kind === 'object');
20
20
  exports.isEmbeddedField = isEmbeddedField;
21
- const isAssociationField = (f) => {
22
- return !!(f && f.name && f.kind === 'association');
23
- };
21
+ const isAssociationField = (f) => !!(f && f.name && f.kind === 'association');
24
22
  exports.isAssociationField = isAssociationField;
25
23
  async function resolveEntity(ctorThunk) {
26
24
  if (typeof ctorThunk !== 'function')
@@ -30,9 +28,7 @@ async function resolveEntity(ctorThunk) {
30
28
  if (isEntityClass(ctorThunk))
31
29
  return ctorThunk;
32
30
  }
33
- exports.resolveEntity = resolveEntity;
34
31
  async function resolveEntityMeta(ctorThunk) {
35
32
  const ctor = await resolveEntity(ctorThunk);
36
33
  return ctor && Reflect.getMetadata(orm_const_js_1.ENTITY_METADATA_KEY, ctor);
37
34
  }
38
- exports.resolveEntityMeta = resolveEntityMeta;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.parseFieldsProjection = exports.FieldsProjection = void 0;
3
+ exports.FieldsProjection = void 0;
4
+ exports.parseFieldsProjection = parseFieldsProjection;
4
5
  const fast_tokenizer_1 = require("fast-tokenizer");
5
6
  const FIELD_PATTERN = /^([+-])?([a-z_$]\w*)$/i;
6
7
  const NO_DOT_BRACKET_PATTERN = /[^.]\(/g;
@@ -24,12 +25,9 @@ function parseFieldsProjection(projection, keepCase) {
24
25
  }
25
26
  return out;
26
27
  }
27
- exports.parseFieldsProjection = parseFieldsProjection;
28
28
  function parse(input, target) {
29
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
- });
30
+ input = input.replace(NO_DOT_BRACKET_PATTERN, s => s.charAt(0) + '.' + s.substring(1));
33
31
  const fields = (0, fast_tokenizer_1.splitString)(input, {
34
32
  delimiters: '.',
35
33
  brackets: true,
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.serializeColumn = void 0;
3
+ exports.serializeColumn = serializeColumn;
4
4
  const builder_1 = require("@sqb/builder");
5
5
  const orm_helper_js_1 = require("./orm.helper.js");
6
6
  function serializeColumn(col, v) {
@@ -16,7 +16,6 @@ function serializeColumn(col, v) {
16
16
  return v.toJSON();
17
17
  return v;
18
18
  }
19
- exports.serializeColumn = serializeColumn;
20
19
  const padZero = (n) => (n < 9 ? '0' : '') + n;
21
20
  function serializeDataValue(dataType, v) {
22
21
  if (v == null)
@@ -176,7 +176,7 @@ export class Cursor extends TypedEventEmitterClass(AsyncEventEmitter) {
176
176
  throw new Error('To move cursor back, it needs cache to be enabled');
177
177
  const _this = this;
178
178
  await this._taskQueue
179
- .enqueue(async function () {
179
+ .enqueue(async () => {
180
180
  /* If moving backward */
181
181
  if (step < 0) {
182
182
  /* Seek cache */
@@ -1,9 +1,37 @@
1
- export let adapters = [];
2
- export function registerAdapter(adapter) {
3
- if (!adapter.driver)
4
- throw new TypeError('A DatabaseAdapter must contain "driver" property');
5
- adapters.push(adapter);
6
- }
7
- export function unRegisterAdapter(...adapter) {
8
- adapters = adapters.filter(x => !adapter.includes(x));
1
+ export class AdapterRegistry {
2
+ static get size() {
3
+ return this.adapters.length;
4
+ }
5
+ static register(...adapters) {
6
+ for (const adapter of adapters) {
7
+ if (!adapter.driver)
8
+ throw new TypeError('A DatabaseAdapter must contain "driver" property');
9
+ this.adapters.push(adapter);
10
+ }
11
+ }
12
+ static forEach(callback, thisArg) {
13
+ return this.adapters.forEach(callback, thisArg);
14
+ }
15
+ static items() {
16
+ return this.adapters.values();
17
+ }
18
+ static unRegister(...extensions) {
19
+ this.adapters = extensions.filter(x => !extensions.includes(x));
20
+ }
21
+ static getAll(dialect) {
22
+ return this.adapters.filter(x => x.dialect === dialect);
23
+ }
24
+ static get(index) {
25
+ return this.adapters[index];
26
+ }
27
+ static findDialect(dialect) {
28
+ return this.adapters.find(x => x.dialect === dialect);
29
+ }
30
+ static findDriver(dialect) {
31
+ return this.adapters.find(x => x.driver === dialect);
32
+ }
33
+ static has(extension) {
34
+ return !!this.adapters.find(x => x === extension);
35
+ }
9
36
  }
37
+ AdapterRegistry.adapters = [];
@@ -16,6 +16,8 @@ export function applyNamingStrategy(value, namingStrategy) {
16
16
  if (!value.match(/[a-z]/))
17
17
  return pascalCase(value.toLowerCase());
18
18
  return pascalCase(value);
19
+ default:
20
+ break;
19
21
  }
20
22
  }
21
23
  else if (typeof namingStrategy === 'function')
@@ -4,7 +4,7 @@ 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';
6
6
  import { Repository } from '../orm/repository.class.js';
7
- import { adapters } from './extensions.js';
7
+ import { AdapterRegistry } from './extensions.js';
8
8
  import { SqbConnection } from './sqb-connection.js';
9
9
  const debug = _debug('sqb:client');
10
10
  const inspect = Symbol.for('nodejs.util.inspect.custom');
@@ -16,12 +16,12 @@ export class SqbClient extends TypedEventEmitterClass(AsyncEventEmitter) {
16
16
  throw new TypeError('Configuration object required');
17
17
  let adapter;
18
18
  if (config.driver) {
19
- adapter = adapters.find(x => x.driver === config.driver);
19
+ adapter = AdapterRegistry.findDriver(config.driver);
20
20
  if (!adapter)
21
21
  throw new Error(`No database adapter registered for "${config.driver}" driver`);
22
22
  }
23
23
  else if (config.dialect) {
24
- adapter = adapters.find(x => x.dialect === config.dialect);
24
+ adapter = AdapterRegistry.findDialect(config.dialect);
25
25
  if (!adapter)
26
26
  throw new Error(`No database adapter registered for "${config.dialect}" dialect`);
27
27
  }
@@ -1,9 +1,9 @@
1
+ import { classes } from '@sqb/builder';
1
2
  import assert from 'assert';
2
3
  import _debug from 'debug';
3
4
  import { TaskQueue } from 'power-tasks';
4
5
  import { coalesce, coerceToBoolean, coerceToInt, coerceToString } from 'putil-varhelpers';
5
6
  import { AsyncEventEmitter, TypedEventEmitterClass } from 'strict-typed-events';
6
- import { classes } from '@sqb/builder';
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';
@@ -187,8 +187,9 @@ export class SqbConnection extends TypedEventEmitterClass(AsyncEventEmitter) {
187
187
  async setSavepoint(savepoint) {
188
188
  if (!this._intlcon)
189
189
  throw new Error('Can not call setSavepoint() on a released connection');
190
- if (typeof this._intlcon.setSavepoint !== 'function')
190
+ if (typeof this._intlcon.setSavepoint !== 'function') {
191
191
  throw new Error(this.client.driver + ' does not support setSavepoint method');
192
+ }
192
193
  if (!this.inTransaction)
193
194
  await this.startTransaction();
194
195
  await this._intlcon.setSavepoint(savepoint);
@@ -197,16 +198,18 @@ export class SqbConnection extends TypedEventEmitterClass(AsyncEventEmitter) {
197
198
  async releaseSavepoint(savepoint) {
198
199
  if (!this._intlcon)
199
200
  throw new Error('Can not call releaseSavepoint() on a released connection');
200
- if (typeof this._intlcon.releaseSavepoint !== 'function')
201
+ if (typeof this._intlcon.releaseSavepoint !== 'function') {
201
202
  throw new Error(this.client.driver + ' does not support releaseSavepoint method');
203
+ }
202
204
  await this._intlcon.releaseSavepoint(savepoint);
203
205
  this.emit('release-savepoint');
204
206
  }
205
207
  async rollbackSavepoint(savepoint) {
206
208
  if (!this._intlcon)
207
209
  throw new Error('Can not call rollbackSavepoint() on a released connection');
208
- if (typeof this._intlcon.rollbackSavepoint !== 'function')
210
+ if (typeof this._intlcon.rollbackSavepoint !== 'function') {
209
211
  throw new Error(this.client.driver + ' does not support rollbackSavepoint method');
212
+ }
210
213
  await this._intlcon.rollbackSavepoint(savepoint);
211
214
  this.emit('rollback-savepoint');
212
215
  }
package/esm/index.js CHANGED
@@ -1,23 +1,12 @@
1
1
  import 'reflect-metadata';
2
- export * from './client/types.js';
3
2
  export * from './client/adapter.js';
3
+ export * from './client/cursor.js';
4
+ export * from './client/extensions.js';
4
5
  export * from './client/sqb-client.js';
5
6
  export * from './client/sqb-connection.js';
6
- export * from './client/cursor.js';
7
- export { registerAdapter, unRegisterAdapter } from './client/extensions.js';
8
- export * from './orm/orm.type.js';
9
- export * from './orm/orm.const.js';
7
+ export * from './client/types.js';
8
+ export * from './orm/backward.js';
10
9
  export * from './orm/base-entity.js';
11
- export * from './orm/repository.class.js';
12
- export * from './orm/model/entity-metadata.js';
13
- export * from './orm/model/field-metadata.js';
14
- export * from './orm/model/column-field-metadata.js';
15
- export * from './orm/model/embedded-field-metadata.js';
16
- export * from './orm/model/association-field-metadata.js';
17
- export * from './orm/model/association.js';
18
- export * from './orm/model/association-node.js';
19
- export * from './orm/model/index-metadata.js';
20
- export * from './orm/model/link-chain.js';
21
10
  export * from './orm/decorators/column.decorator.js';
22
11
  export * from './orm/decorators/embedded.decorator.js';
23
12
  export * from './orm/decorators/entity.decorator.js';
@@ -27,6 +16,17 @@ export * from './orm/decorators/index.decorator.js';
27
16
  export * from './orm/decorators/link.decorator.js';
28
17
  export * from './orm/decorators/primarykey.decorator.js';
29
18
  export * from './orm/decorators/transform.decorator.js';
30
- export { isColumnField, isEmbeddedField, isAssociationField, isEntityClass } from './orm/util/orm.helper.js';
19
+ export * from './orm/model/association.js';
20
+ export * from './orm/model/association-field-metadata.js';
21
+ export * from './orm/model/association-node.js';
22
+ export * from './orm/model/column-field-metadata.js';
23
+ export * from './orm/model/embedded-field-metadata.js';
24
+ export * from './orm/model/entity-metadata.js';
25
+ export * from './orm/model/field-metadata.js';
26
+ export * from './orm/model/index-metadata.js';
27
+ export * from './orm/model/link-chain.js';
28
+ export * from './orm/orm.const.js';
29
+ export * from './orm/orm.type.js';
30
+ export * from './orm/repository.class.js';
31
+ export { isAssociationField, isColumnField, isEmbeddedField, isEntityClass } from './orm/util/orm.helper.js';
31
32
  export * from './orm/util/parse-fields-projection.js';
32
- export * from './orm/backward.js';
@@ -1,4 +1,4 @@
1
- import { And, Eq, Exists, Field, InnerJoin, isCompOperator, isLogicalOperator, LeftOuterJoin, Raw, Select, } from '@sqb/builder';
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
4
  import { isAssociationField, isColumnField, isEmbeddedField } from '../util/orm.helper.js';
@@ -56,6 +56,7 @@ export async function prepareFilter(entityDef, filter, trgOp, tableAlias = 'T')
56
56
  else
57
57
  srcOp.add(filter);
58
58
  }
59
+ const associationPathCache = {};
59
60
  for (const item of srcOp._items) {
60
61
  if (isLogicalOperator(item)) {
61
62
  const ctor = Object.getPrototypeOf(item).constructor;
@@ -74,19 +75,34 @@ export async function prepareFilter(entityDef, filter, trgOp, tableAlias = 'T')
74
75
  let _curPrefix = '';
75
76
  let _curSuffix = '';
76
77
  let subSelect;
77
- for (let i = 0; i < l; i++) {
78
+ let currentOp = trgOp;
79
+ let i = 0;
80
+ const parentPath = itemPath
81
+ .slice(0, l - 2)
82
+ .join('.')
83
+ .toLowerCase();
84
+ const cached = associationPathCache[parentPath];
85
+ if (cached) {
86
+ /** Jump to last item */
87
+ i = l - 1;
88
+ _curEntity = cached._curEntity;
89
+ _curAlias = cached._curAlias;
90
+ currentOp = cached.currentOp;
91
+ }
92
+ for (i; i < l; i++) {
78
93
  pt = itemPath[i];
79
94
  const col = EntityMetadata.getField(_curEntity, pt);
80
95
  if (!col)
81
96
  throw new Error(`Unknown property (${item._left}) defined in filter`);
82
- // if last item on path
97
+ /** if last item on path */
83
98
  if (i === l - 1) {
84
99
  if (!isColumnField(col))
85
100
  throw new Error(`Invalid column expression (${item._left}) defined in filter`);
86
101
  const ctor = Object.getPrototypeOf(item).constructor;
87
- trgOp.add(new ctor(Field(_curAlias + '.' + _curPrefix + col.fieldName + _curSuffix, col.dataType, col.isArray), item._right));
102
+ currentOp.add(new ctor(Field(_curAlias + '.' + _curPrefix + col.fieldName + _curSuffix, col.dataType, col.isArray), item._right));
88
103
  }
89
104
  else {
105
+ /** if not last item on path */
90
106
  if (isColumnField(col))
91
107
  throw new Error(`Invalid column (${item._left}) defined in filter`);
92
108
  if (isEmbeddedField(col)) {
@@ -104,8 +120,13 @@ export async function prepareFilter(entityDef, filter, trgOp, tableAlias = 'T')
104
120
  const targetCol = await col.association.resolveTargetProperty();
105
121
  subSelect = Select(Raw('1')).from(_curEntity.tableName + ' K');
106
122
  subSelect.where(Eq(Field('K.' + targetCol.fieldName, targetCol.dataType, targetCol.isArray), Field(tableAlias + '.' + keyCol.fieldName, keyCol.dataType, keyCol.isArray)));
107
- trgOp.add(Exists(subSelect));
108
- trgOp = subSelect._where;
123
+ currentOp.add(Exists(subSelect));
124
+ if (currentOp._operatorType !== OperatorType.and) {
125
+ currentOp = op.or();
126
+ subSelect.where(currentOp);
127
+ }
128
+ else
129
+ currentOp = subSelect._where;
109
130
  if (col.association.conditions) {
110
131
  await prepareFilter(_curEntity, col.association.conditions, trgOp, 'K');
111
132
  }
@@ -124,6 +145,14 @@ export async function prepareFilter(entityDef, filter, trgOp, tableAlias = 'T')
124
145
  _curAlias = joinAlias;
125
146
  node = node.next;
126
147
  }
148
+ /** If next path is the last one */
149
+ if (i === l - 2) {
150
+ associationPathCache[parentPath] = {
151
+ _curEntity,
152
+ _curAlias,
153
+ currentOp,
154
+ };
155
+ }
127
156
  }
128
157
  }
129
158
  continue;
@@ -60,8 +60,9 @@ export class CreateCommand {
60
60
  if (typeof col.serialize === 'function')
61
61
  v = col.serialize(v, col.name);
62
62
  if (v == null) {
63
- if (col.notNull && !col.autoGenerated)
63
+ if (col.notNull && !col.autoGenerated) {
64
64
  throw new Error(`${entity.name}.${col.name} is required and can't be null`);
65
+ }
65
66
  continue;
66
67
  }
67
68
  ColumnFieldMetadata.checkEnumValue(col, v);
@@ -244,16 +244,18 @@ export class FindCommand {
244
244
  if (args.offset)
245
245
  query.offset(args.offset);
246
246
  // joins must be added last
247
- if (this._joins)
247
+ if (this._joins) {
248
248
  for (const j of this._joins) {
249
249
  query.join(j.join);
250
250
  }
251
+ }
251
252
  // Execute query
252
253
  const resp = await args.connection.execute(query, {
253
254
  params: args?.params,
254
255
  fetchRows: args?.limit,
255
256
  objectRows: false,
256
257
  cursor: false,
258
+ prettyPrint: args.prettyPrint,
257
259
  });
258
260
  // Create objects
259
261
  if (resp.rows && resp.fields) {
@@ -1,13 +1,7 @@
1
1
  import { DataType } from '@sqb/builder';
2
- const isValueProperty = (prop) => {
3
- return prop.fieldAlias && !prop.converter;
4
- };
5
- const isObjectProperty = (prop) => {
6
- return prop.converter && !prop.findCommand;
7
- };
8
- const isNestedProperty = (prop) => {
9
- return prop.converter && prop.findCommand;
10
- };
2
+ const isValueProperty = (prop) => prop.fieldAlias && !prop.converter;
3
+ const isObjectProperty = (prop) => prop.converter && !prop.findCommand;
4
+ const isNestedProperty = (prop) => prop.converter && prop.findCommand;
11
5
  export class RowConverter {
12
6
  constructor(resultType, parent) {
13
7
  this.resultType = resultType;
@@ -150,8 +144,9 @@ export class RowConverter {
150
144
  }
151
145
  },
152
146
  });
153
- if (r.length > findCommand.maxEagerFetch)
147
+ if (r.length > findCommand.maxEagerFetch) {
154
148
  throw new Error(`Number of returning rows for "${propKey}" exceeds maxEagerFetch limit`);
149
+ }
155
150
  for (let i = 0; i < result.length; i++) {
156
151
  const row = rows[i];
157
152
  let obj = result[i];
@@ -8,16 +8,19 @@ export function Link(options) {
8
8
  throw new TypeError('Symbol properties are not allowed');
9
9
  const reflectType = Reflect.getMetadata('design:type', target, propertyKey);
10
10
  if (!root) {
11
- if (reflectType === Array)
11
+ if (reflectType === Array) {
12
12
  throw new TypeError(`Can't get type information while it is an array. Please define entity type`);
13
+ }
13
14
  if (!EntityMetadata.get(reflectType))
14
15
  throw new TypeError(`No entity metadata found for type "${reflectType}"`);
15
16
  fn.toOne(reflectType);
16
17
  }
17
- if (reflectType !== Array && root.first.returnsMany())
18
+ if (reflectType !== Array && root.first.returnsMany()) {
18
19
  throw new TypeError(`Link returns single instance however property type is an array`);
19
- if (reflectType === Array && !root.first.returnsMany())
20
+ }
21
+ if (reflectType === Array && !root.first.returnsMany()) {
20
22
  throw new TypeError(`Link returns array of instances however property type is not an array`);
23
+ }
21
24
  const entity = EntityMetadata.define(target.constructor);
22
25
  // @ts-ignore
23
26
  // noinspection JSConstantReassignment
@@ -3,8 +3,9 @@ import { Column } from './column.decorator.js';
3
3
  export function PrimaryKey(arg0, arg1) {
4
4
  return function (target, propertyKey) {
5
5
  if (arguments.length === 1) {
6
- if (!(typeof arg0 === 'string' || Array.isArray(arg0)))
6
+ if (!(typeof arg0 === 'string' || Array.isArray(arg0))) {
7
7
  throw new Error(`You must specify primary index column(s)`);
8
+ }
8
9
  const meta = EntityMetadata.define(target);
9
10
  EntityMetadata.setPrimaryKeys(meta, arg0, arg1);
10
11
  return;