UNPKG

@medusajs/utils

Version:

Medusa utilities functions shared by Medusa core and Modules

243 lines • 9.94 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.mikroOrmSerializer = exports.EntitySerializer = void 0; const core_1 = require("@mikro-orm/core"); function isVisible(meta, propName, options = {}) { if (options.populate === true) { return true; } if (Array.isArray(options.populate) && options.exclude?.find((item) => item === propName)) { return false; } if (Array.isArray(options.populate) && (options.populate?.find((item) => item === propName || item.startsWith(propName + ".")) || options.populate.includes("*"))) { return true; } const prop = meta.properties[propName]; const visible = (prop && !prop.hidden) || prop === undefined; // allow unknown properties const prefixed = prop && !prop.primary && propName.startsWith("_"); // ignore prefixed properties, if it's not a PK return visible && !prefixed; } function isPopulated(entity, propName, options) { if (Array.isArray(options.populate) && (options.populate?.find((item) => item === propName || item.startsWith(propName + ".")) || options.populate.includes("*"))) { return true; } if (typeof options.populate === "boolean") { return options.populate; } return false; } /** * Custom property filtering for the serialization which takes into account circular references to not return them. * @param propName * @param meta * @param options * @param parents */ function filterEntityPropToSerialize({ propName, meta, options, parents, }) { parents ??= []; const isVisibleRes = isVisible(meta, propName, options); const prop = meta.properties[propName]; // Only prevent circular references if prop is a relation if (prop && options.preventCircularRef && isVisibleRes && prop.kind !== core_1.ReferenceKind.SCALAR) { // mapToPk would represent a foreign key and we want to keep them if (!!prop.mapToPk) { return true; } return !parents.some((parent) => parent === prop.type); } return isVisibleRes; } class EntitySerializer { static serialize(entity, options = {}, parents = []) { const parents_ = Array.from(new Set(parents)); const wrapped = (0, core_1.helper)(entity); const meta = wrapped.__meta; let contextCreated = false; if (!wrapped.__serializationContext.root) { const root = new core_1.SerializationContext({}); core_1.SerializationContext.propagate(root, entity, (meta, prop) => meta.properties[prop]?.kind !== core_1.ReferenceKind.SCALAR); contextCreated = true; } const root = wrapped.__serializationContext .root; const ret = {}; const keys = new Set(meta.primaryKeys); Object.keys(entity).forEach((prop) => keys.add(prop)); const visited = root.visited.has(entity); if (!visited) { root.visited.add(entity); } ; [...keys] /** Medusa Custom properties filtering **/ .filter((prop) => filterEntityPropToSerialize({ propName: prop, meta, options, parents: parents_, })) .map((prop) => { const cycle = root.visit(meta.className, prop); if (cycle && visited) { return [prop, undefined]; } const val = this.processProperty(prop, entity, options, parents_); if (!cycle) { root.leave(meta.className, prop); } if (options.skipNull && core_1.Utils.isPlainObject(val)) { core_1.Utils.dropUndefinedProperties(val, null); } return [prop, val]; }) .filter(([, value]) => typeof value !== "undefined" && !(value === null && options.skipNull)) .forEach(([prop, value]) => (ret[this.propertyName(meta, prop, wrapped.__platform)] = value)); if (contextCreated) { root.close(); } if (!wrapped.isInitialized()) { return ret; } // decorated getters meta.props .filter((prop) => prop.getter && prop.getterName === undefined && typeof entity[prop.name] !== "undefined" && isVisible(meta, prop.name, options)) .forEach((prop) => (ret[this.propertyName(meta, prop.name, wrapped.__platform)] = this.processProperty(prop.name, entity, options, parents_))); // decorated get methods meta.props .filter((prop) => prop.getterName && entity[prop.getterName] instanceof Function && isVisible(meta, prop.name, options)) .forEach((prop) => (ret[this.propertyName(meta, prop.name, wrapped.__platform)] = this.processProperty(prop.getterName, entity, options, parents_))); return ret; } static propertyName(meta, prop, platform) { /* istanbul ignore next */ if (meta.properties[prop]?.serializedName) { return meta.properties[prop].serializedName; } if (meta.properties[prop]?.primary && platform) { return platform.getSerializedPrimaryKeyField(prop); } return prop; } static processProperty(prop, entity, options, parents = []) { const parents_ = [...parents, entity.constructor.name]; const parts = prop.split("."); prop = parts[0]; const wrapped = (0, core_1.helper)(entity); const property = wrapped.__meta.properties[prop]; const serializer = property?.serializer; // getter method if (entity[prop] instanceof Function) { const returnValue = entity[prop](); if (!options.ignoreSerializers && serializer) { return serializer(returnValue); } return returnValue; } /* istanbul ignore next */ if (!options.ignoreSerializers && serializer) { return serializer(entity[prop]); } if (core_1.Utils.isCollection(entity[prop])) { return this.processCollection(prop, entity, options, parents_); } if (core_1.Utils.isEntity(entity[prop], true)) { return this.processEntity(prop, entity, wrapped.__platform, options, parents_); } /* istanbul ignore next */ if (property?.reference === core_1.ReferenceKind.EMBEDDED) { if (Array.isArray(entity[prop])) { return entity[prop].map((item) => (0, core_1.helper)(item).toJSON()); } if (core_1.Utils.isObject(entity[prop])) { return (0, core_1.helper)(entity[prop]).toJSON(); } } const customType = property?.customType; if (customType) { return customType.toJSON(entity[prop], wrapped.__platform); } return wrapped.__platform.normalizePrimaryKey(entity[prop]); } static extractChildOptions(options, prop) { const extractChildElements = (items) => { return items .filter((field) => field.startsWith(`${prop}.`)) .map((field) => field.substring(prop.length + 1)); }; return { ...options, populate: Array.isArray(options.populate) && !options.populate.includes("*") ? extractChildElements(options.populate) : options.populate, exclude: Array.isArray(options.exclude) && !options.exclude.includes("*") ? extractChildElements(options.exclude) : options.exclude, }; } static processEntity(prop, entity, platform, options, parents = []) { const parents_ = [...parents, entity.constructor.name]; const child = core_1.Reference.unwrapReference(entity[prop]); const wrapped = (0, core_1.helper)(child); const populated = isPopulated(child, prop, options) && wrapped.isInitialized(); const expand = populated || options.forceObject || !wrapped.__managed; if (expand) { return this.serialize(child, this.extractChildOptions(options, prop), parents_); } return platform.normalizePrimaryKey(wrapped.getPrimaryKey()); } static processCollection(prop, entity, options, parents = []) { const parents_ = [...parents, entity.constructor.name]; const col = entity[prop]; if (!col.isInitialized()) { return undefined; } return col.getItems(false).map((item) => { if (isPopulated(item, prop, options)) { return this.serialize(item, this.extractChildOptions(options, prop), parents_); } return (0, core_1.helper)(item).getPrimaryKey(); }); } } exports.EntitySerializer = EntitySerializer; const mikroOrmSerializer = (data, options) => { return new Promise((resolve) => { options ??= {}; const data_ = (Array.isArray(data) ? data : [data]).filter(Boolean); const forSerialization = []; const notForSerialization = []; data_.forEach((object) => { if (object.__meta) { return forSerialization.push(object); } return notForSerialization.push(object); }); let result = forSerialization.map((entity) => EntitySerializer.serialize(entity, { forceObject: true, populate: ["*"], preventCircularRef: true, ...options, })); if (notForSerialization.length) { result = result.concat(notForSerialization); } resolve(Array.isArray(data) ? result : result[0]); }); }; exports.mikroOrmSerializer = mikroOrmSerializer; //# sourceMappingURL=mikro-orm-serializer.js.map