@mikro-orm/sql 7.0.0-dev.113 → 7.0.0-dev.115

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.
@@ -1,12 +1,12 @@
1
- import { type Dictionary, type EntityKey, type EntityMetadata, type MetadataStorage } from '@mikro-orm/core';
1
+ import { type Dictionary, type EntityKey, type EntityMetadata, type EntityName, type MetadataStorage, type RawQueryFragmentSymbol } from '@mikro-orm/core';
2
2
  import type { ICriteriaNode } from '../typings.js';
3
3
  /**
4
4
  * @internal
5
5
  */
6
6
  export declare class CriteriaNodeFactory {
7
- static createNode<T extends object>(metadata: MetadataStorage, entityName: string, payload: any, parent?: ICriteriaNode<T>, key?: EntityKey<T>): ICriteriaNode<T>;
8
- static createScalarNode<T extends object>(metadata: MetadataStorage, entityName: string, payload: any, parent?: ICriteriaNode<T>, key?: EntityKey<T>): ICriteriaNode<T>;
9
- static createArrayNode<T extends object>(metadata: MetadataStorage, entityName: string, payload: any[], parent?: ICriteriaNode<T>, key?: EntityKey<T>): ICriteriaNode<T>;
10
- static createObjectNode<T extends object>(metadata: MetadataStorage, entityName: string, payload: Dictionary, parent?: ICriteriaNode<T>, key?: EntityKey<T>): ICriteriaNode<T>;
11
- static createObjectItemNode<T extends object>(metadata: MetadataStorage, entityName: string, node: ICriteriaNode<T>, payload: Dictionary, key: EntityKey<T>, meta?: EntityMetadata<T>): ICriteriaNode<T>;
7
+ static createNode<T extends object>(metadata: MetadataStorage, entityName: EntityName<T>, payload: any, parent?: ICriteriaNode<T>, key?: EntityKey<T> | RawQueryFragmentSymbol): ICriteriaNode<T>;
8
+ static createScalarNode<T extends object>(metadata: MetadataStorage, entityName: EntityName<T>, payload: any, parent?: ICriteriaNode<T>, key?: EntityKey<T> | RawQueryFragmentSymbol): ICriteriaNode<T>;
9
+ static createArrayNode<T extends object>(metadata: MetadataStorage, entityName: EntityName<T>, payload: any[], parent?: ICriteriaNode<T>, key?: EntityKey<T>): ICriteriaNode<T>;
10
+ static createObjectNode<T extends object>(metadata: MetadataStorage, entityName: EntityName<T>, payload: Dictionary, parent?: ICriteriaNode<T>, key?: EntityKey<T>): ICriteriaNode<T>;
11
+ static createObjectItemNode<T extends object>(metadata: MetadataStorage, entityName: EntityName<T>, node: ICriteriaNode<T>, payload: Dictionary, key: EntityKey<T> | RawQueryFragmentSymbol, meta?: EntityMetadata<T>): ICriteriaNode<T>;
12
12
  }
@@ -7,8 +7,8 @@ import { ScalarCriteriaNode } from './ScalarCriteriaNode.js';
7
7
  */
8
8
  export class CriteriaNodeFactory {
9
9
  static createNode(metadata, entityName, payload, parent, key) {
10
- const customExpression = RawQueryFragment.isKnownFragment(key || '');
11
- const scalar = Utils.isPrimaryKey(payload) || isRaw(payload) || payload instanceof RegExp || payload instanceof Date || customExpression;
10
+ const rawField = RawQueryFragment.isKnownFragmentSymbol(key);
11
+ const scalar = Utils.isPrimaryKey(payload) || isRaw(payload) || payload instanceof RegExp || payload instanceof Date || rawField;
12
12
  if (Array.isArray(payload) && !scalar) {
13
13
  return this.createArrayNode(metadata, entityName, payload, parent, key);
14
14
  }
@@ -38,25 +38,27 @@ export class CriteriaNodeFactory {
38
38
  const meta = metadata.find(entityName);
39
39
  const node = new ObjectCriteriaNode(metadata, entityName, parent, key, true, payload.__strict);
40
40
  node.payload = {};
41
- for (const key of Object.keys(payload)) {
42
- node.payload[key] = this.createObjectItemNode(metadata, entityName, node, payload, key, meta);
41
+ for (const k of Utils.getObjectQueryKeys(payload)) {
42
+ node.payload[k] = this.createObjectItemNode(metadata, entityName, node, payload, k, meta);
43
43
  }
44
44
  return node;
45
45
  }
46
46
  static createObjectItemNode(metadata, entityName, node, payload, key, meta) {
47
- const prop = meta?.properties[key];
48
- const childEntity = prop && prop.kind !== ReferenceKind.SCALAR ? prop.type : entityName;
49
- const isNotEmbedded = prop?.kind !== ReferenceKind.EMBEDDED;
47
+ const rawField = RawQueryFragment.isKnownFragmentSymbol(key);
48
+ const prop = rawField ? null : meta?.properties[key];
49
+ const childEntity = prop && prop.kind !== ReferenceKind.SCALAR ? prop.targetMeta.class : entityName;
50
+ const isNotEmbedded = rawField || prop?.kind !== ReferenceKind.EMBEDDED;
51
+ const val = payload[key];
50
52
  if (isNotEmbedded && prop?.customType instanceof JsonType) {
51
- return this.createScalarNode(metadata, childEntity, payload[key], node, key);
53
+ return this.createScalarNode(metadata, childEntity, val, node, key);
52
54
  }
53
- if (prop?.kind === ReferenceKind.SCALAR && payload[key] != null && Object.keys(payload[key]).some(f => f in GroupOperator)) {
55
+ if (prop?.kind === ReferenceKind.SCALAR && val != null && Object.keys(val).some(f => f in GroupOperator)) {
54
56
  throw ValidationError.cannotUseGroupOperatorsInsideScalars(entityName, prop.name, payload);
55
57
  }
56
58
  if (isNotEmbedded) {
57
- return this.createNode(metadata, childEntity, payload[key], node, key);
59
+ return this.createNode(metadata, childEntity, val, node, key);
58
60
  }
59
- if (payload[key] == null) {
61
+ if (val == null) {
60
62
  const map = Object.keys(prop.embeddedProps).reduce((oo, k) => {
61
63
  oo[prop.embeddedProps[k].name] = null;
62
64
  return oo;
@@ -65,23 +67,23 @@ export class CriteriaNodeFactory {
65
67
  }
66
68
  // array operators can be used on embedded properties
67
69
  const allowedOperators = ['$contains', '$contained', '$overlap'];
68
- const operator = Object.keys(payload[key]).some(f => Utils.isOperator(f) && !allowedOperators.includes(f));
70
+ const operator = Object.keys(val).some(f => Utils.isOperator(f) && !allowedOperators.includes(f));
69
71
  if (operator) {
70
72
  throw ValidationError.cannotUseOperatorsInsideEmbeddables(entityName, prop.name, payload);
71
73
  }
72
- const map = Object.keys(payload[key]).reduce((oo, k) => {
74
+ const map = Object.keys(val).reduce((oo, k) => {
73
75
  const embeddedProp = prop.embeddedProps[k] ?? Object.values(prop.embeddedProps).find(p => p.name === k);
74
76
  if (!embeddedProp && !allowedOperators.includes(k)) {
75
77
  throw ValidationError.invalidEmbeddableQuery(entityName, k, prop.type);
76
78
  }
77
79
  if (embeddedProp) {
78
- oo[embeddedProp.name] = payload[key][k];
80
+ oo[embeddedProp.name] = val[k];
79
81
  }
80
- else if (typeof payload[key][k] === 'object') {
81
- oo[k] = JSON.stringify(payload[key][k]);
82
+ else if (typeof val[k] === 'object') {
83
+ oo[k] = JSON.stringify(val[k]);
82
84
  }
83
85
  else {
84
- oo[k] = payload[key][k];
86
+ oo[k] = val[k];
85
87
  }
86
88
  return oo;
87
89
  }, {});
@@ -27,8 +27,7 @@ export class NativeQueryBuilder {
27
27
  }
28
28
  from(tableName, options) {
29
29
  if (tableName instanceof NativeQueryBuilder) {
30
- const { sql, params } = tableName.compile();
31
- tableName = raw(sql, params);
30
+ tableName = tableName.toRaw();
32
31
  }
33
32
  if (typeof tableName === 'string') {
34
33
  const alias = options?.alias ? ` as ${this.platform.quoteIdentifier(options.alias)}` : '';
@@ -9,7 +9,7 @@ export class ObjectCriteriaNode extends CriteriaNode {
9
9
  const matchPopulateJoins = options?.matchPopulateJoins || (this.prop && [ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(this.prop.kind));
10
10
  const nestedAlias = qb.getAliasForJoinPath(this.getPath(), { ...options, matchPopulateJoins });
11
11
  const ownerAlias = options?.alias || qb.alias;
12
- const keys = Object.keys(this.payload);
12
+ const keys = Utils.getObjectQueryKeys(this.payload);
13
13
  let alias = options?.alias;
14
14
  if (nestedAlias) {
15
15
  alias = nestedAlias;
@@ -31,14 +31,14 @@ export class ObjectCriteriaNode extends CriteriaNode {
31
31
  return [QueryType.SELECT, QueryType.COUNT].includes(qb.type) ? `${knownKey ? alias : ownerAlias}.${pk}` : pk;
32
32
  });
33
33
  for (const key of keys) {
34
- if (!['$some', '$none', '$every'].includes(key)) {
34
+ if (typeof key !== 'string' || !['$some', '$none', '$every'].includes(key)) {
35
35
  throw new Error('Mixing collection operators with other filters is not allowed.');
36
36
  }
37
37
  const payload = this.payload[key].unwrap();
38
38
  const qb2 = qb.clone(true);
39
39
  const sub = qb2
40
- .from(parentMeta.className)
41
- .innerJoin(this.key, qb2.getNextAlias(this.prop.type))
40
+ .from(parentMeta.class)
41
+ .innerJoin(this.key, qb2.getNextAlias(this.prop.targetMeta.class))
42
42
  .select(parentMeta.primaryKeys);
43
43
  if (key === '$every') {
44
44
  sub.where({ $not: { [this.key]: payload } });
@@ -78,7 +78,7 @@ export class ObjectCriteriaNode extends CriteriaNode {
78
78
  const childNode = this.payload[field];
79
79
  const payload = childNode.process(qb, { ...options, alias: this.prop ? alias : ownerAlias });
80
80
  const operator = Utils.isOperator(field);
81
- const isRawField = RawQueryFragment.isKnownFragment(field);
81
+ const isRawField = RawQueryFragment.isKnownFragmentSymbol(field);
82
82
  // we need to keep the prefixing for formulas otherwise we would lose aliasing context when nesting inside group operators
83
83
  const virtual = childNode.prop?.persist === false && !childNode.prop?.formula;
84
84
  // if key is missing, we are inside group operator and we need to prefix with alias
@@ -100,18 +100,18 @@ export class ObjectCriteriaNode extends CriteriaNode {
100
100
  this.inlineCondition(field.replaceAll(ALIAS_REPLACEMENT, alias), o, payload);
101
101
  }
102
102
  else {
103
- this.inlineCondition(`${alias}.${field}`, o, payload);
103
+ this.inlineCondition(`${alias ?? qb.alias}.${field}`, o, payload);
104
104
  }
105
105
  return o;
106
106
  }, {});
107
107
  }
108
108
  isStrict() {
109
- return this.strict || Object.keys(this.payload).some(key => {
109
+ return this.strict || Utils.getObjectQueryKeys(this.payload).some(key => {
110
110
  return this.payload[key].isStrict();
111
111
  });
112
112
  }
113
113
  unwrap() {
114
- return Object.keys(this.payload).reduce((o, field) => {
114
+ return Utils.getObjectQueryKeys(this.payload).reduce((o, field) => {
115
115
  o[field] = this.payload[field].unwrap();
116
116
  return o;
117
117
  }, {});
@@ -119,7 +119,7 @@ export class ObjectCriteriaNode extends CriteriaNode {
119
119
  willAutoJoin(qb, alias, options) {
120
120
  const nestedAlias = qb.getAliasForJoinPath(this.getPath(), options);
121
121
  const ownerAlias = alias || qb.alias;
122
- const keys = Object.keys(this.payload);
122
+ const keys = Utils.getObjectQueryKeys(this.payload);
123
123
  if (nestedAlias) {
124
124
  alias = nestedAlias;
125
125
  }
@@ -132,9 +132,9 @@ export class ObjectCriteriaNode extends CriteriaNode {
132
132
  });
133
133
  }
134
134
  shouldInline(payload) {
135
- const customExpression = RawQueryFragment.isKnownFragment(this.key);
136
- const scalar = Utils.isPrimaryKey(payload) || payload instanceof RegExp || payload instanceof Date || customExpression;
137
- const operator = Utils.isObject(payload) && Object.keys(payload).every(k => Utils.isOperator(k, false));
135
+ const rawField = RawQueryFragment.isKnownFragmentSymbol(this.key);
136
+ const scalar = Utils.isPrimaryKey(payload) || payload instanceof RegExp || payload instanceof Date || rawField;
137
+ const operator = Utils.isObject(payload) && Utils.getObjectQueryKeys(payload).every(k => Utils.isOperator(k, false));
138
138
  return !!this.prop && this.prop.kind !== ReferenceKind.SCALAR && !scalar && !operator;
139
139
  }
140
140
  getChildKey(k, prop, childAlias, alias) {
@@ -145,8 +145,8 @@ export class ObjectCriteriaNode extends CriteriaNode {
145
145
  }
146
146
  inlineArrayChildPayload(obj, payload, k, prop, childAlias, alias) {
147
147
  const key = this.getChildKey(k, prop, childAlias);
148
- const value = payload.map((child) => Object.keys(child).reduce((inner, childKey) => {
149
- const key = (this.isPrefixed(childKey) || Utils.isOperator(childKey)) ? childKey : this.aliased(childKey, childAlias);
148
+ const value = payload.map((child) => Utils.getObjectQueryKeys(child).reduce((inner, childKey) => {
149
+ const key = (RawQueryFragment.isKnownFragmentSymbol(childKey) || this.isPrefixed(childKey) || Utils.isOperator(childKey)) ? childKey : this.aliased(childKey, childAlias);
150
150
  inner[key] = child[childKey];
151
151
  return inner;
152
152
  }, {}));
@@ -154,8 +154,11 @@ export class ObjectCriteriaNode extends CriteriaNode {
154
154
  }
155
155
  inlineChildPayload(o, payload, field, alias, childAlias) {
156
156
  const prop = this.metadata.find(this.entityName).properties[field];
157
- for (const k of Object.keys(payload)) {
158
- if (Utils.isOperator(k, false)) {
157
+ for (const k of Utils.getObjectQueryKeys(payload)) {
158
+ if (RawQueryFragment.isKnownFragmentSymbol(k)) {
159
+ o[k] = payload[k];
160
+ }
161
+ else if (Utils.isOperator(k, false)) {
159
162
  const tmp = payload[k];
160
163
  delete payload[k];
161
164
  o[this.aliased(field, alias)] = { [k]: tmp, ...o[this.aliased(field, alias)] };
@@ -167,9 +170,6 @@ export class ObjectCriteriaNode extends CriteriaNode {
167
170
  const key = this.getChildKey(k, prop, childAlias, alias);
168
171
  this.inlineCondition(key, o, payload[k]);
169
172
  }
170
- else if (RawQueryFragment.isKnownFragment(k)) {
171
- o[k] = payload[k];
172
- }
173
173
  else {
174
174
  o[this.aliased(k, childAlias)] = payload[k];
175
175
  }
@@ -194,8 +194,8 @@ export class ObjectCriteriaNode extends CriteriaNode {
194
194
  if (!this.prop || !this.parent) {
195
195
  return false;
196
196
  }
197
- const keys = Object.keys(this.payload);
198
- if (keys.every(k => k.includes('.') && k.startsWith(`${qb.alias}.`))) {
197
+ const keys = Utils.getObjectQueryKeys(this.payload);
198
+ if (keys.every(k => typeof k === 'string' && k.includes('.') && k.startsWith(`${qb.alias}.`))) {
199
199
  return false;
200
200
  }
201
201
  if (keys.some(k => ['$some', '$none', '$every'].includes(k))) {
@@ -206,21 +206,21 @@ export class ObjectCriteriaNode extends CriteriaNode {
206
206
  const knownKey = [ReferenceKind.SCALAR, ReferenceKind.MANY_TO_ONE, ReferenceKind.EMBEDDED].includes(this.prop.kind) || (this.prop.kind === ReferenceKind.ONE_TO_ONE && this.prop.owner);
207
207
  const operatorKeys = knownKey && keys.every(key => Utils.isOperator(key, false));
208
208
  const primaryKeys = knownKey && keys.every(key => {
209
- if (!meta.primaryKeys.includes(key)) {
209
+ if (typeof key !== 'string' || !meta.primaryKeys.includes(key)) {
210
210
  return false;
211
211
  }
212
212
  if (!Utils.isPlainObject(this.payload[key].payload) || ![ReferenceKind.ONE_TO_ONE, ReferenceKind.MANY_TO_ONE].includes(meta.properties[key].kind)) {
213
213
  return true;
214
214
  }
215
- return Object.keys(this.payload[key].payload).every(k => meta.properties[key].targetMeta.primaryKeys.includes(k));
215
+ return Utils.getObjectQueryKeys(this.payload[key].payload).every(k => typeof k === 'string' && meta.properties[key].targetMeta.primaryKeys.includes(k));
216
216
  });
217
217
  return !primaryKeys && !nestedAlias && !operatorKeys && !embeddable;
218
218
  }
219
219
  autoJoin(qb, alias, options) {
220
- const nestedAlias = qb.getNextAlias(this.prop?.pivotTable ?? this.entityName);
221
- const customExpression = RawQueryFragment.isKnownFragment(this.key);
222
- const scalar = Utils.isPrimaryKey(this.payload) || this.payload instanceof RegExp || this.payload instanceof Date || customExpression;
223
- const operator = Utils.isPlainObject(this.payload) && Object.keys(this.payload).every(k => Utils.isOperator(k, false));
220
+ const nestedAlias = qb.getNextAlias(this.prop?.pivotEntity ?? this.entityName);
221
+ const rawField = RawQueryFragment.isKnownFragmentSymbol(this.key);
222
+ const scalar = Utils.isPrimaryKey(this.payload) || this.payload instanceof RegExp || this.payload instanceof Date || rawField;
223
+ const operator = Utils.isPlainObject(this.payload) && Utils.getObjectQueryKeys(this.payload).every(k => Utils.isOperator(k, false));
224
224
  const field = `${alias}.${this.prop.name}`;
225
225
  const method = qb.hasFlag(QueryFlag.INFER_POPULATE) ? 'joinAndSelect' : 'join';
226
226
  const path = this.getPath();
@@ -98,8 +98,6 @@ export declare class QueryBuilder<Entity extends object = AnyEntity, RootAlias e
98
98
  __populateWhere?: ObjectQuery<Entity> | PopulateHint | `${PopulateHint}`;
99
99
  /** @internal */
100
100
  _populateMap: Dictionary<string>;
101
- /** @internal */
102
- readonly rawFragments: Set<string>;
103
101
  protected aliasCounter: number;
104
102
  protected flags: Set<QueryFlag>;
105
103
  protected finalized: boolean;
@@ -175,11 +173,11 @@ export declare class QueryBuilder<Entity extends object = AnyEntity, RootAlias e
175
173
  applyJoinedFilters(em: EntityManager, filterOptions: FilterOptions | undefined): Promise<void>;
176
174
  withSubQuery(subQuery: RawQueryFragment | NativeQueryBuilder, alias: string): this;
177
175
  where(cond: QBFilterQuery<Entity>, operator?: keyof typeof GroupOperator): this;
178
- where(cond: string, params?: any[], operator?: keyof typeof GroupOperator): this;
176
+ where(cond: string | RawQueryFragment, params?: any[], operator?: keyof typeof GroupOperator): this;
179
177
  andWhere(cond: QBFilterQuery<Entity>): this;
180
- andWhere(cond: string, params?: any[]): this;
178
+ andWhere(cond: string | RawQueryFragment, params?: any[]): this;
181
179
  orWhere(cond: QBFilterQuery<Entity>): this;
182
- orWhere(cond: string, params?: any[]): this;
180
+ orWhere(cond: string | RawQueryFragment, params?: any[]): this;
183
181
  orderBy(orderBy: QBQueryOrderMap<Entity> | QBQueryOrderMap<Entity>[]): SelectQueryBuilder<Entity, RootAlias, Hint, Context>;
184
182
  andOrderBy(orderBy: QBQueryOrderMap<Entity> | QBQueryOrderMap<Entity>[]): SelectQueryBuilder<Entity, RootAlias, Hint, Context>;
185
183
  private processOrderBy;
@@ -222,13 +220,9 @@ export declare class QueryBuilder<Entity extends object = AnyEntity, RootAlias e
222
220
  * Specifies FROM which entity's table select/update/delete will be executed, removing all previously set FROM-s.
223
221
  * Allows setting a main string alias of the selection data.
224
222
  */
225
- from<Entity extends AnyEntity<Entity> = AnyEntity>(target: QueryBuilder<Entity>, aliasName?: string): SelectQueryBuilder<Entity, RootAlias, Hint, Context>;
226
- from<Entity extends AnyEntity<Entity> = AnyEntity>(target: EntityName<Entity>): SelectQueryBuilder<Entity, RootAlias, Hint, Context>;
223
+ from<Entity extends object>(target: QueryBuilder<Entity>, aliasName?: string): SelectQueryBuilder<Entity, RootAlias, Hint, Context>;
224
+ from<Entity extends object>(target: EntityName<Entity>): SelectQueryBuilder<Entity, RootAlias, Hint, Context>;
227
225
  getNativeQuery(processVirtualEntity?: boolean): NativeQueryBuilder;
228
- /**
229
- * @internal
230
- */
231
- clearRawFragmentsCache(): void;
232
226
  /**
233
227
  * Returns the query with parameters as wildcards.
234
228
  */
@@ -260,11 +254,11 @@ export declare class QueryBuilder<Entity extends object = AnyEntity, RootAlias e
260
254
  /**
261
255
  * @internal
262
256
  */
263
- getNextAlias(entityName?: string): string;
257
+ getNextAlias(entityName?: string | EntityName): string;
264
258
  /**
265
259
  * @internal
266
260
  */
267
- getAliasMap(): Dictionary<string>;
261
+ getAliasMap(): Dictionary<EntityName>;
268
262
  /**
269
263
  * Executes this QB and returns the raw results, mapped to the property names (unless disabled via last parameter).
270
264
  * Use `method` to specify what kind of result you want to get (array/single/meta).
@@ -313,9 +307,13 @@ export declare class QueryBuilder<Entity extends object = AnyEntity, RootAlias e
313
307
  getResultAndCount(): Promise<[Entity[], number]>;
314
308
  /**
315
309
  * Returns native query builder instance with sub-query aliased with given alias.
316
- * You can provide `EntityName.propName` as alias, then the field name will be used based on the metadata
317
310
  */
318
311
  as(alias: string): NativeQueryBuilder;
312
+ /**
313
+ * Returns native query builder instance with sub-query aliased with given alias.
314
+ * You can provide the target entity name as the first parameter and use the second parameter to point to an existing property to infer its field name.
315
+ */
316
+ as<T>(targetEntity: EntityName<T>, alias: EntityKey<T>): NativeQueryBuilder;
319
317
  clone(reset?: boolean | string[]): QueryBuilder<Entity>;
320
318
  /**
321
319
  * Sets logger context for this query builder.