use crate::collection::operation::WriteResult;
use crate::collection::{CollectionEventListener, Document, FindOptions, NitriteCollection, NitriteId, UpdateOptions};
use crate::common::{
AttributeAware, Attributes, Convertible, EventAware, PersistentCollection, Processor,
SubscriberRef,
};
use crate::errors::NitriteResult;
use crate::filter::Filter;
use crate::index::{IndexDescriptor, IndexOptions};
use crate::repository::cursor::ObjectCursor;
use crate::repository::NitriteEntity;
use crate::store::NitriteStore;
use std::ops::Deref;
use std::sync::Arc;
pub trait ObjectRepositoryProvider<T>: PersistentCollection
where
T: Convertible<Output = T> + NitriteEntity + Send + Sync
{
fn insert(&self, object: T) -> NitriteResult<WriteResult>;
fn insert_many(&self, objects: Vec<T>) -> NitriteResult<WriteResult>;
fn update(
&self,
filter: Filter,
object: T,
) -> NitriteResult<WriteResult> {
self.update_with_options(filter, object, &UpdateOptions::default())
}
fn update_with_options(
&self,
filter: Filter,
object: T,
update_options: &UpdateOptions,
) -> NitriteResult<WriteResult>;
fn update_one(&self, object: T, insert_if_absent: bool) -> NitriteResult<WriteResult>;
fn update_document(
&self,
filter: Filter,
document: &Document,
just_once: bool,
) -> NitriteResult<WriteResult>;
fn update_by_nitrite_id(
&self,
id: &NitriteId,
object: T,
insert_if_absent: bool,
) -> NitriteResult<WriteResult>;
fn remove_one(&self, object: T) -> NitriteResult<WriteResult>;
fn remove(&self, filter: Filter, just_once: bool) -> NitriteResult<WriteResult>;
fn get_by_id(&self, id: &T::Id) -> NitriteResult<Option<T>>;
fn find(&self, filter: Filter) -> NitriteResult<ObjectCursor<T>>;
fn find_with_options(
&self,
filter: Filter,
find_options: &FindOptions,
) -> NitriteResult<ObjectCursor<T>>;
fn document_collection(&self) -> NitriteCollection;
}
#[derive(Clone)]
pub struct ObjectRepository<T>
where
T: Convertible + NitriteEntity
{
inner: Arc<dyn ObjectRepositoryProvider<T>>,
}
impl<T> ObjectRepository<T>
where
T: Convertible<Output = T> + NitriteEntity + Send + Sync
{
pub fn new<I: ObjectRepositoryProvider<T> + 'static>(inner: I) -> Self {
ObjectRepository { inner: Arc::new(inner) }
}
}
impl<T> Deref for ObjectRepository<T>
where
T: Convertible + NitriteEntity
{
type Target = Arc<dyn ObjectRepositoryProvider<T>>;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::collection::operation::WriteResult;
use crate::collection::{Document, FindOptions, UpdateOptions};
use crate::common::{Attributes, DocumentCursor, Processor, ProcessorChain, ProcessorProvider, Value};
use crate::errors::{ErrorKind, NitriteError, NitriteResult};
use crate::filter::{all, field, Filter};
use crate::index::{IndexDescriptor, IndexOptions};
use crate::repository::cursor::ObjectCursor;
use crate::repository::{EntityId, EntityIndex};
use crate::store::NitriteStore;
use basu::HandlerId;
struct MockBaseObjectRepository;
impl PersistentCollection for MockBaseObjectRepository {
fn add_processor(&self, _processor: Processor) -> NitriteResult<()> {
Ok(())
}
fn create_index(&self, _field_names: Vec<&str>, _index_options: &IndexOptions) -> NitriteResult<()> {
Ok(())
}
fn rebuild_index(&self, _field_names: Vec<&str>) -> NitriteResult<()> {
Ok(())
}
fn list_indexes(&self) -> NitriteResult<Vec<IndexDescriptor>> {
Ok(vec![])
}
fn has_index(&self, _field_names: Vec<&str>) -> NitriteResult<bool> {
Ok(false)
}
fn is_indexing(&self, _field_names: Vec<&str>) -> NitriteResult<bool> {
Ok(false)
}
fn drop_index(&self, _field_names: Vec<&str>) -> NitriteResult<()> {
Ok(())
}
fn drop_all_indexes(&self) -> NitriteResult<()> {
Ok(())
}
fn clear(&self) -> NitriteResult<()> {
Ok(())
}
fn dispose(&self) -> NitriteResult<()> {
Ok(())
}
fn is_dropped(&self) -> NitriteResult<bool> {
Ok(false)
}
fn is_open(&self) -> NitriteResult<bool> {
Ok(true)
}
fn size(&self) -> NitriteResult<u64> {
Ok(0)
}
fn close(&self) -> NitriteResult<()> {
Ok(())
}
fn store(&self) -> NitriteResult<NitriteStore> {
Ok(NitriteStore::default())
}
}
impl EventAware for MockBaseObjectRepository {
fn subscribe(&self, _handler: CollectionEventListener) -> NitriteResult<Option<SubscriberRef>> {
Ok(Some(SubscriberRef::new(HandlerId::new())))
}
fn unsubscribe(&self, _subscriber: SubscriberRef) -> NitriteResult<()> {
Ok(())
}
}
impl AttributeAware for MockBaseObjectRepository {
fn attributes(&self) -> NitriteResult<Option<Attributes>> {
Ok(None)
}
fn set_attributes(&self, _attributes: Attributes) -> NitriteResult<()> {
Ok(())
}
}
impl<T> ObjectRepositoryProvider<T> for MockBaseObjectRepository
where
T: Convertible<Output = T> + NitriteEntity + Send + Sync,
{
fn insert(&self, _object: T) -> NitriteResult<WriteResult> {
Ok(WriteResult::new(vec![]))
}
fn insert_many(&self, _objects: Vec<T>) -> NitriteResult<WriteResult> {
Ok(WriteResult::new(vec![]))
}
fn update_with_options(
&self,
_filter: Filter,
_object: T,
_update_options: &UpdateOptions,
) -> NitriteResult<WriteResult> {
Ok(WriteResult::new(vec![]))
}
fn update_one(&self, _object: T, _insert_if_absent: bool) -> NitriteResult<WriteResult> {
Ok(WriteResult::new(vec![]))
}
fn update_document(
&self,
_filter: Filter,
_document: &Document,
_just_once: bool,
) -> NitriteResult<WriteResult> {
Ok(WriteResult::new(vec![]))
}
fn update_by_nitrite_id(
&self,
_id: &NitriteId,
_object: T,
_insert_if_absent: bool,
) -> NitriteResult<WriteResult> {
Ok(WriteResult::new(vec![]))
}
fn remove_one(&self, _object: T) -> NitriteResult<WriteResult> {
Ok(WriteResult::new(vec![]))
}
fn remove(&self, _filter: Filter, _just_once: bool) -> NitriteResult<WriteResult> {
Ok(WriteResult::new(vec![]))
}
fn get_by_id(&self, _id: &T::Id) -> NitriteResult<Option<T>> {
Ok(None)
}
fn find(&self, _filter: Filter) -> NitriteResult<ObjectCursor<T>> {
Ok(ObjectCursor::new(DocumentCursor::new(Box::new(vec![].into_iter()), ProcessorChain::new())))
}
fn find_with_options(
&self,
_filter: Filter,
_find_options: &FindOptions,
) -> NitriteResult<ObjectCursor<T>> {
Ok(ObjectCursor::new(DocumentCursor::new(Box::new(vec![].into_iter()), ProcessorChain::new())))
}
fn document_collection(&self) -> NitriteCollection {
todo!()
}
}
#[derive(Default)]
struct TestEntity {
id: String,
}
impl Convertible for TestEntity {
type Output = TestEntity;
fn to_value(&self) -> NitriteResult<Value> {
let mut document = Document::new();
document.put("id", Value::from(self.id.clone()))?;
Ok(Value::Document(document))
}
fn from_value(value: &Value) -> NitriteResult<Self::Output> {
match value {
Value::Document(document) => {
let item = document.get("id")?;
let id = item.as_string().unwrap();
Ok(TestEntity { id: id.clone() })
},
_ => Err(NitriteError::new(
"Repository conversion error: expected document value but found another type",
ErrorKind::InvalidOperation
)),
}
}
}
impl NitriteEntity for TestEntity {
type Id = String;
fn entity_name(&self) -> String {
"TestEntity".to_string()
}
fn entity_indexes(&self) -> Option<Vec<EntityIndex>> {
None
}
fn entity_id(&self) -> Option<EntityId> {
Some(EntityId::new("id", Some(false), None))
}
}
#[test]
fn test_insert() {
let repo = ObjectRepository::new(MockBaseObjectRepository);
let entity = TestEntity::default();
let result = repo.insert(entity);
assert!(result.is_ok());
}
#[test]
fn test_insert_batch() {
let repo = ObjectRepository::new(MockBaseObjectRepository);
let entities = vec![TestEntity::default(), TestEntity::default()];
let result = repo.insert_many(entities);
assert!(result.is_ok());
}
#[test]
fn test_update() {
let repo = ObjectRepository::new(MockBaseObjectRepository);
let entity = TestEntity::default();
let filter = field("id").eq("test_id");
let update_options = UpdateOptions::default();
let result = repo.update_with_options(filter, entity, &update_options);
assert!(result.is_ok());
}
#[test]
fn test_update_one() {
let repo = ObjectRepository::new(MockBaseObjectRepository);
let entity = TestEntity::default();
let result = repo.update_one(entity, true);
assert!(result.is_ok());
}
#[test]
fn test_update_document() {
let repo: ObjectRepository<TestEntity> = ObjectRepository::new(MockBaseObjectRepository);
let filter = all();
let document = Document::default();
let result = repo.update_document(filter, &document, true);
assert!(result.is_ok());
}
#[test]
fn test_remove_one() {
let repo: ObjectRepository<TestEntity> = ObjectRepository::new(MockBaseObjectRepository);
let entity = TestEntity::default();
let result = repo.remove_one(entity);
assert!(result.is_ok());
}
#[test]
fn test_remove() {
let repo: ObjectRepository<TestEntity> = ObjectRepository::new(MockBaseObjectRepository);
let filter = all();
let result = repo.remove(filter, true);
assert!(result.is_ok());
}
#[test]
fn test_get_by_id() {
let repo: ObjectRepository<TestEntity> = ObjectRepository::new(MockBaseObjectRepository);
let id = "test_id".to_string();
let result = repo.get_by_id(&id);
assert!(result.is_ok());
assert!(result.unwrap().is_none());
}
#[test]
fn test_find() {
let repo: ObjectRepository<TestEntity> = ObjectRepository::new(MockBaseObjectRepository);
let filter = all();
let result = repo.find(filter);
assert!(result.is_ok());
}
#[test]
fn test_find_options() {
let repo: ObjectRepository<TestEntity> = ObjectRepository::new(MockBaseObjectRepository);
let filter = all();
let find_options = FindOptions::default();
let result = repo.find_with_options(filter, &find_options);
assert!(result.is_ok());
}
#[test]
fn test_subscribe() {
let repo: ObjectRepository<TestEntity> = ObjectRepository::new(MockBaseObjectRepository);
let handler = CollectionEventListener::new(Box::new(|_event| Ok(())));
let result = repo.subscribe(handler);
assert!(result.is_ok());
}
#[test]
fn test_unsubscribe() {
let repo: ObjectRepository<TestEntity> = ObjectRepository::new(MockBaseObjectRepository);
let subscriber = SubscriberRef::new(HandlerId::new());
let result = repo.unsubscribe(subscriber);
assert!(result.is_ok());
}
#[test]
fn test_attributes() {
let repo: ObjectRepository<TestEntity> = ObjectRepository::new(MockBaseObjectRepository);
let result = repo.attributes();
assert!(result.is_ok());
}
#[test]
fn test_set_attributes() {
let repo: ObjectRepository<TestEntity> = ObjectRepository::new(MockBaseObjectRepository);
let attributes = Attributes::default();
let result = repo.set_attributes(attributes);
assert!(result.is_ok());
}
#[test]
fn test_add_processor() {
struct MockProcessor;
impl ProcessorProvider for MockProcessor {
fn name(&self) -> String {
"MockProcessor".to_string()
}
fn process_before_write(&self, doc: Document) -> NitriteResult<Document> {
Ok(doc)
}
fn process_after_read(&self, doc: Document) -> NitriteResult<Document> {
Ok(doc)
}
}
let repo: ObjectRepository<TestEntity> = ObjectRepository::new(MockBaseObjectRepository);
let processor = Processor::new(MockProcessor);
let result = repo.add_processor(processor);
assert!(result.is_ok());
}
#[test]
fn test_create_index() {
let repo: ObjectRepository<TestEntity> = ObjectRepository::new(MockBaseObjectRepository);
let field_names = vec!["field1"];
let index_options = IndexOptions::default();
let result = repo.create_index(field_names, &index_options);
assert!(result.is_ok());
}
#[test]
fn test_rebuild_index() {
let repo: ObjectRepository<TestEntity> = ObjectRepository::new(MockBaseObjectRepository);
let field_names = vec!["field1"];
let result = repo.rebuild_index(field_names);
assert!(result.is_ok());
}
#[test]
fn test_list_indexes() {
let repo: ObjectRepository<TestEntity> = ObjectRepository::new(MockBaseObjectRepository);
let result = repo.list_indexes();
assert!(result.is_ok());
}
#[test]
fn test_has_index() {
let repo: ObjectRepository<TestEntity> = ObjectRepository::new(MockBaseObjectRepository);
let field_names = vec!["field1"];
let result = repo.has_index(field_names);
assert!(result.is_ok());
}
#[test]
fn test_is_indexing() {
let repo: ObjectRepository<TestEntity> = ObjectRepository::new(MockBaseObjectRepository);
let field_names = vec!["field1"];
let result = repo.is_indexing(field_names);
assert!(result.is_ok());
}
#[test]
fn test_drop_index() {
let repo: ObjectRepository<TestEntity> = ObjectRepository::new(MockBaseObjectRepository);
let field_names = vec!["field1"];
let result = repo.drop_index(field_names);
assert!(result.is_ok());
}
#[test]
fn test_drop_all_indexes() {
let repo: ObjectRepository<TestEntity> = ObjectRepository::new(MockBaseObjectRepository);
let result = repo.drop_all_indexes();
assert!(result.is_ok());
}
#[test]
fn test_clear() {
let repo: ObjectRepository<TestEntity> = ObjectRepository::new(MockBaseObjectRepository);
let result = repo.clear();
assert!(result.is_ok());
}
#[test]
fn test_destroy() {
let repo: ObjectRepository<TestEntity> = ObjectRepository::new(MockBaseObjectRepository);
let result = repo.dispose();
assert!(result.is_ok());
}
#[test]
fn test_is_dropped() {
let repo: ObjectRepository<TestEntity> = ObjectRepository::new(MockBaseObjectRepository);
let result = repo.is_dropped();
assert!(result.is_ok());
}
#[test]
fn test_is_open() {
let repo: ObjectRepository<TestEntity> = ObjectRepository::new(MockBaseObjectRepository);
let result = repo.is_open();
assert!(result.is_ok());
}
#[test]
fn test_size() {
let repo: ObjectRepository<TestEntity> = ObjectRepository::new(MockBaseObjectRepository);
let result = repo.size();
assert!(result.is_ok());
}
#[test]
fn test_close() {
let repo: ObjectRepository<TestEntity> = ObjectRepository::new(MockBaseObjectRepository);
let result = repo.close();
assert!(result.is_ok());
}
#[test]
fn test_store() {
let repo: ObjectRepository<TestEntity> = ObjectRepository::new(MockBaseObjectRepository);
let result = repo.store();
assert!(result.is_ok());
}
}