"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MongoDatabaseFactory = void 0;
const mongodb_1 = require("mongodb");
const database_1 = require("../adapters/database");
async function withMongoClient(fn, options) {
    const conn = await new mongodb_1.MongoClient(options.databaseURI).connect();
    try {
        return await fn(conn);
    }
    finally {
        conn.close().catch(reason => {
            console.log(reason, 'close connection FAIL *******');
        });
    }
}
class MongoDatabaseFactory extends database_1.DatabaseAdapter {
    async createOneData(table, data, options) {
        return withMongoClient(async (conn) => {
            await conn.db(options.projectId).collection(table).insertOne(data);
            return data;
        }, options);
    }
    async createManyData(table, data, options) {
        return withMongoClient(async (conn) => {
            await conn.db(options.projectId).collection(table).insertMany(data, {
                ordered: false
            });
            return data;
        }, options);
    }
    async updateOneData(table, updateModel, options) {
        return withMongoClient(async (conn) => {
            const a = await conn.db(options.projectId).collection(table).updateMany(updateModel.filter, updateModel.update, {
                upsert: !!updateModel.upsert,
            });
            return { modified: a.modifiedCount + a.upsertedCount };
        }, options);
    }
    async updateManyData(table, updateModel, options) {
        return withMongoClient(async (conn) => {
            const bulk = conn.db(options.projectId).collection(table).initializeUnorderedBulkOp();
            updateModel.forEach(u => {
                if (u.upsert === true) {
                    bulk.find(u.filter).upsert().update(u.update);
                }
                else {
                    bulk.find(u.filter).update(u.update);
                }
            });
            const a = await bulk.execute();
            if (a.isOk() === true) {
                return { modified: a.modifiedCount + a.upsertedCount };
            }
            throw { message: 'transaction write not executed', reason: a.toString() };
        }, options);
    }
    getOneData(table, id, options) {
        return withMongoClient(async (conn) => {
            return conn.db(options.projectId).collection(table).findOne({ _id: id });
        }, options);
    }
    getManyData(table, query, options) {
        return withMongoClient(async (conn) => {
            const collection = conn.db(options.projectId).collection(table);
            const cursor = collection.find(query.filter);
            if (query && !isNaN(query.size)) {
                cursor.limit(query.size);
            }
            if (query && !isNaN(query.skip)) {
                cursor.skip(query.skip);
            }
            if (query && Array.isArray(query.orderBy)) {
                query.orderBy.forEach(o => {
                    cursor.sort(Object.keys(o)[0], Object.values(o)[0]);
                });
            }
            if (query && query.count === true) {
                return cursor.count();
            }
            return cursor.toArray();
        }, options);
    }
    removeOneData(table, id, options) {
        return withMongoClient(async (conn) => {
            await conn.db(options.projectId).collection(table).deleteOne({ _id: id });
            return { _id: id };
        }, options);
    }
    removeManyData(table, query, options) {
        return withMongoClient(async (conn) => {
            await conn.db(options.projectId).collection(table).deleteMany(query);
            return 'done';
        }, options);
    }
    async init(options) {
        return 'done';
    }
    async aggregateData(table, pipelines, options) {
        return withMongoClient(conn => {
            return conn.db(options.projectId)
                .collection(table).aggregate(pipelines, { allowDiskUse: true }).toArray();
        }, options);
    }
    session() {
        return Promise.resolve(undefined);
    }
}
exports.MongoDatabaseFactory = MongoDatabaseFactory;
