@mikro-orm/core 7.0.10-dev.10 → 7.0.10-dev.11

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mikro-orm/core",
3
- "version": "7.0.10-dev.10",
3
+ "version": "7.0.10-dev.11",
4
4
  "description": "TypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, PostgreSQL and SQLite databases as well as usage with vanilla JavaScript.",
5
5
  "keywords": [
6
6
  "data-mapper",
@@ -4,6 +4,8 @@ declare const rawFragmentSymbolBrand: unique symbol;
4
4
  export type RawQueryFragmentSymbol = symbol & {
5
5
  readonly [rawFragmentSymbolBrand]: true;
6
6
  };
7
+ /** Checks whether the given value is a `RawQueryFragment` instance. */
8
+ export declare function isRaw(value: unknown): value is RawQueryFragment;
7
9
  /** Represents a raw SQL fragment with optional parameters, usable as both a value and an object key via Symbol coercion. */
8
10
  export declare class RawQueryFragment<Alias extends string = string> {
9
11
  #private;
@@ -30,8 +32,6 @@ export declare class RawQueryFragment<Alias extends string = string> {
30
32
  static getKnownFragment(key: unknown): RawQueryFragment | undefined;
31
33
  }
32
34
  export { RawQueryFragment as Raw };
33
- /** Checks whether the given value is a `RawQueryFragment` instance. */
34
- export declare function isRaw(value: unknown): value is RawQueryFragment;
35
35
  /** @internal */
36
36
  export declare const ALIAS_REPLACEMENT = "[::alias::]";
37
37
  /** @internal */
@@ -1,21 +1,53 @@
1
1
  import { Utils } from './Utils.js';
2
- const rawSymbol = Symbol('RawQueryFragment');
2
+ // Brand lives on the prototype so JSON payloads — whose proto is
3
+ // `Object.prototype` — cannot forge it. String key, not a `Symbol.for(...)`,
4
+ // so each CJS/ESM copy of this module independently installs it on its own
5
+ // prototype without publishing a global key for the marker that controls raw
6
+ // SQL assembly. The string is namespaced so it does not collide with property
7
+ // names users might independently install on their own prototypes.
8
+ const RAW_FRAGMENT_BRAND = '__mikroOrmRawFragment';
9
+ // Back-references from a fragment's symbol key to the fragment itself, shared
10
+ // across CJS/ESM module copies via globalThis: when one copy creates a fragment
11
+ // via `raw('…')` and stores its symbol in a where-clause object key, the other
12
+ // copy still needs to recover the original fragment to assemble SQL.
13
+ const REGISTRY_KEY = Symbol.for('@mikro-orm/core/RawQueryFragment.references');
14
+ const rawQueryReferences = (globalThis[REGISTRY_KEY] ??=
15
+ new WeakMap());
16
+ /** Checks whether the given value is a `RawQueryFragment` instance. */
17
+ export function isRaw(value) {
18
+ if (value == null || typeof value !== 'object') {
19
+ return false;
20
+ }
21
+ // Fast path: intra-module instances and their subclasses.
22
+ // eslint-disable-next-line no-use-before-define
23
+ if (value instanceof RawQueryFragment) {
24
+ return true;
25
+ }
26
+ // Walk the prototype chain starting from the *prototype* (not the value) so
27
+ // own-property spoofing from JSON payloads cannot forge the brand. Stop at
28
+ // `Object.prototype`, which is never branded — that bails plain objects,
29
+ // JSON payloads, and built-ins like `Date`/`Array`/`Map` at depth 1.
30
+ for (let p = Object.getPrototypeOf(value); p != null && p !== Object.prototype; p = Object.getPrototypeOf(p)) {
31
+ if (Object.hasOwn(p, RAW_FRAGMENT_BRAND)) {
32
+ return true;
33
+ }
34
+ }
35
+ return false;
36
+ }
3
37
  /** Represents a raw SQL fragment with optional parameters, usable as both a value and an object key via Symbol coercion. */
4
38
  export class RawQueryFragment {
5
39
  sql;
6
40
  params;
7
- static #rawQueryReferences = new WeakMap();
8
41
  #key;
9
42
  constructor(sql, params = []) {
10
43
  this.sql = sql;
11
44
  this.params = params;
12
- Object.defineProperty(this, rawSymbol, { value: true, enumerable: false });
13
45
  }
14
46
  /** Returns a unique symbol key for this fragment, creating and caching it on first access. */
15
47
  get key() {
16
48
  if (!this.#key) {
17
49
  this.#key = Symbol(this.toJSON());
18
- RawQueryFragment.#rawQueryReferences.set(this.#key, this);
50
+ rawQueryReferences.set(this.#key, this);
19
51
  }
20
52
  return this.#key;
21
53
  }
@@ -42,7 +74,7 @@ export class RawQueryFragment {
42
74
  }
43
75
  /** Checks whether the given value is a symbol that maps to a known raw query fragment. */
44
76
  static isKnownFragmentSymbol(key) {
45
- return typeof key === 'symbol' && this.#rawQueryReferences.has(key);
77
+ return typeof key === 'symbol' && rawQueryReferences.has(key);
46
78
  }
47
79
  /** Checks whether an object has any symbol keys that are known raw query fragments. */
48
80
  static hasObjectFragments(object) {
@@ -51,20 +83,17 @@ export class RawQueryFragment {
51
83
  }
52
84
  /** Checks whether the given value is a RawQueryFragment instance or a known fragment symbol. */
53
85
  static isKnownFragment(key) {
54
- if (key instanceof RawQueryFragment) {
55
- return true;
56
- }
57
- return this.isKnownFragmentSymbol(key);
86
+ return isRaw(key) || this.isKnownFragmentSymbol(key);
58
87
  }
59
88
  /** Retrieves the RawQueryFragment associated with the given key (instance or symbol). */
60
89
  static getKnownFragment(key) {
61
- if (key instanceof RawQueryFragment) {
90
+ if (isRaw(key)) {
62
91
  return key;
63
92
  }
64
93
  if (typeof key !== 'symbol') {
65
94
  return;
66
95
  }
67
- return this.#rawQueryReferences.get(key);
96
+ return rawQueryReferences.get(key);
68
97
  }
69
98
  /** @ignore */
70
99
  /* v8 ignore next */
@@ -75,11 +104,19 @@ export class RawQueryFragment {
75
104
  return { sql: this.sql };
76
105
  }
77
106
  }
107
+ // Non-enumerable so the brand is skipped by JSON/Object.keys/for-in, and locked
108
+ // down (non-writable, non-configurable) so in-process code cannot delete or
109
+ // overwrite it and thereby silently disable `isRaw` recognition for every
110
+ // fragment in the process. Subclasses don't need mutability here — they inherit
111
+ // the brand via the prototype chain, and sibling-copy classes install their own
112
+ // brand on their own prototype (a different object), so lockdown only blocks
113
+ // tampering with the canonical marker.
114
+ Object.defineProperty(RawQueryFragment.prototype, RAW_FRAGMENT_BRAND, {
115
+ value: true,
116
+ writable: false,
117
+ configurable: false,
118
+ });
78
119
  export { RawQueryFragment as Raw };
79
- /** Checks whether the given value is a `RawQueryFragment` instance. */
80
- export function isRaw(value) {
81
- return typeof value === 'object' && value !== null && Object.hasOwn(value, rawSymbol);
82
- }
83
120
  /** @internal */
84
121
  export const ALIAS_REPLACEMENT = '[::alias::]';
85
122
  /** @internal */
@@ -140,7 +177,7 @@ export const ALIAS_REPLACEMENT_RE = '\\[::alias::\\]';
140
177
  * ```
141
178
  */
142
179
  export function raw(sql, params) {
143
- if (sql instanceof RawQueryFragment) {
180
+ if (isRaw(sql)) {
144
181
  return sql;
145
182
  }
146
183
  if (sql instanceof Function) {
package/utils/Utils.js CHANGED
@@ -22,13 +22,22 @@ export function compareObjects(a, b) {
22
22
  if (a === b || (a == null && b == null)) {
23
23
  return true;
24
24
  }
25
- if (!a || !b || typeof a !== 'object' || typeof b !== 'object' || !compareConstructors(a, b)) {
25
+ if (!a || !b || typeof a !== 'object' || typeof b !== 'object') {
26
26
  return false;
27
27
  }
28
+ // Raw fragments are compared by `sql` + `params` *before* the constructor
29
+ // check, so that two fragments carrying the same SQL but constructed by
30
+ // different CJS/ESM copies of this module (different classes, different
31
+ // prototypes) still compare as equal. Without this, the dual-package hazard
32
+ // would produce spurious change-set diffs when a raw fragment is used as a
33
+ // property value.
28
34
  if (isRaw(a) && isRaw(b)) {
29
35
  // eslint-disable-next-line @typescript-eslint/no-use-before-define
30
36
  return a.sql === b.sql && compareArrays(a.params, b.params);
31
37
  }
38
+ if (!compareConstructors(a, b)) {
39
+ return false;
40
+ }
32
41
  if (a instanceof Date && b instanceof Date) {
33
42
  const timeA = a.getTime();
34
43
  const timeB = b.getTime();
@@ -132,7 +141,7 @@ export function parseJsonSafe(value) {
132
141
  /** Collection of general-purpose utility methods used throughout the ORM. */
133
142
  export class Utils {
134
143
  static PK_SEPARATOR = '~~~';
135
- static #ORM_VERSION = '7.0.10-dev.10';
144
+ static #ORM_VERSION = '7.0.10-dev.11';
136
145
  /**
137
146
  * Checks if the argument is instance of `Object`. Returns false for arrays.
138
147
  */