@mikro-orm/core 7.1.10-dev.7 → 7.1.10-dev.9
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/drivers/DatabaseDriver.d.ts +6 -0
- package/drivers/DatabaseDriver.js +71 -9
- package/package.json +1 -1
- package/utils/Cursor.js +1 -6
- package/utils/Utils.js +1 -1
|
@@ -64,6 +64,12 @@ export declare abstract class DatabaseDriver<C extends Connection> implements ID
|
|
|
64
64
|
orderBy: OrderDefinition<T>[];
|
|
65
65
|
where: FilterQuery<T>;
|
|
66
66
|
};
|
|
67
|
+
/**
|
|
68
|
+
* Restores the JS value of a single cursor offset: ISO strings become `Date` instances based on the
|
|
69
|
+
* property type (never based on the string shape alone), and custom types are restored via
|
|
70
|
+
* `convertToJSValue`. Values compared against a JSON document keep their serialized form instead.
|
|
71
|
+
*/
|
|
72
|
+
private mapCursorOffset;
|
|
67
73
|
protected createCursorCondition<T extends object>(definition: (readonly [keyof T & string, QueryOrder])[], offsets: Dictionary[], inverse: boolean, meta: EntityMetadata<T>): FilterQuery<T>;
|
|
68
74
|
/** @internal */
|
|
69
75
|
mapDataToFieldNames(data: Dictionary, stringifyJsonArrays: boolean, properties?: Record<string, EntityProperty>, convertCustomTypes?: boolean, object?: boolean): Dictionary;
|
|
@@ -7,8 +7,11 @@ import { EntityManager } from '../EntityManager.js';
|
|
|
7
7
|
import { CursorError, ValidationError } from '../errors.js';
|
|
8
8
|
import { DriverException } from '../exceptions.js';
|
|
9
9
|
import { helper } from '../entity/wrap.js';
|
|
10
|
+
import { Reference } from '../entity/Reference.js';
|
|
10
11
|
import { PolymorphicRef } from '../entity/PolymorphicRef.js';
|
|
11
12
|
import { JsonType } from '../types/JsonType.js';
|
|
13
|
+
import { DateTimeType } from '../types/DateTimeType.js';
|
|
14
|
+
import { QueryHelper } from '../utils/QueryHelper.js';
|
|
12
15
|
import { MikroORM } from '../MikroORM.js';
|
|
13
16
|
/** Abstract base class for all database drivers, implementing common driver logic. */
|
|
14
17
|
export class DatabaseDriver {
|
|
@@ -141,13 +144,24 @@ export class DatabaseDriver {
|
|
|
141
144
|
return !!val && typeof val === 'object' && key in val;
|
|
142
145
|
};
|
|
143
146
|
const createCursor = (val, key, inverse = false) => {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
+
const def = Reference.unwrapReference((isCursor(val, key) ? val[key] : val));
|
|
148
|
+
let offsets;
|
|
149
|
+
// entity (and reference) instances are supported as cursors too, their properties are read the same way
|
|
150
|
+
if (Utils.isPlainObject(def) || Utils.isEntity(def)) {
|
|
151
|
+
// POJO values are already JS values, extract them ordered per the definition,
|
|
152
|
+
// without the JSON round trip `Cursor.for` + `Cursor.decode` would impose
|
|
153
|
+
offsets = definition.map(([key]) => {
|
|
154
|
+
if (def[key] === undefined) {
|
|
155
|
+
throw CursorError.missingValue(meta.className, key);
|
|
156
|
+
}
|
|
157
|
+
return def[key];
|
|
158
|
+
});
|
|
147
159
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
160
|
+
else {
|
|
161
|
+
/* v8 ignore next */
|
|
162
|
+
offsets = def ? Cursor.decode(def) : [];
|
|
163
|
+
}
|
|
164
|
+
if (definition.length > 0 && definition.length === offsets.length) {
|
|
151
165
|
return this.createCursorCondition(definition, offsets, inverse, meta);
|
|
152
166
|
}
|
|
153
167
|
/* v8 ignore next */
|
|
@@ -174,19 +188,66 @@ export class DatabaseDriver {
|
|
|
174
188
|
const dir = Utils.xor(desc, isLast) ? 'desc' : 'asc';
|
|
175
189
|
return { [prop]: dir };
|
|
176
190
|
};
|
|
191
|
+
// the cursor condition is created at the driver level, after the EM already converted custom types
|
|
192
|
+
// in the user `where`, so we need to run the same conversion over it explicitly
|
|
193
|
+
const where = QueryHelper.processWhere({
|
|
194
|
+
where: ($and.length > 1 ? { $and } : { ...$and[0] }),
|
|
195
|
+
entityName: meta.class,
|
|
196
|
+
metadata: this.metadata,
|
|
197
|
+
platform: this.platform,
|
|
198
|
+
convertCustomTypes: options.convertCustomTypes,
|
|
199
|
+
});
|
|
177
200
|
return {
|
|
178
201
|
orderBy: definition.map(([prop, direction]) => createOrderBy(prop, direction)),
|
|
179
|
-
where
|
|
202
|
+
where,
|
|
180
203
|
};
|
|
181
204
|
}
|
|
205
|
+
/**
|
|
206
|
+
* Restores the JS value of a single cursor offset: ISO strings become `Date` instances based on the
|
|
207
|
+
* property type (never based on the string shape alone), and custom types are restored via
|
|
208
|
+
* `convertToJSValue`. Values compared against a JSON document keep their serialized form instead.
|
|
209
|
+
*/
|
|
210
|
+
mapCursorOffset(prop, value, insideJson) {
|
|
211
|
+
if (Utils.isScalarReference(value)) {
|
|
212
|
+
value = value.unwrap();
|
|
213
|
+
}
|
|
214
|
+
// scalar direction on a relation orders by its primary key
|
|
215
|
+
if (Utils.isEntity(value, true)) {
|
|
216
|
+
value = helper(value).getPrimaryKey();
|
|
217
|
+
}
|
|
218
|
+
if (value == null) {
|
|
219
|
+
return value;
|
|
220
|
+
}
|
|
221
|
+
if (insideJson) {
|
|
222
|
+
// compared against the JSON document, which holds the serialized form
|
|
223
|
+
if (value instanceof Date) {
|
|
224
|
+
return value.toISOString();
|
|
225
|
+
}
|
|
226
|
+
// restore the JS value from the serialized form, `processWhere` then converts it to
|
|
227
|
+
// the database form, which is what the JSON document holds for custom typed props
|
|
228
|
+
return prop?.customType ? prop.customType.convertToJSValue(value, this.platform) : value;
|
|
229
|
+
}
|
|
230
|
+
if (typeof value === 'string' &&
|
|
231
|
+
(prop?.runtimeType === 'Date' ||
|
|
232
|
+
(prop?.customType && this.platform.getMappedType(prop.columnTypes?.[0] ?? '') instanceof DateTimeType))) {
|
|
233
|
+
value = new Date(value);
|
|
234
|
+
}
|
|
235
|
+
return prop?.customType ? prop.customType.convertToJSValue(value, this.platform) : value;
|
|
236
|
+
}
|
|
182
237
|
createCursorCondition(definition, offsets, inverse, meta) {
|
|
183
|
-
const createCondition = (prop, direction, offset, eq = false, path = prop) => {
|
|
238
|
+
const createCondition = (prop, direction, offset, eq = false, path = prop, properties = meta.properties, insideJson = false) => {
|
|
239
|
+
const propMeta = properties[prop];
|
|
184
240
|
if (Utils.isPlainObject(direction)) {
|
|
185
241
|
if (offset === undefined) {
|
|
186
242
|
throw CursorError.missingValue(meta.className, path);
|
|
187
243
|
}
|
|
244
|
+
// POJO cursors can carry entity, reference or embeddable class instances, read their properties directly
|
|
245
|
+
offset = Reference.unwrapReference(offset);
|
|
246
|
+
const childProps = propMeta?.kind === ReferenceKind.EMBEDDED ? propMeta.embeddedProps : propMeta?.targetMeta?.properties;
|
|
247
|
+
insideJson ||=
|
|
248
|
+
(propMeta?.kind === ReferenceKind.EMBEDDED && !!propMeta.object) || propMeta?.customType instanceof JsonType;
|
|
188
249
|
const value = Utils.keys(direction).reduce((o, key) => {
|
|
189
|
-
Object.assign(o, createCondition(key, direction[key], offset?.[key], eq, `${path}.${key}
|
|
250
|
+
Object.assign(o, createCondition(key, direction[key], offset?.[key], eq, `${path}.${key}`, childProps ?? {}, insideJson));
|
|
190
251
|
return o;
|
|
191
252
|
}, {});
|
|
192
253
|
return { [prop]: value };
|
|
@@ -209,6 +270,7 @@ export class DatabaseDriver {
|
|
|
209
270
|
if (offset === undefined) {
|
|
210
271
|
throw CursorError.missingValue(meta.className, path);
|
|
211
272
|
}
|
|
273
|
+
offset = this.mapCursorOffset(propMeta, offset, insideJson);
|
|
212
274
|
// Handle null offset (intentional null cursor value)
|
|
213
275
|
if (offset === null) {
|
|
214
276
|
if (eq) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mikro-orm/core",
|
|
3
|
-
"version": "7.1.10-dev.
|
|
3
|
+
"version": "7.1.10-dev.9",
|
|
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",
|
package/utils/Cursor.js
CHANGED
|
@@ -150,12 +150,7 @@ export class Cursor {
|
|
|
150
150
|
return Buffer.from(JSON.stringify(value)).toString('base64url');
|
|
151
151
|
}
|
|
152
152
|
static decode(value) {
|
|
153
|
-
return JSON.parse(Buffer.from(value, 'base64url').toString('utf8'))
|
|
154
|
-
if (typeof value === 'string' && /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}/.exec(value)) {
|
|
155
|
-
return new Date(value);
|
|
156
|
-
}
|
|
157
|
-
return value;
|
|
158
|
-
});
|
|
153
|
+
return JSON.parse(Buffer.from(value, 'base64url').toString('utf8'));
|
|
159
154
|
}
|
|
160
155
|
static getDefinition(meta, orderBy) {
|
|
161
156
|
return Utils.asArray(orderBy).flatMap(order => {
|
package/utils/Utils.js
CHANGED
|
@@ -153,7 +153,7 @@ export function parseJsonSafe(value) {
|
|
|
153
153
|
/** Collection of general-purpose utility methods used throughout the ORM. */
|
|
154
154
|
export class Utils {
|
|
155
155
|
static PK_SEPARATOR = '~~~';
|
|
156
|
-
static #ORM_VERSION = '7.1.10-dev.
|
|
156
|
+
static #ORM_VERSION = '7.1.10-dev.9';
|
|
157
157
|
/**
|
|
158
158
|
* Checks if the argument is instance of `Object`. Returns false for arrays.
|
|
159
159
|
*/
|