edgedb / edgedb-rust

The official Rust binding for EdgeDB
https://edgedb.com
Apache License 2.0
208 stars 26 forks source link

Deduplicate structure from queries #258

Open tailhook opened 1 year ago

tailhook commented 1 year ago

The idea is that when one does a query via Rust (or perhaps any other type-safe language), they describe shape twice:

struct User {
  first_name: String,
  last_name: String,
  articles: Vec<Article>,
}
struct Article {
  title: String,
  date: SystemTime,
}

let user: User = cli.query("
  SELECT User {
    first_name,
    last_name,
    articles: {
      title,
      date,
    },
  }
  FILTER .id = <uuid>$0
", (user_id,) 

Since we know the shape of the query from defined structure we can simplify query to:

let user: User = cli.auto_query("SELECT User FILTER .id = <uuid>$0", (user_id,));

Where internally it's transformed into the following query:

WITH inner := (SELECT User FILTER .id = <uuid>$0)
SELECT inner { first_name, last_name, articles: {title, date}}

Since EdgeQL is easily composable, it will work fine if you need a filter on an articles, or a computable:

cli.auto_query("
  SELECT User {
    first_name := get_first_name(.full_name),
    articles := (SELECT .articles FILTER .visible LIMIT 10),
  }
  FILTER .id = <uuid>$0
", (user_id,));

Note:

  1. first_name would better be in-schema computable
  2. Shape on articles still auto-generated (by having it in outer query, we don't need to parse EdgeQL text and inject anything inside).

This might also be integrated to compile-time checks, described in edgedb/edgedb#4276 so that shape and types of values are checked at compile time rather than at run time.