@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 +1 -1
- package/utils/RawQueryFragment.d.ts +2 -2
- package/utils/RawQueryFragment.js +53 -16
- package/utils/Utils.js +11 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mikro-orm/core",
|
|
3
|
-
"version": "7.0.10-dev.
|
|
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
|
-
|
|
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
|
-
|
|
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' &&
|
|
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
|
-
|
|
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
|
|
90
|
+
if (isRaw(key)) {
|
|
62
91
|
return key;
|
|
63
92
|
}
|
|
64
93
|
if (typeof key !== 'symbol') {
|
|
65
94
|
return;
|
|
66
95
|
}
|
|
67
|
-
return
|
|
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
|
|
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'
|
|
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.
|
|
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
|
*/
|