Documentation
use crate::document::document::BaseDocument;
use crate::document::pageable::{PageableRequest, PageableResponse};
use async_trait::async_trait;
use bson::oid::ObjectId;
use bson::Document;
use mongodb::error::Error;
use mongodb::options::{
    DeleteOptions, FindOneAndDeleteOptions, FindOneOptions, FindOptions, InsertManyOptions,
};
use opentelemetry::Context;
use std::fmt::Debug;

/// Base repository trait.
/// The context passed here is open telemetry context which is useful for telemetry/monitoring purposes
#[async_trait]
pub trait Repository<
    T: BaseDocument + Debug + serde::ser::Serialize + for<'de> serde::Deserialize<'de>,
>
{
    /// Save a new document
    async fn save(&self, entity: T, ctx: Option<&Context>) -> Result<ObjectId, Error>;

    /// Save many documents
    async fn save_many(
        &self,
        entities: Vec<T>,
        ctx: Option<&Context>,
        options: Option<InsertManyOptions>,
    ) -> Result<Vec<ObjectId>, Error>;

    /// Get all documents from a collection (pageable)
    async fn get_all_pageable(
        &self,
        request: PageableRequest,
        ctx: Option<&Context>,
    ) -> Result<PageableResponse<T>, Error>;

    /// Get the number of documents in a collection
    async fn count_documents_in_collection(&self, ctx: Option<&Context>) -> Result<u64, Error>;

    /// find a document by ObjectId hex(string)
    async fn find_by_id(&self, id: &str, ctx: Option<&Context>) -> Result<T, Error>;

    /// find a document by ObjectId
    async fn find_by_raw_id(&self, id: ObjectId, ctx: Option<&Context>) -> Result<T, Error>;

    /// Find documents by a list of ObjectId hex(string)
    async fn find_by_ids(&self, ids: Vec<String>, ctx: Option<&Context>) -> Result<Vec<T>, Error>;

    /// Find documents by a list of ObjectIds
    async fn find_by_raw_ids(
        &self,
        pids: Vec<ObjectId>,
        ctx: Option<&Context>,
    ) -> Result<Vec<T>, Error>;

    /// Find 1 document by a user defined filter
    async fn find_by_filter_and_options(
        &self,
        filter: Document,
        options: Option<FindOneOptions>,
        ctx: Option<&Context>,
    ) -> Result<T, Error>;

    /// Find a list of documents by a user defined filter
    async fn find_all_by_filter_and_options(
        &self,
        filter: Document,
        options: Option<FindOptions>,
        ctx: Option<&Context>,
    ) -> Result<Vec<T>, Error>;

    /// Update an existing document
    async fn update(&self, document: &T, ctx: Option<&Context>) -> Result<ObjectId, Error>;

    /// Delete an existing document by ObjectID
    async fn delete_by_id(&self, id: ObjectId, ctx: Option<&Context>) -> Result<(), Error>;

    /// Delete a list existing documents by ObjectIDs
    async fn delete_by_ids(&self, ids: Vec<ObjectId>, ctx: Option<&Context>) -> Result<(), Error>;

    /// Delete an existing document by a user filter
    async fn delete(
        &self,
        filter: Document,
        ctx: Option<&Context>,
        options: Option<FindOneAndDeleteOptions>,
    ) -> Result<(), Error>;

    /// Delete existing documents by a user defined filter
    async fn delete_many(
        &self,
        filter: Document,
        ctx: Option<&Context>,
        options: Option<DeleteOptions>,
    ) -> Result<(), Error>;
}