Skip to content
Snippets Groups Projects
MongoDBClient.scala 4.11 KiB
Newer Older
package models

Felipe D'Abrantes's avatar
Felipe D'Abrantes committed
import utils.ConfigHelper
import org.mongodb.scala.{MongoClient, MongoDatabase, MongoCollection, Document, FindObservable, Observer, Observable}
import org.mongodb.scala.model.{Filters, Projections, Sorts}
import org.bson.conversions.Bson
import org.bson.types.ObjectId

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
import scala.util.{Success, Failure, Try}


/**
 * A MongoDB client for connecting to and interacting with a MongoDB database.
 * 
 * @constructor Creates a new instance of the MongoDBClient class.
 */
class MongoDBClient {
Felipe D'Abrantes's avatar
Felipe D'Abrantes committed
    private val mongoUri = ConfigHelper.getString("mongodb.uri")
    // Connects to a MongoDB Client when class is constructed
    private var client: MongoClient = this.connect()

    /**
     * Connects to a MongoDB database using the default MongoDB connection string.
     * 
     * @return A MongoClient instance.
     */
    def connect(): MongoClient = {
        MongoClient(mongoUri)
    }

    /**
     * Gets a reference to a MongoDB database.
     * 
     * @param database The name of the database to retrieve.
     * @return A Future containing a MongoDatabase instance.
     */
    def getDatabase(database: String): Future[MongoDatabase] = Future {
        client.getDatabase(database)
    }

    /**
     * Gets a reference to a MongoDB collection within a database.
     * 
     * @param database The MongoDatabase instance containing the desired collection.
     * @param collection The name of the collection to retrieve.
     * @return A Future containing a MongoCollection instance.
     */
    def getCollection(database: MongoDatabase, collection: String): Future[MongoCollection[Document]] = Future {
        database.getCollection(collection)
    }

    /**
     * Finds documents in a MongoDB collection.
     * 
     * @param collection The MongoCollection instance to search.
     * @param filter A Bson filter to apply to the search.
     * @param projection A Bson projection to apply to the search.
     * @param sort A Bson sort to apply to the search.
     * @return A Future containing a sequence of matching documents as Documents.
     */
    def find(
        collection: MongoCollection[Document], 
        filter: Bson = Filters.empty(), 
        projection: Bson = Projections.excludeId(),
        sort: Bson = Sorts.ascending("_id")
    ): Future[Seq[Document]] = {
        collection.find(filter)
        .projection(projection)
        .sort(sort)
        .toFuture()
    }

    /**
     * Inserts a document into a MongoDB collection.
     * 
     * @param collection The MongoCollection instance to insert into.
     * @param document The document to insert.
     * @return A Future containing the ID of the inserted document.
     * @throws RuntimeException if the insertion was not acknowledged by the database.
     */
    def insertOne(collection: MongoCollection[Document], document: Document): Future[String] = {
        val futureResult = collection.insertOne(document).toFuture()
        
        futureResult.map(result => {
            if (result.wasAcknowledged()) {
                // Grab the generated ID of the inserted document
                result.getInsertedId().asObjectId.getValue().toString()
            } else {
                throw new RuntimeException("Insertion was not acknowledged")
            }
        })
    }

    /**
     * Updates a document in a MongoDB collection.
     * 
     * @param collection The MongoCollection instance the document is in.
     * @param documentId The ID of the document to update.
     * @param updates A sequence of Bson documents defining the updates.
     * @throws RuntimeException if the update was not acknowledged by the database.
     */
    def updateOne(collection: MongoCollection[Document], documentId: ObjectId, updates: Seq[Bson]): Future[Unit] = {
        val filter = Filters.equal("_id", documentId)
        val futureResult =  collection.updateOne(filter, updates).toFuture()
        
        futureResult.map(result => {
            if (!result.wasAcknowledged()) {
                throw new RuntimeException("Update was not acknowledged")
            }
        })
    }