Closed kushuh closed 1 year ago
It is impossible to have bun.PostgresConfig
without adding a dependency on pgdriver
and pgdialect
, which makes MySQL users unahppy and does not allow to use pgx
.
Perhaps you should just extract the functionality you need to a package in your repo.
I wonder if it could be possible to have a config
or params
module, that would work similarly to driver
and dialect
(with specialized sub-modules to separate dependencies).
config
\_ sqlconfig
\_ ...
\_ pgconfig
The pgconfig
module could have 2 configuration objects, one for pgdriver
and another for pgx
.
It could also be a solution to completly not support pgx with configuration based instantiation, since it is more suited for simple use-cases and using pgx
instead of the internal pgdriver
would not fall in such a scenario (again it is a quick start solution that does not replace the current api, it doesn't have to cover every use-case).
This would still allow for a 1-line declaration with a configuration object, and would just involve to do the right imports (kind of like it already works for drivers and dialects actually).
I can get away with sticking to my own repositories but it is still frustrating to not have a generic solution π . Driver-specific configuration could still be passed by importing the right module without conflict.
Plus migrations seem to work equally no matter which driver is used, and there is only 2 of them (go-based and sql-based), which I think can be handled pretty easily in a configuration object (especially now that go has generics). I tend to believe configuration patterns are more readable than declarative one, easier to understand, and especially with go tedious error handling, having a single failure point is another argument for me.
But maybe all of this is too much opinion-based. I'd still be happy to have an integrated solution, but for now I'll work with my own package π.
To complete my last message, it could ressemble something like this:
db, err := config.NewClient(config.Config{
Driver: pgconfig.Config{ // This could possibly be handled elegantly with generics?
DSN: "blablabla",
},
// Not scoped since not specific to a driver, maybe there is a more elegant solution.
Migrations: &config.Migrations{
Files: []fs.FS{/* list of FS to apply Discover to */},
// IDK what type to put here, I don't use Go migrations that much.
Go: []interface{},
}
})
Or another use-case:
db, err := config.NewClient(config.Config{
Driver: pgconfig.PGXConfig{DSN: "blablabla"},
})
Each config object could ship with class methods that would return a *bun.DB
instance, so that the main package only calls this method (eg: Init
or Connect
). Thus the Driver
key could be of type interface, where the interface only contains one method to create the *bun.DB
object.
type DriverConfig interface{
// No circular deps because `config` is never called from the main package.
Connect() (*bun.DB, error)
}
type Config struct {
Driver DriverConfig
Migrations // ...
}
I also have doubt about the name config
, but basically the idea would be to have a "quickstart" module with preconfigured 1-line handlers.
If someone is interested in the issue or wants an alternative solution, I made a "poc" of my idea based on previous work. I'll use it for now, not loosing hope on having a native solution one day π.
The issue
I love bun for its simplicity, but initialization is a pain point. Basically, I have many repos where I always need to do only 2 things:
I find the steps to do so quite verbose (in a bad way) and have written a dedicated utils package just for this.
Currently, I have to do something along those lines (to start the connection and run migrations):
This is a lot of lines for a very simple need (and quite tedious to figure out for someone new to the ORM).
The proposal
This ORM does it in a way I find more elegant: https://github.com/go-redis/redis (I can see you also contribute to it @vmihailenco π).
The idea would be, for cases that require minimal configuration, to allow a 1-line method that would ressemble this, and would handle all the "dirty" work:
Where
options
would be a single configuration object with optional values.I have some ideas for how to handle things such as switching dialects and running migrations (I already done some work in my repositories with Postgres driver). With some approval I can start working on a more concrete proposition (PR? Design Document?) as soon as this weekend.
Pros
=> Mostly sugar-syntax, so testing should be fast and easy => Does not break anything, only addition to current apis => More versatile, easier to read, less verbose for simple configurations => Better errors handling (a single failure point instead of many)
Example
That's something ressembling the solution I'd come up with right now:
Or: