Light
Dark
System
1.0latest

Query Builder

The EdgeDB query builder provides a code-first way to write fully-typed EdgeQL queries with TypeScript. We recommend it for TypeScript users, or anyone who prefers writing queries with code.

Copy
const query = e.select(e.Movie, ()=>({
  id: true,
  title: true,
  actors: { name: true }
}));

const result = await query.run(client)
// { id: string; title: string; actors: {name: string}[] }[]

Type inference! If you’re using TypeScript, the result type of all queries is automatically inferred for you. For the first time, you don’t need an ORM to write strongly typed queries.

Auto-completion! You can write queries full autocompletion on EdgeQL keywords, standard library functions, and link/property names.

Type checking! In the vast majority of cases, the query builder won’t let you construct invalid queries. This eliminates an entire class of bugs and helps you write valid queries the first time.

If you haven’t already, initialize a project, write your schema, and create/ apply a migration. Follow the Quickstart for a guided walkthrough of this process.

The rest of this walkthrough uses the following simple Movie schema:

Copy
type Movie {
  required property title -> str { constraint exclusive; };
  property release_year -> int64;
  multi link actors -> Person;
}

type Person {
  required property name -> str;
}

Use npx to generate the query builder.

Copy
$ 
npx edgeql-js

This detects whether you’re using JavaScript or TypeScript and generates the appropriate files into the dbschema/edgeql-js directory. For this tutorial, we’ll assume you’re using TypeScript.

The first time you generate the query builder you’ll be prompted to add the generated files to your .gitignore. If you confirm this prompt, we’ll add the the line automatically.

If you’re having trouble with this step, refer to the Generation docs for more information, then return to this tutorial.

Create a TypeScript file called script.ts (the name doesn’t matter) and import the query builder like so:

Copy
// script.ts
import e from "./dbschema/edgeql-js";

The query builder is only used to write queries, not execute them. To execute queries, we still need a client that manages the actual connection to our EdgeDB instance.

Copy
// script.ts
import {createClient} from "edgedb";
import e from "./dbschema/edgeql-js";

const client = createClient();

If you’ve initialized a project, there’s no need to provide connection information to createClient—it will connect to your project-linked instance by default. You can override this by setting the value of the EDGEDB_DSN environment variable; refer to the Connection docs for more information.

Now we have everything we need to write our first query!

Copy
// script.ts
import {createClient} from "edgedb";
import e from "./dbschema/edgeql-js";

const client = createClient();

async function run() {
  // select datetime_current();
  const query = e.select(e.datetime_current());
  const result = await query.run(client);
  console.log(result);
}
run();

We use the e object to construct queries. The goal of the query builder is to provide an API that is as close as possible to EdgeQL itself. So select datetime_current() becomes e.select(e.datetime_current(). This query is then executed with the .run() method which accepts a client as it’s first input.

Run that script with the esbuild-runner like so. It should print the current timestamp (as computed by the database).

Copy
$ 
npx esbuild-runner script.ts
2022-05-10T03:11:27.205Z

Below is a set of examples to get you started with the query builder. It is not intended to be comprehensive, but it should provide a good starting point.

Modify the examples below to fit your schema, paste them into script.ts, and execute them with the npx command from the previous section! Note how the signature of result changes as you modify the query.

Copy
const query = e.insert(e.Movie, {
  title: 'Doctor Strange 2',
  release_year: 2022
});

const result = await query.run(client);
// {id: string}
// by default INSERT only returns
// the id of the new object
Copy
const query = e.select(e.Movie, () => ({
  id: true,
  title: true,
}));

const result = await query.run(client);
// Array<{id: string; title: string}>

To select all properties of an object, use the spread operator with the special * property:

Copy
const query = e.select(e.Movie, () => ({
  ...e.Movie['*']
}));

const result = await query.run(client);
/* Array{
  id: string;
  title: string;
  release_year: number | null;  # optional property
}> */
Copy
const query = e.select(e.Movie, () => ({
  id: true,
  title: true,
  actors: {
    name: true,
  }
}));

const result = await query.run(client);
// Array<{id: string; title: string, actors: Array<{name: string}>}>

The special keys filter, order_by, limit, and offset correspond to equivalent EdgeQL clauses.

Copy
const query = e.select(e.Movie, (movie) => ({
  id: true,
  title: true,
  filter: e.op(movie.release_year, ">", 1999),
  order_by: movie.title,
  limit: 10,
  offset: 10
}));

const result = await query.run(client);
// Array<{id: string; title: number}>

The filter expression above uses e.op function, which is how to use operators like =, >=, ++, and and.

Filter by a property with an exclusive constraint to fetch a particular object.

Copy
const query = e.select(e.Movie, (movie) => ({
  id: true,
  title: true,
  release_year: true,

  // filter .id = '2053a8b4-49b1-437a-84c8-e1b0291ccd9f'
  filter: e.op(movie.id, '=', '2053a8b4-49b1-437a-84c8-e1b0291ccd9f'),
}));

const result = await query.run(client);
// {id: string; title: string; release_year: number | null}

Note that result is now a single object, not a list of objects. The query builder detects when you are filtering on a property with an exclusive constraint.

Copy
const query = e.update(e.Movie, (movie) => ({
  filter: e.op(movie.title, '=', 'Doctor Strange 2'),
  set: {
    title: 'Doctor Strange in the Multiverse of Madness',
  },
}));

const result = await query.run(client);
Copy
const query = e.delete(e.Movie, (movie) => ({
  filter: e.op(movie.title, 'ilike', "the avengers%"),
}));

const result = await query.run(client);
// Array<{id: string}>
Copy
const query = e.params({
  title: e.str,
  release_year: e.int64,
},
(params) => {
  return e.insert(e.Movie, {
    title: params.title,
    release_year: params.release_year,
  }))
};

const result = await query.run(client, {
  title: 'Thor: Love and Thunder',
  release_year: 2022,
});
// {id: string}

Continue reading for more complete documentation on how to express any EdgeQL query with the query builder.

Light
Dark
System