333
schangxiang@126.com
2025-09-19 18966e02fb573c7e2bb0c6426ed792b38b910940
1
{"version":3,"sources":["../browser/src/persistence/Subject.ts"],"names":[],"mappings":"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","file":"Subject.js","sourcesContent":["import {ObjectLiteral} from \"../common/ObjectLiteral\";\nimport {EntityMetadata} from \"../metadata/EntityMetadata\";\nimport {SubjectChangeMap} from \"./SubjectChangeMap\";\nimport {OrmUtils} from \"../util/OrmUtils\";\nimport {RelationMetadata} from \"../metadata/RelationMetadata\";\nimport {ColumnMetadata} from \"../metadata/ColumnMetadata\";\n\n/**\n * Subject is a subject of persistence.\n * It holds information about each entity that needs to be persisted:\n * - what entity should be persisted\n * - what is database representation of the persisted entity\n * - what entity metadata of the persisted entity\n * - what is allowed to with persisted entity (insert/update/remove)\n *\n * Having this collection of subjects we can perform database queries.\n */\nexport class Subject {\n\n    // -------------------------------------------------------------------------\n    // Properties\n    // -------------------------------------------------------------------------\n\n    /**\n     * Entity metadata of the subject entity.\n     */\n    metadata: EntityMetadata;\n\n    /**\n     * Subject identifier.\n     * This identifier is not limited to table entity primary columns.\n     * This can be entity id or ids as well as some unique entity properties, like name or title.\n     * Insert / Update / Remove operation will be executed by a given identifier.\n     */\n    identifier: ObjectLiteral|undefined = undefined;\n\n    /**\n     * Copy of entity but with relational ids fulfilled.\n     */\n    entityWithFulfilledIds: ObjectLiteral|undefined = undefined;\n\n    /**\n     * If subject was created by cascades this property will contain subject\n     * from where this subject was created.\n     */\n    parentSubject?: Subject;\n\n    /**\n     * Gets entity sent to the persistence (e.g. changed entity).\n     * If entity is not set then this subject is created only for the entity loaded from the database,\n     * or this subject is used for the junction operation (junction operations are relying only on identifier).\n     */\n    entity?: ObjectLiteral;\n\n    /**\n     * Database entity.\n     * THIS IS NOT RAW ENTITY DATA, its a real entity.\n     */\n    databaseEntity?: ObjectLiteral;\n\n    /**\n     * Indicates if database entity was loaded.\n     * No matter if it was found or not, it indicates the fact of loading.\n     */\n    databaseEntityLoaded: boolean = false;\n\n    /**\n     * Changes needs to be applied in the database for the given subject.\n     */\n    changeMaps: SubjectChangeMap[] = [];\n\n    /**\n     * Generated values returned by a database (for example generated id or default values).\n     * Used in insert and update operations.\n     * Has entity-like structure (not just column database name and values).\n     */\n    generatedMap?: ObjectLiteral;\n\n    /**\n     * Inserted values with updated values of special and default columns.\n     * Has entity-like structure (not just column database name and values).\n     */\n    insertedValueSet?: ObjectLiteral;\n\n    /**\n     * Indicates if this subject can be inserted into the database.\n     * This means that this subject either is newly persisted, either can be inserted by cascades.\n     */\n    canBeInserted: boolean = false;\n\n    /**\n     * Indicates if this subject can be updated in the database.\n     * This means that this subject either was persisted, either can be updated by cascades.\n     */\n    canBeUpdated: boolean = false;\n\n    /**\n     * Indicates if this subject MUST be removed from the database.\n     * This means that this subject either was removed, either was removed by cascades.\n     */\n    mustBeRemoved: boolean = false;\n\n    /**\n     * Relations updated by the change maps.\n     */\n    updatedRelationMaps: { relation: RelationMetadata, value: ObjectLiteral }[] = [];\n\n    /**\n     * List of updated columns\n     */\n    diffColumns: ColumnMetadata[] = [];\n\n    /**\n     * List of updated relations\n     */\n    diffRelations: RelationMetadata[] = [];\n\n    // -------------------------------------------------------------------------\n    // Constructor\n    // -------------------------------------------------------------------------\n\n    constructor(options: {\n        metadata: EntityMetadata,\n        parentSubject?: Subject,\n        entity?: ObjectLiteral,\n        canBeInserted?: boolean,\n        canBeUpdated?: boolean,\n        mustBeRemoved?: boolean,\n        identifier?: ObjectLiteral,\n        changeMaps?: SubjectChangeMap[]\n    }) {\n        this.metadata = options.metadata;\n        this.entity = options.entity;\n        this.parentSubject = options.parentSubject;\n        if (options.canBeInserted !== undefined)\n            this.canBeInserted = options.canBeInserted;\n        if (options.canBeUpdated !== undefined)\n            this.canBeUpdated = options.canBeUpdated;\n        if (options.mustBeRemoved !== undefined)\n            this.mustBeRemoved = options.mustBeRemoved;\n        if (options.identifier !== undefined)\n            this.identifier = options.identifier;\n        if (options.changeMaps !== undefined)\n            this.changeMaps.push(...options.changeMaps);\n\n        this.recompute();\n    }\n\n    // -------------------------------------------------------------------------\n    // Accessors\n    // -------------------------------------------------------------------------\n\n    /**\n     * Checks if this subject must be inserted into the database.\n     * Subject can be inserted into the database if it is allowed to be inserted (explicitly persisted or by cascades)\n     * and if it does not have database entity set.\n     */\n    get mustBeInserted() {\n        return this.canBeInserted && !this.databaseEntity;\n    }\n\n    /**\n     * Checks if this subject must be updated into the database.\n     * Subject can be updated in the database if it is allowed to be updated (explicitly persisted or by cascades)\n     * and if it does have differentiated columns or relations.\n     */\n    get mustBeUpdated() {\n        return this.canBeUpdated &&\n            this.identifier &&\n            (this.databaseEntityLoaded === false || (this.databaseEntityLoaded && this.databaseEntity)) &&\n            // ((this.entity && this.databaseEntity) || (!this.entity && !this.databaseEntity)) &&\n            this.changeMaps.length > 0;\n    }\n\n    // -------------------------------------------------------------------------\n    // Public Methods\n    // -------------------------------------------------------------------------\n\n    /**\n     * Creates a value set needs to be inserted / updated in the database.\n     * Value set is based on the entity and change maps of the subject.\n     * Important note: this method pops data from this subject's change maps.\n     */\n    createValueSetAndPopChangeMap(): ObjectLiteral {\n        const changeMapsWithoutValues: SubjectChangeMap[] = [];\n        const changeSet = this.changeMaps.reduce((updateMap, changeMap) => {\n            let value = changeMap.value;\n            if (value instanceof Subject) {\n\n                // referenced columns can refer on values both which were just inserted and which were present in the model\n                // if entity was just inserted valueSets must contain all values from the entity and values just inserted in the database\n                // so, here we check if we have a value set then we simply use it as value to get our reference column values\n                // otherwise simply use an entity which cannot be just inserted at the moment and have all necessary data\n                value = value.insertedValueSet ? value.insertedValueSet : value.entity;\n            }\n            // value = changeMap.valueFactory ? changeMap.valueFactory(value) : changeMap.column.createValueMap(value);\n\n            let valueMap: ObjectLiteral|undefined;\n            if (this.metadata.isJunction && changeMap.column) {\n                valueMap = changeMap.column.createValueMap(changeMap.column.referencedColumn!.getEntityValue(value));\n\n            } else if (changeMap.column) {\n                valueMap = changeMap.column.createValueMap(value);\n\n            } else if (changeMap.relation) {\n\n                // value can be a related object, for example: post.question = { id: 1 }\n                // or value can be a null or direct relation id, e.g. post.question = 1\n                // if its a direction relation id then we just set it to the valueMap,\n                // however if its an object then we need to extract its relation id map and set it to the valueMap\n                if (value instanceof Object) {\n\n                    // get relation id, e.g. referenced column name and its value,\n                    // for example: { id: 1 } which then will be set to relation, e.g. post.category = { id: 1 }\n                    const relationId = changeMap.relation!.getRelationIdMap(value);\n\n                    // but relation id can be empty, for example in the case when you insert a new post with category\n                    // and both post and category are newly inserted objects (by cascades) and in this case category will not have id\n                    // this means we need to insert post without question id and update post's questionId once question be inserted\n                    // that's why we create a new changeMap operation for future updation of the post entity\n                    if (relationId === undefined) {\n                        changeMapsWithoutValues.push(changeMap);\n                        this.canBeUpdated = true;\n                        return updateMap;\n                    }\n                    valueMap = changeMap.relation!.createValueMap(relationId);\n                    this.updatedRelationMaps.push({ relation: changeMap.relation, value: relationId });\n\n                } else { // value can be \"null\" or direct relation id here\n                    valueMap = changeMap.relation!.createValueMap(value);\n                    this.updatedRelationMaps.push({ relation: changeMap.relation, value: value });\n                }\n            }\n\n            OrmUtils.mergeDeep(updateMap, valueMap);\n            return updateMap;\n        }, {} as ObjectLiteral);\n        this.changeMaps = changeMapsWithoutValues;\n        return changeSet;\n    }\n\n    /**\n     * Recomputes entityWithFulfilledIds and identifier when entity changes.\n     */\n    recompute(): void {\n\n        if (this.entity) {\n            this.entityWithFulfilledIds = Object.assign({}, this.entity);\n            if (this.parentSubject) {\n                this.metadata.primaryColumns.forEach(primaryColumn => {\n                    if (primaryColumn.relationMetadata && primaryColumn.relationMetadata.inverseEntityMetadata === this.parentSubject!.metadata) {\n                        primaryColumn.setEntityValue(this.entityWithFulfilledIds!, this.parentSubject!.entity);\n                    }\n                });\n            }\n            this.identifier = this.metadata.getEntityIdMap(this.entityWithFulfilledIds);\n\n        } else if (this.databaseEntity) {\n            this.identifier = this.metadata.getEntityIdMap(this.databaseEntity);\n        }\n    }\n\n}\n"],"sourceRoot":".."}