kurtbuilds / ormlite

An ORM in Rust for developers that love SQL.
https://crates.io/crates/ormlite
MIT License
216 stars 11 forks source link

how can i use the feature "sqlite" and "mysql" at the same time? #17

Open miaomiao1992 opened 1 year ago

miaomiao1992 commented 1 year ago

[cfg(feature = "mysql")]

compile_error!("mysql is currently not supported");

[cfg(feature = "postgres")]

pub type DB = postgres::PostgresBackend;

[cfg(feature = "sqlite")]

pub type DB = sqlite::SqliteBackend;

kurtbuilds commented 1 year ago

Yeah, this is an unfortunate limitation that needs to be fixed.

Part of the question is, how to resolve which databases to codegen for if you have multiple features enabled.

Some options might be:

  1. If multiple features are enabled, just use any database.
  2. If mutiple features are enabled, codegen for every database type.
  3. If multiple features are enabled, require an annotation like #[ormlite(database = "postgres")] for any #[derive(Model)] struct.

Thoughts?

andreapavoni commented 1 year ago

Considering that I don't know how's statistically relevant in terms of use case, I'd opt for the option 3. It's a bit more verbose, but it's also clear and explicit, so that developers don't get confused about which model belongs to which db, and codegen doesn't need to produce unneeded pieces (like the option 2).

mikkel1156 commented 1 year ago

Wouldn't option 3 make it less flexible? My use-case for having support or multiple databases is so the administrator could choose. It wouldn't be able to do this flexibly at runtime anymore if we use annotations, since we then need to have duplicate models for every database supported.

andreapavoni commented 1 year ago

My use-case for having support or multiple databases is so the administrator could choose. It wouldn't be able to do this flexibly at runtime anymore if we use annotations

Maybe I misunderstood your words, or I've read them too literally, but "switching db at runtime from an admin action" is something out of scope for an ORM library.

If, instead, you were referring to the ability to switch the database through some kind of configuration (and then restarting the app) maybe option 2 is more appropriate for the goal. But this solution might be a problem if/when your use-case is to have different models on different dbs (which I know it might be a very narrow/rare use case).

I really don't have idea about how much it is possible/reasonable, but perhaps a combination of 1, 2 and 3 would work well: you either choose a specific db or any annotation on model, then codegen accordingly.

Just my 2 cents

mikkel1156 commented 1 year ago

If, instead, you were referring to the ability to switch the database through some kind of configuration (and then restarting the app) maybe option 2 is more appropriate for the goal. But this solution might be a problem if/when your use-case is to have different models on different dbs (which I know it might be a very narrow/rare use case).

This was more what I was thinking yes. Meant runtime as in it checks and chooses backend when i starts up as part of initialization.

A combination as you described might be good.

kurtbuilds commented 1 year ago

It's not done, but the commit above starts to build support for this.

Since the database gets parameterized in a generic, there will be support for backing the same model with multiple databases.

That would enable the use case of switching backends at runtime, but I agree that making that seamless is beyond the scope of an ORM.

Finishing this is mostly about fixing compile issues at this point, so I'd welcome PRs if anyone wants to get it over the finish line.

The syntax that I think makes the most sense is something like the following:

# cargo build --features sqlite,postgres

#[ormlite(database="sqlite")
pub struct BuiltForSqlite {}

// without the annotation, this will fail to compile.
pub struct NoAnnotation {}

// two annotations also works
#[ormlite(database="sqlite")
#[ormlite(database="postgres")
pub struct TwoAnnotations {}

Additionally, there would be features, default-<db> to avoid defaults for most structs

# cargo build --features sqlite,default-postgres

// the annotation overrides the default, so this is built only for sqlite
#[ormlite(database="sqlite")
pub struct BuiltForSqlite {}

// because of default-postgres feature, this now compiles with postgres.
pub struct NoAnnotation {}

// two annotations works as before
#[ormlite(database="sqlite")
#[ormlite(database="postgres")
pub struct TwoAnnotations {}

Let me know any feedback!