-
Notifications
You must be signed in to change notification settings - Fork 25
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in 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: