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
JavaScript
;
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