{"version":3,"file":"outbox.mjs","sources":["../../../src/sync/outbox.ts"],"sourcesContent":["// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nimport { ModelPredicateCreator } from '../predicates';\nimport { QueryOne, } from '../types';\nimport { SYNC, USER, directedValueEquality } from '../util';\nimport { TransformerMutationType, getIdentifierValue } from './utils';\n// TODO: Persist deleted ids\n// https://github.com/aws-amplify/amplify-js/blob/datastore-docs/packages/datastore/docs/sync-engine.md#outbox\nclass MutationEventOutbox {\n    constructor(schema, _MutationEvent, modelInstanceCreator, ownSymbol) {\n        this.schema = schema;\n        this._MutationEvent = _MutationEvent;\n        this.modelInstanceCreator = modelInstanceCreator;\n        this.ownSymbol = ownSymbol;\n    }\n    async enqueue(storage, mutationEvent) {\n        await storage.runExclusive(async (s) => {\n            const mutationEventModelDefinition = this.schema.namespaces[SYNC].models.MutationEvent;\n            // `id` is the key for the record in the mutationEvent;\n            // `modelId` is the key for the actual record that was mutated\n            const predicate = ModelPredicateCreator.createFromAST(mutationEventModelDefinition, {\n                and: [\n                    { modelId: { eq: mutationEvent.modelId } },\n                    { id: { ne: this.inProgressMutationEventId } },\n                ],\n            });\n            // Check if there are any other records with same id\n            const [first] = await s.query(this._MutationEvent, predicate);\n            // No other record with same modelId, so enqueue\n            if (first === undefined) {\n                await s.save(mutationEvent, undefined, this.ownSymbol);\n                return;\n            }\n            // There was an enqueued mutation for the modelId, so continue\n            const { operation: incomingMutationType } = mutationEvent;\n            if (first.operation === TransformerMutationType.CREATE) {\n                if (incomingMutationType === TransformerMutationType.DELETE) {\n                    await s.delete(this._MutationEvent, predicate);\n                }\n                else {\n                    // first gets updated with the incoming mutation's data, condition intentionally skipped\n                    // we need to merge the fields for a create and update mutation to prevent\n                    // data loss, since update mutations only include changed fields\n                    const merged = this.mergeUserFields(first, mutationEvent);\n                    await s.save(this._MutationEvent.copyOf(first, draft => {\n                        draft.data = merged.data;\n                    }), undefined, this.ownSymbol);\n                }\n            }\n            else {\n                const { condition: incomingConditionJSON } = mutationEvent;\n                const incomingCondition = JSON.parse(incomingConditionJSON);\n                let merged;\n                // If no condition\n                if (Object.keys(incomingCondition).length === 0) {\n                    merged = this.mergeUserFields(first, mutationEvent);\n                    // delete all for model\n                    await s.delete(this._MutationEvent, predicate);\n                }\n                merged = merged || mutationEvent;\n                // Enqueue new one\n                await s.save(merged, undefined, this.ownSymbol);\n            }\n        });\n    }\n    async dequeue(storage, record, recordOp) {\n        const head = await this.peek(storage);\n        if (record) {\n            await this.syncOutboxVersionsOnDequeue(storage, record, head, recordOp);\n        }\n        if (head) {\n            await storage.delete(head);\n        }\n        this.inProgressMutationEventId = undefined;\n        return head;\n    }\n    /**\n     * Doing a peek() implies that the mutation goes \"inProgress\"\n     *\n     * @param storage\n     */\n    async peek(storage) {\n        const head = await storage.queryOne(this._MutationEvent, QueryOne.FIRST);\n        this.inProgressMutationEventId = head ? head.id : undefined;\n        return head;\n    }\n    async getForModel(storage, model, userModelDefinition) {\n        const mutationEventModelDefinition = this.schema.namespaces[SYNC].models.MutationEvent;\n        const modelId = getIdentifierValue(userModelDefinition, model);\n        const mutationEvents = await storage.query(this._MutationEvent, ModelPredicateCreator.createFromAST(mutationEventModelDefinition, {\n            and: { modelId: { eq: modelId } },\n        }));\n        return mutationEvents;\n    }\n    async getModelIds(storage) {\n        const mutationEvents = await storage.query(this._MutationEvent);\n        const result = new Set();\n        mutationEvents.forEach(({ modelId }) => result.add(modelId));\n        return result;\n    }\n    // applies _version from the AppSync mutation response to other items\n    // in the mutation queue with the same id\n    // see https://github.com/aws-amplify/amplify-js/pull/7354 for more details\n    async syncOutboxVersionsOnDequeue(storage, record, head, recordOp) {\n        if (head?.operation !== recordOp) {\n            return;\n        }\n        const { _version, _lastChangedAt, _deleted, ..._incomingData } = record;\n        const incomingData = this.removeTimestampFields(head.model, _incomingData);\n        const data = JSON.parse(head.data);\n        if (!data) {\n            return;\n        }\n        const { _version: __version, _lastChangedAt: __lastChangedAt, _deleted: __deleted, ..._outgoingData } = data;\n        const outgoingData = this.removeTimestampFields(head.model, _outgoingData);\n        // Don't sync the version when the data in the response does not match the data\n        // in the request, i.e., when there's a handled conflict\n        //\n        // NOTE: `incomingData` contains all the fields in the record received from AppSync\n        // and `outgoingData` only contains updated fields sent to AppSync\n        // If all send data isn't matched in the returned data then the update was rejected\n        // by AppSync and we should not update the version on other outbox entries for this\n        // object\n        if (!directedValueEquality(outgoingData, incomingData, true)) {\n            return;\n        }\n        const mutationEventModelDefinition = this.schema.namespaces[SYNC].models.MutationEvent;\n        const userModelDefinition = this.schema.namespaces.user.models[head.model];\n        const recordId = getIdentifierValue(userModelDefinition, record);\n        const predicate = ModelPredicateCreator.createFromAST(mutationEventModelDefinition, {\n            and: [\n                { modelId: { eq: recordId } },\n                { id: { ne: this.inProgressMutationEventId } },\n            ],\n        });\n        const outdatedMutations = await storage.query(this._MutationEvent, predicate);\n        if (!outdatedMutations.length) {\n            return;\n        }\n        const reconciledMutations = outdatedMutations.map(m => {\n            const oldData = JSON.parse(m.data);\n            const newData = { ...oldData, _version, _lastChangedAt };\n            return this._MutationEvent.copyOf(m, draft => {\n                draft.data = JSON.stringify(newData);\n            });\n        });\n        await storage.delete(this._MutationEvent, predicate);\n        await Promise.all(reconciledMutations.map(async (m) => storage.save(m, undefined, this.ownSymbol)));\n    }\n    mergeUserFields(previous, current) {\n        const { _version, _lastChangedAt, _deleted, ...previousData } = JSON.parse(previous.data);\n        const { _version: __version, _lastChangedAt: __lastChangedAt, _deleted: __deleted, ...currentData } = JSON.parse(current.data);\n        const data = JSON.stringify({\n            _version,\n            _lastChangedAt,\n            _deleted,\n            ...previousData,\n            ...currentData,\n        });\n        return this.modelInstanceCreator(this._MutationEvent, {\n            ...current,\n            data,\n        });\n    }\n    /*\n    if a model is using custom timestamp fields\n    the custom field names will be stored in the model attributes\n\n    e.g.\n    \"attributes\": [\n    {\n            \"type\": \"model\",\n            \"properties\": {\n                \"timestamps\": {\n                    \"createdAt\": \"createdOn\",\n                    \"updatedAt\": \"updatedOn\"\n                }\n            }\n    }\n    ]\n    */\n    removeTimestampFields(model, record) {\n        const CREATED_AT_DEFAULT_KEY = 'createdAt';\n        const UPDATED_AT_DEFAULT_KEY = 'updatedAt';\n        let createdTimestampKey = CREATED_AT_DEFAULT_KEY;\n        let updatedTimestampKey = UPDATED_AT_DEFAULT_KEY;\n        const modelAttributes = this.schema.namespaces[USER].models[model].attributes?.find(attr => attr.type === 'model');\n        const timestampFieldsMap = modelAttributes?.properties?.timestamps;\n        if (timestampFieldsMap) {\n            createdTimestampKey = timestampFieldsMap[CREATED_AT_DEFAULT_KEY];\n            updatedTimestampKey = timestampFieldsMap[UPDATED_AT_DEFAULT_KEY];\n        }\n        delete record[createdTimestampKey];\n        delete record[updatedTimestampKey];\n        return record;\n    }\n}\nexport { MutationEventOutbox };\n"],"names":[],"mappings":"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"}