{"version":3,"file":"relationship.mjs","sources":["../../../src/storage/relationship.ts"],"sourcesContent":["// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nimport { isFieldAssociation } from '../types';\n/**\n * Defines a relationship from a LOCAL model.field to a REMOTE model.field and helps\n * navigate the relationship, providing a simplified peek at the relationship details\n * pertinent to setting FK's and constructing join conditions.\n *\n * Because I mean, relationships are tough.\n *\n */\nexport class ModelRelationship {\n    /**\n     * @param modelDefinition The \"local\" model.\n     * @param field The \"local\" model field.\n     */\n    constructor(model, field) {\n        if (!isFieldAssociation(model.schema, field)) {\n            throw new Error(`${model.schema.name}.${field} is not a relationship.`);\n        }\n        this.localModel = model;\n        this._field = field;\n    }\n    /**\n     * Returns a ModelRelationship for the the given model and field if the pair\n     * indicates a relationship to another model. Else, returns `null`.\n     *\n     * @param model The model the relationship field exists in.\n     * @param field The field that may relates the local model to the remote model.\n     */\n    static from(model, field) {\n        if (isFieldAssociation(model.schema, field)) {\n            return new this(model, field);\n        }\n        else {\n            return null;\n        }\n    }\n    /**\n     * Enumerates all valid `ModelRelationship`'s on the given model.\n     *\n     * @param model The model definition to enumerate relationships of.\n     */\n    static allFrom(model) {\n        const relationships = [];\n        for (const field of Object.keys(model.schema.fields)) {\n            const relationship = ModelRelationship.from(model, field);\n            relationship && relationships.push(relationship);\n        }\n        return relationships;\n    }\n    get localDefinition() {\n        return this.localModel.schema;\n    }\n    /**\n     * The virtual/computed field on the local model that should contain\n     * the related model.\n     */\n    get field() {\n        return this._field;\n    }\n    /**\n     * The constructor that can be used to query DataStore or create instance for\n     * the local model.\n     */\n    get localConstructor() {\n        return this.localModel.builder;\n    }\n    /**\n     * The name/type of the relationship the local model has with the remote model\n     * via the defined local model field.\n     */\n    get type() {\n        return this.localAssocation.connectionType;\n    }\n    /**\n     * Raw details about the local FK as-is from the local model's field definition in\n     * the schema. This field requires interpretation.\n     *\n     * @see localJoinFields\n     * @see localAssociatedWith\n     */\n    get localAssocation() {\n        return this.localDefinition.fields[this.field].association;\n    }\n    /**\n     * The field names on the local model that can be used to query or queried to match\n     * with instances of the remote model.\n     *\n     * Fields are returned in-order to match the order of `this.remoteKeyFields`.\n     */\n    get localJoinFields() {\n        /**\n         * This is relatively straightforward, actually.\n         *\n         * If we have explicitly stated targetNames, codegen is telling us authoritatively\n         * to use those fields for this relationship. The local model \"points to\" fields\n         * in the remote one.\n         *\n         * In other cases, the remote model points to this one's\n         */\n        if (this.localAssocation.targetName) {\n            // This case is theoretically unnecessary going forward.\n            return [this.localAssocation.targetName];\n        }\n        else if (this.localAssocation.targetNames) {\n            return this.localAssocation.targetNames;\n        }\n        else {\n            return this.localPKFields;\n        }\n    }\n    /**\n     * The field names on the local model that uniquely identify it.\n     *\n     * These fields may or may not be relevant to the join fields.\n     */\n    get localPKFields() {\n        return this.localModel.pkField;\n    }\n    get remoteDefinition() {\n        return this.remoteModelType.modelConstructor?.schema;\n    }\n    get remoteModelType() {\n        return this.localDefinition.fields[this.field].type;\n    }\n    /**\n     * Constructor that can be used to query DataStore or create instances for\n     * the remote model.\n     */\n    get remoteModelConstructor() {\n        return this.remoteModelType.modelConstructor.builder;\n    }\n    /**\n     * The field names on the remote model that uniquely identify it.\n     *\n     * These fields may or may not be relevant to the join fields.\n     */\n    get remotePKFields() {\n        return this.remoteModelType.modelConstructor?.pkField || ['id'];\n    }\n    /**\n     * The `associatedWith` fields from the local perspective.\n     *\n     * When present, these fields indicate which fields on the remote model to use\n     * when looking for a remote association and/or determining the final remote\n     * key fields.\n     */\n    get localAssociatedWith() {\n        if (this.localAssocation.connectionType === 'HAS_MANY' ||\n            this.localAssocation.connectionType === 'HAS_ONE') {\n            // This de-arraying is theoretically unnecessary going forward.\n            return Array.isArray(this.localAssocation.associatedWith)\n                ? this.localAssocation.associatedWith\n                : [this.localAssocation.associatedWith];\n        }\n        else {\n            return undefined;\n        }\n    }\n    /**\n     * The `remote` model's associated field's `assocation` metadata, if\n     * present.\n     *\n     * This is used when determining if the remote model's associated field\n     * specifies which FK fields to use. If this value is `undefined`, the\n     * name of the remote field (`this.localAssociatedWith`) *is* the remote\n     * key field.\n     */\n    get explicitRemoteAssociation() {\n        if (this.localAssociatedWith) {\n            if (this.localAssociatedWith.length === 1) {\n                return this.remoteDefinition.fields[this.localAssociatedWith[0]]\n                    ?.association;\n            }\n            else {\n                return undefined;\n            }\n        }\n    }\n    /**\n     * The field names on the remote model that can used to query or queried to match\n     * with instances of the local model.\n     *\n     * Fields are returned in-order to match the order of `this.localKeyFields`.\n     */\n    get remoteJoinFields() {\n        /**\n         * If the local relationship explicitly names \"associated with\" fields, we\n         * need to see if this points direction to a reciprocating assocation. If it\n         * does, the remote assocation indicates what fields to use.\n         */\n        if (this.explicitRemoteAssociation?.targetName) {\n            // This case is theoretically unnecessary going forward.\n            return [this.explicitRemoteAssociation.targetName];\n        }\n        else if (this.explicitRemoteAssociation?.targetNames) {\n            // eslint-disable-next-line @typescript-eslint/no-non-null-asserted-optional-chain\n            return this.explicitRemoteAssociation?.targetNames;\n        }\n        else if (this.localAssociatedWith) {\n            return this.localAssociatedWith;\n        }\n        else {\n            return this.remotePKFields;\n        }\n    }\n    /**\n     * Whether this relationship everything necessary to get, set, and query from\n     * the perspective of the local model provided at instantiation.\n     */\n    get isComplete() {\n        return this.localJoinFields.length > 0 && this.remoteJoinFields.length > 0;\n    }\n    /**\n     * Creates an FK mapper object with respect to the given related instance.\n     *\n     * E.g., if the local FK fields are `[parentId, parentName]` and point to\n     * `[customId, name]` on the remote model, `createLocalFKObject(remote)`\n     * will return:\n     *\n     * ```\n     * {\n     * \tparentId: remote.customId,\n     * \tparentName: remote.name\n     * }\n     * ```\n     *\n     * @param remote The remote related instance.\n     */\n    createLocalFKObject(remote) {\n        const fk = {};\n        for (let i = 0; i < this.localJoinFields.length; i++) {\n            fk[this.localJoinFields[i]] = remote[this.remoteJoinFields[i]];\n        }\n        return fk;\n    }\n    /**\n     * Creates an query mapper object to help fetch the remote instance(s) or\n     * `null` if any of the necessary local fields are `null` or `undefined`.\n     *\n     * E.g., if the local FK fields are `[parentId, parentName]` and point to\n     * `[customId, name]` on the remote model, `createLocalFKObject(remote)`\n     * will return:\n     *\n     * ```\n     * {\n     * \tcustomId: local.parentId\n     * \tname: local.parentName\n     * }\n     * ```\n     *\n     * If the local fields are not populated, returns\n     *\n     * @param local The local instance.\n     */\n    createRemoteQueryObject(local) {\n        const query = {};\n        for (let i = 0; i < this.remoteJoinFields.length; i++) {\n            const localValue = local[this.localJoinFields[i]];\n            if (localValue === null || localValue === undefined)\n                return null;\n            query[this.remoteJoinFields[i]] = local[this.localJoinFields[i]];\n        }\n        return query;\n    }\n}\n"],"names":[],"mappings":"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"}