skerkour / bloom-legacy

DEPRECATED - End-to-end encrypted Notes, Files, Calendar, Contacts... for Android, IOS, Linux & MacOS
https://bloom.sh
Other
123 stars 23 forks source link

Congratulations and question about repositories #71

Closed frederikhors closed 7 months ago

frederikhors commented 8 months ago

Dear @skerkour @skerkour-dev,

I switched from Go to Rust recently and I'm learning day by day.

Thank you for your project. It's really inspiring to see such a beautiful code. Thanks again.

I re-visited after some time this amazing project and I have a question, I'm hoping for an answer from you, if it's not too much trouble. :)

I have a similar code architecture in my project. But I'm struggling with DB transactions and different databases changed at runtime.

I see you're passing DB directly in services:

pub struct Repository {}

pub struct Service {
    repo: Repository,
    pub db: DB,
}

with DB:

use sqlx::{self, Executor, Pool, Postgres, Transaction};

pub type DB = Pool<Postgres>;

pub trait Queryer<'c>: Executor<'c, Database = sqlx::Postgres> {}

impl<'c> Queryer<'c> for &Pool<Postgres> {}
impl<'c> Queryer<'c> for &'c mut Transaction<'_, Postgres> {}

I can understand why: you can create transactions in services directly using something like:

let mut tx = pool.begin().await?;

// use tx

tx.commit().await?;

and even if this is not exactly what the Clean Architecture prescribes IMO (the services level goes into the details of persistence which is one level below) let's say I could accept it for "practicity of writing daily code".

But what I can't figure out is what I should change in the code to have at runtime the choice whether to persist on postgresql or MongoDB or in memory for example.

Much complex projects I have seen have a lot of traits in the service layer to describe the repository behavior.

And those traits are implemented for Postgresql's, MongoDB's and InMemory's one. Does it make sense to you?

Can you show (maybe in a separate branch so I can easily spot differences with git diff) what to change to start app either with Postgresql or another persistence adapter?

I imagine we need to have multiple directories under repository:

And then?

Thank you very much in advance and congratulations again for this amazing project!

frederikhors commented 7 months ago

@sylvain101010 what do you think?

sylvain101010 commented 7 months ago

I think that trying to use different databases is practically impossible. It may sounds nice for hello world examples, or simple use cases such as a key-value store, but it will be impossible to make any real-world application like that.

The Queryer is used by the repository layer to abstract the database connection (normal connection or transaction) because in the real-world you either need to have some business logic in your transaction, or to make cross-service transaction (and thus the repository layer can't create/read/update entities from another service).

If you persist in this way, a trait would indeed be the way to go, you can learn more on my blog https://kerkour.com/rust-web-application-clean-architecture and in my book https://kerkour.com/black-hat-rust

Good luck :)

frederikhors commented 7 months ago

Thank you for the answer.

use different databases is practically impossible

Why do you say that?