UNPKG

adonis-odm

Version:

A comprehensive MongoDB ODM for AdonisJS with Lucid-style API, type-safe relationships, embedded documents, and transaction support

134 lines (133 loc) 5.35 kB
import 'reflect-metadata'; import { MongoDatabaseManager } from '../src/database_manager.js'; import { BaseModel } from '../src/base_model/base_model.js'; import { ModelQueryBuilder } from '../src/query_builder/model_query_builder.js'; import { PersistenceManager } from '../src/base_model/persistence_manager.js'; import { SeederManager } from '../src/seeders/seeder_manager.js'; /** * MongoDB ODM Service Provider for AdonisJS */ export default class MongodbProvider { app; constructor(app) { this.app = app; } manager; /** * Register bindings to the container */ register() { // Create the database manager instance const config = this.app.config.get('odm'); if (!config) { throw new Error('ODM configuration not found. Please ensure config/odm.ts is properly configured.'); } if (!config.connections) { throw new Error('ODM connections not configured. Please check your config/odm.ts file.'); } this.manager = new MongoDatabaseManager(config); // Store it in the container this.app.container.bind('mongodb.manager', () => this.manager); this.app.container.bind('mongodb', () => this.manager); // Also register the class itself for the service pattern this.app.container.bind(MongoDatabaseManager, () => this.manager); // Register SeederManager as a singleton this.app.container.singleton('odm.seeder', () => { return new SeederManager(config, this.manager); }); // Also register the class itself for the service pattern this.app.container.bind(SeederManager, () => { return this.app.container.make('odm.seeder'); }); } /** * Boot the provider */ async boot() { // Extend BaseModel with database functionality this.extendBaseModel(); } /** * Start the provider */ async start() { // Connect to MongoDB when the application starts // Skip auto-connection if autoConnect is explicitly set to false in config if (this.manager) { const config = this.app.config.get('odm'); const shouldAutoConnect = config?.autoConnect !== false; if (shouldAutoConnect) { await this.manager.connect(); } } } /** * Ready hook */ async ready() { // Provider is ready } /** * Shutdown hook */ async shutdown() { // Close all MongoDB connections if (this.manager) { await this.manager.close(); } } /** * Extend BaseModel with database functionality */ extendBaseModel() { const manager = this.manager; // Override the static query method to use the actual database connection BaseModel.query = function (options) { const collectionName = this.getCollectionName(); const connectionName = this.getConnection(); const collection = manager.collection(collectionName, connectionName); const queryBuilder = new ModelQueryBuilder(collection, this); // If transaction client is provided, associate it with the query builder if (options?.client) { queryBuilder.useTransaction(options.client); } return queryBuilder; }; // Extend PersistenceManager with database functionality // Override the performInsert method in PersistenceManager PersistenceManager.prototype.performInsert = async function (session) { const model = this.model; const constructor = model.constructor; const collectionName = constructor.getCollectionName(); const connectionName = constructor.getConnection(); const collection = manager.collection(collectionName, connectionName); const document = model.toDocument(); // Remove _id if it's undefined to let MongoDB generate it if (!document._id) { delete document._id; } // Use session if provided (for transactions) const options = session ? { session } : {}; const result = await collection.insertOne(document, options); model._id = result.insertedId; }; // Override the performUpdate method in PersistenceManager PersistenceManager.prototype.performUpdate = async function (session) { const model = this.model; if (!model._id) { throw new Error('Cannot update model without an ID'); } const constructor = model.constructor; const collectionName = constructor.getCollectionName(); const connectionName = constructor.getConnection(); const collection = manager.collection(collectionName, connectionName); const updates = model.getDirtyAttributes(); if (Object.keys(updates).length === 0) { return; // Nothing to update } // Use session if provided (for transactions) const options = session ? { session } : {}; await collection.updateOne({ _id: model._id }, { $set: updates }, options); }; } }