Open melkir opened 2 years ago
Sure. This is in our to do list. We don't have a timeline yet, though.
Just to mention it's the only thing preventing me from switching from Postgres :)
Adding my +1 for support of this feature. Compile-time guarantees are my biggest reason for using Rust, and I would love to see EdgeDB take full advantage of that. As a newbie to EdgeDB, this would also be extremely helpful for getting me getting used to the query language.
Also adding +1, this feature would provide a great end-to-end experience with the static typing of Rust and EdgeDB.
@melkir @imbolc @tailhook @MarioIshac I've just published a tool I've been using internally this week.
https://github.com/ifiokjr/edgedb_codegen
It's still very early and I'm eager for feedback.
The types are currently generated from a running instance of the edgedb
instance using the environment variable EDGEDB_INSTANCE
. Once this is in place it will automatically verify the queries written.
use edgedb_codegen::edgedb_query;
use edgedb_errors::Error;
use edgedb_tokio::create_client;
// Creates a module called `simple` with a function called `query` and structs
// for the `Input` and `Output`.
edgedb_query!(
simple,
"select {hello := \"world\", custom := <str>$custom }"
);
#[tokio::main]
async fn main() -> Result<(), Error> {
let client = create_client().await?;
let input = simple::Input::builder().custom("custom").build();
// For queries the following code can be used.
let output = simple::query(&client, &input).await?;
Ok(())
}
The macro above generates the following code:
pub mod simple {
use ::edgedb_codegen::exports as e;
#[doc = r" Execute the desired query."]
#[cfg(feature = "query")]
pub async fn query(
client: &e::edgedb_tokio::Client,
props: &Input,
) -> core::result::Result<Output, e::edgedb_errors::Error> {
client.query_required_single(QUERY, props).await
}
#[doc = r" Compose the query as part of a larger transaction."]
#[cfg(feature = "query")]
pub async fn transaction(
conn: &mut e::edgedb_tokio::Transaction,
props: &Input,
) -> core::result::Result<Output, e::edgedb_errors::Error> {
conn.query_required_single(QUERY, props).await
}
#[derive(Clone, Debug, e :: typed_builder :: TypedBuilder)]
#[cfg_attr(feature = "serde", derive(e::serde::Serialize, e::serde::Deserialize))]
#[cfg_attr(feature = "query", derive(e::edgedb_derive::Queryable))]
pub struct Input {
#[builder(setter(into))]
pub custom: String,
}
impl e::edgedb_protocol::query_arg::QueryArgs for Input {
fn encode(
&self,
encoder: &mut e::edgedb_protocol::query_arg::Encoder,
) -> core::result::Result<(), e::edgedb_errors::Error> {
let map = e::edgedb_protocol::named_args! { "custom" => self . custom . clone () , };
map.encode(encoder)
}
}
#[derive(Clone, Debug, e :: typed_builder :: TypedBuilder)]
#[cfg_attr(feature = "serde", derive(e::serde::Serialize, e::serde::Deserialize))]
#[cfg_attr(feature = "query", derive(e::edgedb_derive::Queryable))]
pub struct Output {
#[builder(setter(into))]
pub hello: String,
#[builder(setter(into))]
pub custom: String,
}
#[doc = r" The original query string provided to the macro. Can be reused in your codebase."]
pub const QUERY: &str = "select { hello := \"world\", custom := <str>$custom }";
}
Define a query file in the queries
directory of your crate called select_user.edgeql
.
# queries/select_user.edgeql
select User {
name,
bio,
slug,
} filter .slug = <str>$slug;
Then use the edgedb_query
macro to import the query.
use edgedb_codegen::edgedb_query;
use edgedb_errors::Error;
use edgedb_tokio::create_client;
// Creates a module called `select_user` with public functions `transaction` and
// `query` as well as structs for the `Input` and `Output`.
edgedb_query!(select_user);
#[tokio::main]
async fn main() -> Result<(), Error> {
let client = create_client().await?;
// Generated code can be run inside a transaction.
let result = client
.transaction(|mut txn| {
async move {
let input = select_user::Input::builder().slug("test").build();
let output = select_user::transaction(&mut txn, &input).await?;
Ok(output)
}
})
.await?;
Ok(())
}
Would it be possible to support something similar to sqlx?
I think it could be really nice to have this feature when it comes to have a great developer experience 🙂
https://github.com/launchbadge/sqlx#sqlx-is-not-an-orm