"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.WriteTransaction = void 0;
const threads_pb_1 = require("@textile/threads-client-grpc/threads_pb");
const Transaction_1 = require("./Transaction");
/**
 * WriteTransaction performs a mutating bulk transaction on the underlying store.
 */
class WriteTransaction extends Transaction_1.Transaction {
    constructor(context, client, threadID, modelName) {
        super(client, threadID, modelName);
        this.context = context;
        this.client = client;
        this.threadID = threadID;
        this.modelName = modelName;
    }
    /**
     * start begins the transaction. All operations between start and end will be applied as a single transaction upon a call to end.
     */
    start() {
        return __awaiter(this, void 0, void 0, function* () {
            const startReq = new threads_pb_1.StartTransactionRequest();
            startReq.setDbid(this.threadID.toBytes());
            startReq.setCollectionname(this.modelName);
            const req = new threads_pb_1.WriteTransactionRequest();
            req.setStarttransactionrequest(startReq);
            const metadata = JSON.parse(JSON.stringify(this.context));
            this.client.start(metadata);
            this.client.send(req);
        });
    }
    /**
     * create creates a new model instance in the given store.
     * @param values An array of model instances as JSON/JS objects.
     */
    create(values) {
        const _super = Object.create(null, {
            setReject: { get: () => super.setReject }
        });
        return __awaiter(this, void 0, void 0, function* () {
            return new Promise((resolve, reject) => {
                const createReq = new threads_pb_1.CreateRequest();
                const list = [];
                values.forEach((v) => {
                    list.push(Buffer.from(JSON.stringify(v)));
                });
                createReq.setInstancesList(list);
                const req = new threads_pb_1.WriteTransactionRequest();
                req.setCreaterequest(createReq);
                this.client.onMessage((message) => {
                    const reply = message.getCreatereply();
                    if (reply === undefined) {
                        resolve();
                    }
                    else {
                        resolve(reply.toObject().instanceidsList);
                    }
                });
                _super.setReject.call(this, reject);
                this.client.send(req);
            });
        });
    }
    /**
     * save saves changes to an existing model instance in the given store.
     * @param values An array of model instances as JSON/JS objects. Each model instance must have a valid existing `ID` property.
     */
    save(values) {
        const _super = Object.create(null, {
            setReject: { get: () => super.setReject }
        });
        return __awaiter(this, void 0, void 0, function* () {
            return new Promise((resolve, reject) => {
                const saveReq = new threads_pb_1.SaveRequest();
                const list = [];
                values.forEach((v) => {
                    if (!v.hasOwnProperty('ID')) {
                        v['ID'] = ''; // The server will add an ID if empty.
                    }
                    list.push(Buffer.from(JSON.stringify(v)));
                });
                saveReq.setInstancesList(list);
                const req = new threads_pb_1.WriteTransactionRequest();
                req.setSaverequest(saveReq);
                this.client.onMessage((_message) => {
                    resolve();
                });
                _super.setReject.call(this, reject);
                this.client.send(req);
            });
        });
    }
    /**
     * delete deletes an existing model instance from the given store.
     * @param IDs An array of instance ids to delete.
     */
    delete(IDs) {
        const _super = Object.create(null, {
            setReject: { get: () => super.setReject }
        });
        return __awaiter(this, void 0, void 0, function* () {
            return new Promise((resolve, reject) => {
                const deleteReq = new threads_pb_1.DeleteRequest();
                deleteReq.setInstanceidsList(IDs);
                const req = new threads_pb_1.WriteTransactionRequest();
                req.setDeleterequest(deleteReq);
                this.client.onMessage((_message) => {
                    resolve();
                });
                _super.setReject.call(this, reject);
                this.client.send(req);
            });
        });
    }
    /**
     * has checks whether a given instance exists in the given store.
     * @param IDs An array of instance ids to check for.
     */
    has(IDs) {
        const _super = Object.create(null, {
            setReject: { get: () => super.setReject }
        });
        return __awaiter(this, void 0, void 0, function* () {
            return new Promise((resolve, reject) => {
                const hasReq = new threads_pb_1.HasRequest();
                hasReq.setInstanceidsList(IDs);
                const req = new threads_pb_1.WriteTransactionRequest();
                req.setHasrequest(hasReq);
                this.client.onMessage((message) => {
                    const reply = message.getHasreply();
                    resolve(reply ? reply.toObject().exists == true : false);
                });
                _super.setReject.call(this, reject);
                this.client.send(req);
            });
        });
    }
    /**
     * find queries the store for entities matching the given query parameters. See Query for options.
     * @param query The object that describes the query. See Query for options. Alternatively, see QueryJSON for the basic interface.
     */
    find(query) {
        const _super = Object.create(null, {
            setReject: { get: () => super.setReject }
        });
        return __awaiter(this, void 0, void 0, function* () {
            return new Promise((resolve, reject) => {
                const findReq = new threads_pb_1.FindRequest();
                findReq.setQueryjson(Buffer.from(JSON.stringify(query)));
                const req = new threads_pb_1.WriteTransactionRequest();
                req.setFindrequest(findReq);
                this.client.onMessage((message) => {
                    const reply = message.getFindreply();
                    if (reply === undefined) {
                        resolve();
                    }
                    else {
                        const ret = {
                            instancesList: reply
                                .toObject()
                                .instancesList.map((instance) => JSON.parse(Buffer.from(instance, 'base64').toString())),
                        };
                        resolve(ret);
                    }
                });
                _super.setReject.call(this, reject);
                this.client.send(req);
            });
        });
    }
    /**
     * findByID queries the store for the id of an instance.
     * @param ID The id of the instance to search for.
     */
    findByID(ID) {
        const _super = Object.create(null, {
            setReject: { get: () => super.setReject }
        });
        return __awaiter(this, void 0, void 0, function* () {
            return new Promise((resolve, reject) => {
                const findReq = new threads_pb_1.FindByIDRequest();
                findReq.setInstanceid(ID);
                const req = new threads_pb_1.WriteTransactionRequest();
                req.setFindbyidrequest(findReq);
                this.client.onMessage((message) => {
                    const reply = message.getFindbyidreply();
                    if (reply === undefined) {
                        resolve();
                    }
                    else {
                        const ret = {
                            instance: JSON.parse(Buffer.from(reply.toObject().instance, 'base64').toString()),
                        };
                        resolve(ret);
                    }
                });
                _super.setReject.call(this, reject);
                this.client.send(req);
            });
        });
    }
}
exports.WriteTransaction = WriteTransaction;
//# sourceMappingURL=WriteTransaction.js.map