Closed casey closed 1 week ago
Oh yeah, in particular I'm curious about efficiency. A downside of this approach is that the database has to open and close tables for each query, instead of reusing them.
One cool thing would be if you could express table definitions fully in the type system, i.e., by using the table name as a const generic, in which case you wouldn't need wrappers, but const generics don't support strings. I think you could do it though if table names were integers.
Oh yeah, in particular I'm curious about efficiency. A downside of this approach is that the database has to open and close tables for each query, instead of reusing them.
I haven't benchmarked it, but my guess is this is fine. Opening and closing tables should be cheap, so as long as the queries are non-trivial it's probably fine
I haven't looked at axum, but this definitely seems like an interesting idea! When I first started redb, I was actually thinking it would be a little more like sqlite than lmdb, but then I quickly gave up on that idea.
One thing that seems a bit off about the proposed Query
trait is that run()
only takes the transaction as an argument. How would I pass in a value other than "james"
? I was expecting it to look a little more like a prepared statement in SQL, where you write the function that executes operations on a Table
(s), and then you pass arguments into that function to execute it
I added an example in the tests using a closure, which allows you to pass in outside arguments. I also added an example using a struct and implementing query manually, which is pretty gross but probably becomes okay once you have enough things that the boilerplate of opening tables is greater than the boilerplate of the trait implementation.
Ah yes, I see how it works. Are you using it in ord
? I'd be curious to see whether the code ends up being cleaner with this approach, in practice
I'm not, but I'll try it out and see how it works in practice.
Feel free to re-open if you do further work on this
I was inspired by axum to try to write a library for easily writing redb queries, called redbql. The "ql" is for query library, since it's not really a language.
It introduces a few new traits.
Query
is a function that runs against a read transaction.Statement
is a function that runs against a write transaction.StatementArg
is something that can produce a value from a write transaction, andQueryArg
is something that can produce a value from a read transaction.You can write a
Query
orStatement
implementation manually, but the nice thing is that it can be auto-implemented for functions which take types which implementQueryArg
/StatementArg
:And a boilerplate macro for declaring tables with corresponding
QueryArg
andStatrementArg
types:And finally, what this buys is, is that we can write functions that implement our queries, and the tables are opened for us:
What do you think? I just finished the implementation, and want to play with it a bit more to see how it works inside of
ord
. I think this gets very close to the convenience of SQL statements, where you just use the tables you want, and the database takes care of opening them for you.I also wanted to write a function on
Database
which would take a query an execute it without needing to start a transaction, but I ran into lifetime errors and gave up T_T I'm sure someone clever can come up with a working version tho.