With Gel 6, we're introducing several exciting features that focus on the developer experience. Read more to learn about some of the improvements we've made to the EdgeQL and our CLI.
EdgeQL
We're constantly working to make developing complex applications with Gel more intuitive and efficient. At the heart of this effort is EdgeQL, our query language designed to be both powerful and approachable. The more expressive your queries and data models can be, the more you can offload to your data layer.
DML in user-defined functions
One of the restrictions of user-defined functions in EdgeQL has been that they could not contain DML statements like insert
, update
, or delete
. With Gel 6.0, this restriction has been lifted! We expect that many people will find the function interface to data mutation a very useful abstraction when writing queries.
function create_admin_user(name: str, email: str) -> AdminUser
using (
insert User {
name := name,
email := email,
role := UserRole.Admin,
}
);
Take a look at the documentation for User-Defined Functions for more details.
Simpler scoping rules
We've simplified the scoping rules for EdgeQL to make them more intuitive, aligning them with what feels natural when using EdgeQL in practice. In the process of our attempts to clean up some of the more obscure corners of the language, we've found that the existing path factoring behavior was a source of confusion and complexity.
By default, new projects will use the new scoping rules by setting the using future simple_scoping
pragma in the generated default.gel
schema file. Existing projects will continue to use the old behavior, but we will now produce warnings when a query is relying on the old path factoring behavior to make it easier to update your queries.
You can read more about the history, rationale, and the details of the new scoping rules in RFC 1027 outlining the changes.
String interpolation
Another simple but impactful quality of life feature added in 6.0 is support for string interpolation in EdgeQL.
with
who := 'world',
greeting := 'Hello',
select '\(greeting), \(who)';
Complex types in more places
Complex types like unions and intersections can now be used inline in more places that expect a type. Here are a few examples:
# Updates and deletes with complex types
update Timestamped[is User | Group]
set {
updated_at := datetime_of_statement()
};
# Complex types in intersections
select Shape[is Circle | Triangle & HasRightAngle];
# Complex types in function arguments
function get_name(x: User | Organization) -> str
using (x.name);
CLI
Powerful queries are only part of the equation. Another real challenge is seamlessly integrating your evolving data model with the rest of your development workflow, including the code generation tools we provide. That's why we've also improved the Gel CLI with new automation features that help keep your data layer in sync with your codebase.
Hooks
There are a number of points in the development workflow where you may have some tasks that need to run at certain points based on state changes in your database schema, or the project instance. Some common examples include:
-
Code generation: When the schema changes, you may need to regenerate your code generation files, such as the TypeScript query builder, or the various generated query files we support across our different language clients.
-
Data fixture loading: When you initialize a new project, you may need to load some data into the database as part of the initialization process.
-
Test or type checking: When your schema changes, or when you switch branches, you may need to re-run tests or type checking to see how the changes affect your code.
and more!
To make it easier to handle these cases, you can now define hooks
in your gel.toml
file to run scripts in response to certain events, such as for schema changes, project initialization, branch switching, and more.
[instance]
server-version = "6.1.0"
[hooks]
schema.update.after = """
npx @gel/generate edgeql-js && npx @gel/generate queries
"""
See the gel.toml configuration file documentation for more details.
A new watch
mode
In version 3.0 we introduced a new watch
command to the CLI to make it easier to iterate on your schema without having to manually create and apply multiple migrations. After living with this feature for a while, we've found that the need to respond to changes in the filesystem to trigger database related side-effects is a more general need than just for schema changes.
While designing the hooks feature detailed above, we realized that the other "half" of the equation for ensuring that schema changes and query changes are kept in sync is to be able to trigger code generation when query files change. We decided that a general purpose solution for this would be a great addition to the CLI, and so we've changed the watch
mode which can now be configured to watch glob patterns and trigger arbitrary commands.
Here's an example of how you can use the new watch
mode to trigger code generation when query files change, making it a perfect complement to the hooks
TypeScript code generation example we showed above.
npx @gel/generate edgeql-js && npx @gel/generate queries """ [[watch]] files = ["**/*.edgeql"] script = "npx @gel/generate queries"
The old behavior of applying migrations in dev-mode is still available by passing the --migrate
flag to the watch
command.