Light
Dark
System
v3latest
v3latest
v2
v1

Queries Generator

The queries generator scans your project for *.edgeql files and generates functions that allow you to execute these queries in a typesafe way.

To get started, install the following packages.

If you’re using Deno, you can skip this step.

Install the edgedb package.

Copy
$ 
npm install edgedb       # npm users
Copy
$ 
yarn add edgedb          # yarn users

Then install @edgedb/generate as a dev dependency.

Copy
$ 
npm install @edgedb/generate --save-dev      # npm users
Copy
$ 
yarn add @edgedb/generate --dev              # yarn users

Consider the following file tree.

Copy
.
├── package.json
├── edgedb.toml
├── index.ts
├── dbschema
└── queries
    └── getUser.edgeql

The following command will run the queries generator.

Node.js
Deno
Copy
$ 
npx @edgedb/generate queries
Copy
$ 
deno run --allow-all --unstable https://deno.land/x/edgedb/generate.ts queries

The generator will detect the project root by looking for an edgedb.toml, then scan the directory for *.edgeql files. In this case, there’s only one: queries/getUser.edgeql.

Copy
select User { name, email } filter .id = <uuid>$user_id;

For each .edgeql file, the generator will read the contents and send the query to the database, which returns type information about its parameters and return type. The generator uses this information to create a new file getUser.query.ts alongside the original getUser.edgeql file.

Copy
.
├── package.json
├── edgedb.toml
├── index.ts
├── dbschema
└── queries
    └── getUser.edgeql
    └── getUser.query.ts    <-- generated file

This example assumes you are using TypeScript. The generator tries to auto-detect the language you’re using; you can also specify the language with the --target flag. See the Targets section for more information.

The generated file will look something like this:

Copy
import type { Client } from "edgedb";

export type GetUserArgs = {
  user_id: string;
};

export type GetUserReturns = {
  name: string;
  email: string;
} | null;

export async function getUser(
  client: Client,
  args: GetUserArgs
): Promise<GetUserReturns> {
  return await client.querySingle(
    `select User { name, email } filter .id = <uuid>$user_id;`,
    args
  );
}

Some things to note:

  • The first argument is a Client instance. This is the same client you would use to execute a query manually. You can use the same client for both manual and generated queries.

  • The second argument is a parameter object. The keys of this object are the names of the parameters in the query.

  • The code uses the querySingle method, since the query is only expected to return a single result.

  • We export the type of the parameter object and the return value unwrapped from the promise.

We can now use this function in our code.

Copy
import { getUser } from "./queries/getUser.query";
import {
  createClient,
  type GetUserArgs,
  type GetUserReturns,
} from "edgedb";

const client = await createClient();

const newUser: GetUserArgs = {
  user_id: "00000000-0000-0000-0000-000000000000"
};

const user = await getUser(client, newUser); // GetUserReturns

if (user) {
  user.name; // string
  user.email; // string
}

Pass the --file flag to generate a single file that contains functions for all detected .edgeql files. This lets you import all your queries from a single file.

Let’s say we start with the following file tree.

Copy
.
├── package.json
├── edgedb.toml
├── index.ts
├── dbschema
└── queries
    └── getUser.edgeql
    └── getMovies.edgeql

The following command will run the generator in --file mode.

Copy
$ 
npx @edgedb/generate queries --file

A single file will be generated that exports two functions, getUser and getMovies. By default this file is generated into the dbschema directory.

Copy
.
├── package.json
├── edgedb.toml
├── index.ts
├── dbschema
│   └── queries.ts  <-- generated file
└── queries
    └── getUser.edgeql
    └── getMovies.edgeql

We can now use these functions in our code.

Copy
import * as queries from "./dbschema/queries";
import {createClient} from "edgedb";

const client = await createClient();

const movies = await queries.getMovies(client);
const user = await queries.getUser(client, {
  user_id: "00000000-0000-0000-0000-000000000000"
});

To override the file path and name, you can optionally pass a value to the --file flag. Note that you should exclude the extension.

Copy
$ 
npx @edgedb/generate queries --file path/to/myqueries

The file extension is determined by the generator --target and will be automatically appended to the provided path. Extensionless “absolute” paths will work; relative paths will be resolved relative to the current working directory.

This will result in the following file tree.

Copy
.
├── package.json
├── edgedb.toml
├── path
│   └── to
│       └── myqueries.ts
├── queries
│   └── getUser.edgeql
│   └── getMovies.edgeql
└── index.ts

To exclude the generated files, add the following lines to your .gitignore file.

Copy
**/*.edgeql.ts
dbschema/queries.*
Light
Dark
System

We use ChatGPT with additional context from our documentation to answer your questions. Not all answers will be accurate. Please join our Discord if you need more help.