UNPKG

tspace-mysql

Version:

Tspace MySQL is a promise-based ORM for Node.js, designed with modern TypeScript and providing type safety for schema databases.

255 lines 8.62 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.MongodblDriver = void 0; const __1 = require(".."); const MongodbQueryBuilder_1 = require("./MongodbQueryBuilder"); class MongodblDriver extends __1.BaseDriver { db; _connecting; constructor(options) { super(); this.options = options; } connect() { const options = this.options; const { MongoClient } = this.import("mongodb"); const url = `mongodb://${options.user}:${options.password}@${options.host}:${options.port}/${options.database}?authSource=admin`; this.pool = new MongoClient(url, { maxPoolSize: options.connectionLimit ?? 10, minPoolSize: Math.max(2, Math.floor((options.connectionLimit ?? 10) / 3)), maxIdleTimeMS: 1000 * 60, }); this._connecting = this.pool .connect() .then(() => { this.db = this.pool.db(options.database); if (this.options.CONNECTION_SUCCESS) { console.log(this._messageConnected("MongoDB connected")); } }) .catch((err) => { const message = this._messageError.bind(this); console.log(message(err?.message)); if (this.options.CONNECTION_ERROR) process.exit(); }); return { database: () => options.database, on: (event, data) => this.on(event, data), queryBuilder: MongodbQueryBuilder_1.MongodbQueryBuilder, query: async (collection) => this._query(collection), connection: () => this._connection(), end: () => this._end(), }; } disconnect(pool) { if (pool == null) return; pool?.end(() => { pool = undefined; }); } async _query(pipeline) { if (this.db == null) { await this._connecting; } if (this.db?.collection == null) { throw new Error("Failed to establish a connection to the collection."); } const { type, collection, args } = this._parseInput(pipeline); const col = this.db.collection(collection); let results; switch (type) { case 'aggregate': results = await col.aggregate(args).toArray(); break; case 'insertMany': results = await col.insertMany(args); break; case 'updateMany': results = await col.updateMany(args.filter, args.update); break; case 'deleteMany': results = await col.deleteMany(args); break; default: throw new Error('Unsupported query type'); } this.meta(results, pipeline); return this.returning(results); } async _connection() { if (this.db == null) { await this._connecting; } const client = this.pool; const session = client.startSession(); let closed = false; let inTransaction = false; const supportsTransaction = client?.topology?.s?.description?.type !== "Single"; const ensureOpen = () => { if (closed) throw new Error(this.MESSAGE_TRX_CLOSED); }; const query = async (collectionName) => { ensureOpen(); const start = Date.now(); const collection = this.db.collection(collectionName); let data; if (supportsTransaction && inTransaction) { data = await collection.aggregate([], { session }).toArray(); } else { data = await collection.aggregate([]).toArray(); } this._detectEventQuery({ start, sql: collectionName, }); this.meta(data, collectionName); return this.returning(data); }; const startTransaction = async () => { ensureOpen(); if (!supportsTransaction) { throw new Error("MongoDB is running in standalone mode. Transactions are not supported."); } if (inTransaction) { throw new Error("Transaction already started"); } session.startTransaction(); inTransaction = true; }; const commit = async () => { ensureOpen(); if (supportsTransaction && inTransaction) { await session.commitTransaction(); } inTransaction = false; await end(); }; const rollback = async () => { ensureOpen(); if (supportsTransaction && inTransaction) { await session.abortTransaction(); } inTransaction = false; await end(); }; const end = async () => { if (closed) return; closed = true; await session.endSession(); }; return { on: (event, data) => this.on(event, data), queryBuilder: MongodbQueryBuilder_1.MongodbQueryBuilder, query, startTransaction, commit, rollback, end, release: async () => { return; } }; } async _end() { if (!this.pool) return; await this.pool.close(); this.pool = undefined; console.log("MongoDB connection closed"); } meta(results, pipeline) { if (Array.isArray(results)) return; if (results.$meta == null) results.$meta = {}; const command = this._detectQueryType(pipeline); results.$meta = { command }; if (command === "INSERT") { const insertIds = Object.values(results.insertedIds); results.$meta = { ...results.$meta, insertIds, affected: true, }; } if (command === "UPDATE" || command === "DELETE") { results.$meta = { ...results.$meta, insertIds: [], affected: Boolean(results.affectedRows), }; } } returning(results) { if (Array.isArray(results)) return results; return results; } _parseInput(input) { let match = input.match(/db\.([a-zA-Z0-9_]+)\.aggregate\((\[.*\])\)\.toArray\(\)/); if (match) { const [, collection, pipelineStr] = match; return { type: 'aggregate', collection, args: JSON.parse(pipelineStr) }; } match = input.match(/db\.([a-zA-Z0-9_]+)\.insertMany\((\[.*\])\)/); if (match) { const [, collection, docsStr] = match; return { type: 'insertMany', collection, args: JSON.parse(docsStr) }; } match = input.match(/db\.([a-zA-Z0-9_]+)\.updateMany\((\{.*\}),\s*(\{.*\})\)/); if (match) { const [, collection, filterStr, updateStr] = match; return { type: 'updateMany', collection, args: { filter: JSON.parse(filterStr), update: JSON.parse(updateStr) } }; } match = input.match(/db\.([a-zA-Z0-9_]+)\.deleteMany\((\{.*\})\)/); if (match) { const [, collection, filterStr] = match; return { type: 'deleteMany', collection, args: JSON.parse(filterStr) }; } return { type: 'unknown', collection: '', args: null }; } _detectQueryType(query) { const { type } = this._parseInput(query); const selectRegex = /^\s*aggregate\b/i; const updateRegex = /^\s*updateMany\b/i; const insertRegex = /^\s*insertMany\b/i; const deleteRegex = /^\s*deleteMany\b/i; if (selectRegex.test(type)) return "SELECT"; if (updateRegex.test(type)) return "UPDATE"; if (insertRegex.test(type)) return "INSERT"; if (deleteRegex.test(type)) return "DELETE"; return "UNKNOWN"; } } exports.MongodblDriver = MongodblDriver; //# sourceMappingURL=MongodbDriver.js.map