@mikro-orm/core
Advanced tools
+1
-1
| { | ||
| "name": "@mikro-orm/core", | ||
| "version": "7.1.8-dev.13", | ||
| "version": "7.1.8-dev.14", | ||
| "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,0 +5,0 @@ "keywords": [ |
@@ -43,2 +43,7 @@ import type { Dictionary, EntityMetadata, EntityName, EntityProperty, FilterDef, FilterQuery } from '../typings.js'; | ||
| static processCustomType<T extends object>(prop: EntityProperty<T>, cond: FilterQuery<T>, platform: Platform, key?: string, fromQuery?: boolean): FilterQuery<T>; | ||
| /** | ||
| * Composite PK conditions are keyed by a hash of all the PK names, which `findProperty` cannot | ||
| * resolve, so the custom types have to be applied positionally instead. | ||
| */ | ||
| private static processCompositeCustomTypes; | ||
| private static isSupportedOperator; | ||
@@ -45,0 +50,0 @@ private static processJsonCondition; |
+25
-0
@@ -230,2 +230,9 @@ import { Reference } from '../entity/Reference.js'; | ||
| } | ||
| else if (!prop && | ||
| meta?.compositePK && | ||
| convertCustomTypes && | ||
| Array.isArray(value) && | ||
| key === Utils.getPrimaryKeyHash(meta.primaryKeys)) { | ||
| value = QueryHelper.processCompositeCustomTypes(value, meta, platform); | ||
| } | ||
| // oxfmt-ignore | ||
@@ -325,2 +332,20 @@ const isJsonProperty = prop?.customType instanceof JsonType && !isRaw(value) && (Utils.isPlainObject(value) ? !['$eq', '$elemMatch'].includes(Object.keys(value)[0]) : !Array.isArray(value)); | ||
| } | ||
| /** | ||
| * Composite PK conditions are keyed by a hash of all the PK names, which `findProperty` cannot | ||
| * resolve, so the custom types have to be applied positionally instead. | ||
| */ | ||
| static processCompositeCustomTypes(value, meta, platform) { | ||
| const props = meta.primaryKeys.map(pk => meta.properties[pk]); | ||
| if (!props.some(prop => prop.customType)) { | ||
| return value; | ||
| } | ||
| // the tuple can be longer than the PK when the user passes a malformed condition | ||
| const convert = (tuple) => tuple.map((val, idx) => { | ||
| if (!props[idx]?.customType) { | ||
| return val; | ||
| } | ||
| return QueryHelper.processCustomType(props[idx], val, platform, undefined, true); | ||
| }); | ||
| return value.every(val => Array.isArray(val)) ? value.map(val => convert(val)) : convert(value); | ||
| } | ||
| static isSupportedOperator(key) { | ||
@@ -327,0 +352,0 @@ return !!QueryHelper.SUPPORTED_OPERATORS.find(op => key === op); |
@@ -54,2 +54,8 @@ import type { EntityManager } from '../EntityManager.js'; | ||
| /** | ||
| * Returns the property names a given property is tracked and snapshotted under, paired with their values. | ||
| * Inlined embeddables are hydrated as a single object, so only their leaves tell whether it is complete. | ||
| */ | ||
| private getTrackedValues; | ||
| private restore; | ||
| /** | ||
| * Registers a deletion handler to unset entity identities after flush. | ||
@@ -56,0 +62,0 @@ */ |
@@ -172,5 +172,15 @@ import { ReferenceKind, TransactionPropagation } from '../enums.js'; | ||
| } | ||
| parentWrapped.__data = wrapped.__data; | ||
| parentWrapped.__originalEntityData = wrapped.__originalEntityData; | ||
| const parentData = parentWrapped.__data; | ||
| const parentSnapshot = parentWrapped.__originalEntityData; | ||
| parentWrapped.__data = { ...wrapped.__data }; | ||
| const originalEntityData = { ...wrapped.__originalEntityData }; | ||
| for (const prop of meta.hydrateProps) { | ||
| const tracked = this.getTrackedValues(prop, entity[prop.name]); | ||
| // the fork entity can be partially loaded, and propagating a property it does not know about | ||
| // would clobber the parent state, so we restore both its value and its snapshot entries | ||
| if (!tracked.every(([key, value]) => value !== undefined || wrapped.__loadedProperties.has(key))) { | ||
| this.restore(parentWrapped.__data, parentData, prop.name); | ||
| tracked.forEach(([key]) => this.restore(originalEntityData, parentSnapshot, key)); | ||
| continue; | ||
| } | ||
| if (prop.kind === ReferenceKind.SCALAR) { | ||
@@ -180,2 +190,5 @@ parentEntity[prop.name] = entity[prop.name]; | ||
| } | ||
| if (wrapped.__originalEntityData) { | ||
| parentWrapped.__originalEntityData = originalEntityData; | ||
| } | ||
| } | ||
@@ -188,2 +201,22 @@ else { | ||
| /** | ||
| * Returns the property names a given property is tracked and snapshotted under, paired with their values. | ||
| * Inlined embeddables are hydrated as a single object, so only their leaves tell whether it is complete. | ||
| */ | ||
| getTrackedValues(prop, value) { | ||
| if (prop.kind === ReferenceKind.EMBEDDED && !prop.object) { | ||
| return Object.values(prop.embeddedProps).flatMap(child => { | ||
| return this.getTrackedValues(child, value?.[child.embedded[1]]); | ||
| }); | ||
| } | ||
| return [[prop.name, value]]; | ||
| } | ||
| restore(target, source, key) { | ||
| if (source && key in source) { | ||
| target[key] = source[key]; | ||
| } | ||
| else { | ||
| delete target[key]; | ||
| } | ||
| } | ||
| /** | ||
| * Registers a deletion handler to unset entity identities after flush. | ||
@@ -190,0 +223,0 @@ */ |
+1
-1
@@ -156,3 +156,3 @@ import { clone } from './clone.js'; | ||
| static PK_SEPARATOR = '~~~'; | ||
| static #ORM_VERSION = '7.1.8-dev.13'; | ||
| static #ORM_VERSION = '7.1.8-dev.14'; | ||
| /** | ||
@@ -159,0 +159,0 @@ * Checks if the argument is instance of `Object`. Returns false for arrays. |
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
1574374
0.22%33659
0.21%