Creates a new entity instance or returns an existing one from the identity map, hydrating it with the provided data.
(
entityName: EntityName<T>,
data: EntityData<T>,
options: FactoryOptions = {},
)
| 83 | |
| 84 | /** Creates a new entity instance or returns an existing one from the identity map, hydrating it with the provided data. */ |
| 85 | create<T extends object, P extends string = string>( |
| 86 | entityName: EntityName<T>, |
| 87 | data: EntityData<T>, |
| 88 | options: FactoryOptions = {}, |
| 89 | ): New<T, P> { |
| 90 | data = Reference.unwrapReference(data as T); |
| 91 | options.initialized ??= true; |
| 92 | |
| 93 | if (EntityHelper.isEntity(data)) { |
| 94 | return data as New<T, P>; |
| 95 | } |
| 96 | |
| 97 | const meta = this.#metadata.get<T>(entityName); |
| 98 | |
| 99 | if (meta.virtual) { |
| 100 | data = { ...data }; |
| 101 | const entity = this.createEntity<T>(data, meta, options); |
| 102 | this.hydrate(entity, meta, data, options); |
| 103 | |
| 104 | return entity as New<T, P>; |
| 105 | } |
| 106 | |
| 107 | if (meta.serializedPrimaryKey) { |
| 108 | this.denormalizePrimaryKey(meta, data); |
| 109 | } |
| 110 | |
| 111 | const meta2 = this.processDiscriminatorColumn<T>(meta, data); |
| 112 | const exists = this.findEntity<T>(data, meta2, options); |
| 113 | let wrapped = exists && helper(exists); |
| 114 | |
| 115 | if (wrapped && !options.refresh) { |
| 116 | const wasInitialized = wrapped.isInitialized(); |
| 117 | wrapped.__processing = true; |
| 118 | Utils.dropUndefinedProperties(data); |
| 119 | this.mergeData(meta2, exists!, data, options); |
| 120 | wrapped.__processing = false; |
| 121 | wrapped.__initialized ||= !!options.initialized; |
| 122 | |
| 123 | if (wrapped.isInitialized()) { |
| 124 | if (!wasInitialized) { |
| 125 | if (meta.root.inheritanceType && !(exists instanceof meta2.class)) { |
| 126 | Object.setPrototypeOf(exists, meta2.prototype as object); |
| 127 | } |
| 128 | |
| 129 | if (options.merge && wrapped.hasPrimaryKey()) { |
| 130 | this.unitOfWork.register(exists!, data, { loaded: options.initialized }); |
| 131 | |
| 132 | // ensure all data keys are tracked as loaded for shouldRefresh checks, |
| 133 | // but don't overwrite __originalEntityData — mergeData already set it |
| 134 | // with DB values for non-user-modified keys, leaving user changes detectable |
| 135 | for (const key of Utils.keys(data)) { |
| 136 | if (meta2.properties[key]) { |
| 137 | wrapped.__loadedProperties.add(key as string); |
| 138 | } |
| 139 | } |
| 140 | } |
| 141 | |
| 142 | if (this.#eventManager.hasListeners(EventType.onInit, meta2)) { |
no test coverage detected