Generate fully typed rust code from your gel schema and inline queries with
gelx.
Installation
To install the gelx crate, you can use the following commands.
# Optional dependency when using the `query` feature
Or, add the following directly to your Cargo.toml file.
[]
= "0.4"
# Optional dependencies
= "0.8" # needed when using the `query` feature
Make sure you've installed the gel CLI for your platform.
Once installed you should be able to run the following command to verify your installation.
And then initialize in the project directory.
gelx!
Working with the default gel crate requires manually writing untyped queries and creating the rust structs and enums for both the input and output into these queries with. The correctness of your code can only be checked at runtime increasing the risk of bugs and errors.
gelx! transforms your queries into rust structs, types and functions, providing safety during development of your project.
Inline Queries
use Error;
use create_client;
use gelx;
// Creates a module called `example` with a function called `query` and structs
// for the `Input` and `Output`.
gelx!;
async
The macro above generates the following code in the background:
Query Files
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 gelx macro to import the query.
use Error;
use create_client;
use gelx;
// Creates a module called `select_user` with public functions `transaction` and
// `query` as well as structs for the `Input` and `Output`.
gelx!;
async
gelx_build
By default, macros can't read from the Cargo.toml file of the consuming crate. The gelx_build crate provides a way to read the configuration from the Cargo.toml file using the build.rs script.
You can read the gelx_build readme for more information.
CLI
The gelx_cli crate exposes a binary called gelx transforms the typed code into *.rs files rather than inline queries.
It should be run from the crate directory and will read from the configuration specified in the next section.
Sometimes you will need to check that the generated code matches the current database schema and queries generated by gel. This is useful for CI pipelines to ensure the generated code is up to date.
If there are changes that haven't been accounted for, the check will fail with a diff and you should regenerate the code.
More information can be found in the gelx_cli readme.
Globals
The gelx_cli will generate a Globals struct for your project. It iterates over all the schema::Global types defined in your .gel schema to generate a Globals struct. This struct can be used to create a gel client.
For example if you have the following globals in your schema.
module default {
global current_user_id: uuid;
global current_user := (
select User filter .id = global current_user_id
);
global alternative: str;
}
The generated Globals struct will look like the following. Notice how the current_user global, which is an alias type, is ignored. This is because it can't be set externally and is automatically derived from the current_user_id global (it only exists within the database).
// src/db/mod.rs
use exports as __g;
The above code can be used to create a gel client with the globals.
use crateGlobals;
use Uuid;
// Using the builder pattern
let client = builder
.current_user_id
.alternative
.build
.into_client
.await?;
// Using the `to_client` method
let client = Globals .into_client.await?;
Configuration
The following configuration options are supported. The provided defaults will be used if a value is not specified.
[]
# The path to the directory containing the queries.
= "./queries"
# The features to enable and their aliases. By default all features are enabled.
# To disable a feature set its value to `false`. To alias a feature behind a
# feature flag use the following format `feature = { query = "ssr" }`. This will
# enable the query feature only when the `ssr` feature is enabled.
#
# The available features are:
#
# - `query` - When enabled you must include `gel-protocol` as a dependency.
# - `serde` - Enable `serde` for the generated code.
= { = true, = true }
# The location of the generated code when using the `gelx` CLI.
= "./src/db"
# The name of the arguments input struct. Will be transformed to PascalCase.
= "Input"
# The name of the exported output struct for generated queries. Will be transformed to PascalCase.
= "Output"
# The name of the query function exported.
= "query"
# The name of the transaction function exported.
= "transaction"
# The name of the query constant exported.
= "QUERY"
# The alias used for the `gelx::exports` module.
= "__g"
# The macros which are always derived for the generated structs.
= [
"::std::fmt::Debug",
"::core::clone::Clone",
]
# The macros which are always derived for the generated enums.
= [
"::std::fmt::Debug",
"::core::clone::Clone",
"::core::marker::Copy",
]
# The relative path to the `gel` config file. This is optional, and if not
# provided, the `gel` config will be read from the environment variables.
= "./gel.toml"
# The name of the `gel` instance to use. This is optional, and if not provided,
# the environment variable `$GEL_INSTANCE` will be used.
= "$GEL_INSTANCE"
# The name of the `gel` branch to use. This is optional, and if not provided,
# the environment variable `$GEL_BRANCH` will be used.
= "$GEL_BRANCH"
Geometry and Geography
The gelx crate provides wrapper types for the Geometry and Geography types from the geo crate.
# queries/insert_location.edgeql
with NewLocation := (insert Location {
point := <ext::postgis::geometry>$point,
area := <ext::postgis::geography>$area,
})
select NewLocation {
point,
area,
};
use Error;
use Geography;
use Geometry;
use create_client;
use gelx;
use point;
use polygon;
// Creates a module called `insert_location` with public functions `transaction`
// and `query` as well as structs for the `Input` and `Output`.
gelx!;
async
Missing Types
The following types are not currently supported:
MultiRange- The CLI/macro will panic if a multirange is used.
MultiRange
These are not currently exported by gel-protocol and should be added in a PR to the gel-protocol crate if they are still supported in the new protocol.
Crate Features
default— The default feature iswith_all.with_bigint— Include thenum-bigintdependency.with_bigdecimal— Use thebigdecimalcrate.with_chrono— Use thechronocrate for all dates.with_geo— Use thegeocrate for all geometry and geography types.with_all(enabled by default) — Include all additional types. This is included by default. Usedefault-features = falseto disable.builder— Use thetyped-buildercrate to generate the builders for the generatedInputstructs.query— Turn on thequeryandtransactionmethods and anything that relies ongel-tokio. The reason to separate this feature is to enable usage of this macro in browser environments wheregel-tokiois not feasible.serde— Enableserdefor the generated code.strum- Use thestrumcrate for deriving strings from the created enums.
Recommended Setup
Create a gel.toml in the root of your project with the following configuration. The following configuration will work for a single crate project.
[]
= "6.7"
[]
= "dbschema"
[]
= "gelx generate"
= "gelx generate"
= "gelx generate"
[[]]
= ["dbschema/*.gel"]
= "gelx generate"
[[]]
= ["queries/*.edgeql"]
= "gelx generate"
By default this will generate the code into the src/db directory. You can change this by setting the output_path in the configuration.
Contributing
devenv is used to provide a reproducible development environment for this project. Follow the getting started instructions.
To automatically load the environment you should install direnv and then run direnv allow ..
You now have a shell with all the dependencies installed and project-specific commands available.
Run the following commands to install all the required dependencies.
This installs all the cargo binaries locally so you don't need to worry about polluting your global namespace.
At this point you must setup the gel instance.
The above command will setup the local database and install the postgis extension.
Now you can make your changes and run tests.
Available Commands
You can view all the available scripts, packages, tasks and environment variables by running devenv info.
build:all: Build all crates with all features activated.build:docs: Build documentation site.coverage:all: Test all files and generate a coverage report for upload to codecov.db:destroy: Destroy the local database.db:reset: Reset the local database.db:setup: Setup the local database.db:up: Watch changes to the local database.fix:all: Fix all fixable lint issues.fix:clippy: Fix fixable lint issues raised by rust clippy.fix:format: Fix formatting for entire project.fix:gelx: Fix fixable lint issues raised by gelx.install:all: Install all dependencies.install:cargo:bin: Install cargo binaries locally.lint:all: Lint all project files.lint:clippy: Check rust clippy lints.lint:format: Check all formatting is correct.lint:gelx: Check gelx is formatted correctly.test:all: Test all project files.update:deps: Update all project dependencies.
Upgrading devenv
If you have an outdated version of devenv, you can update it by running the following commands. If you know of an easier way, please create a PR to update these docs.
Editor Setup
To setup recommended configuration for your favorite editor run the corresponding command.
License
Unlicense, see the license file.