-
Notifications
You must be signed in to change notification settings - Fork 26
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Compile time checked queries #161
Comments
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 Inline Queriesuse 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 }";
} Query FilesDefine a query file in the # queries/select_user.edgeql
select User {
name,
bio,
slug,
} filter .slug = <str>$slug; Then use the 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
The text was updated successfully, but these errors were encountered: