Search...
ctrl/
Light
Dark
System
Sign in

Writing Gel Documentation

We pride ourselves on having some of the best documentation around, but we want you to help us make it even better. Documentation is a great way to get started contributing to Gel. Improvements to our documentation create a better experience for every developer coming through the door behind you.

Follow our general and style guidelines to make for a smooth contributing exprience, both for us and for you. You may notice that the existing documentation doesn't always follow the guidelines laid out here. They are aspirational, so there are times when we intentionally break with them. Other times, bits of documentation may not be touched for a while and so may not reflect our current guidelines. These are great "low-hanging fruit" opportunities for your contributions!

  • Avoid changes that don't fix an obvious mistake or add clarity. This is subjective, but try to look at your changes with a critical eye. Do they fix errors in the original like misspellings or typos? Do they make existing prose more clear or accessible while maintaining accuracy? If you answered "yes" to either of those questions, this might be a great addition to our docs! If not, consider starting a discussion instead to see if your changes might be the exception to this guideline before submitting.

  • Keep commits and pull requests small. We get it. It's more convenient to throw all your changes into a single pull request or even into a single commit. The problem is that, if some of the changes are good and others don't quite work, having everything in one bucket makes it harder to filter out the great changes from those that need more work.

  • Make spelling and grammar fixes in a separate pull request from any content changes. These changes are quick to check and important to anyone reading the docs. We want to make sure they hit the live documentation as quickly as possible without being bogged down by other changes that require more intensive review.

  • Remove trailing whitespace or whitespace on empty lines.

  • Surround references to parameter named with asterisks. You may be tempted to surround parameter names with double backticks (``param``). We avoid that in favor of *param*, in order to distinguish between parameter references and inline code (which should be surrounded by double backticks).

  • Gel is singular. Choose "Gel is" over "Gel are" and "Gel does" over "Gel do."

  • Use American English spellings. Choose "color" over "colour" and "organize" over "organise."

  • Use the Oxford comma. When delineating a series, place a comma between each item in the series, even the one with the conjunction. Use "eggs, bacon, and juice" rather than "eggs, bacon and juice."

  • Write in the simplest prose that is still accurate and expresses everything you need to convey. You may be tempted to write documentation that sounds like a computer science textbook. Sometimes that's necessary, but in most cases, it isn't. Prioritize accuracy first and accessibility a close second.

  • Be careful using words that have a special meaning in the context of Gel. In casual speech or writing, you might talk about a "set" of something in a generic sense. Using the word this way in Gel documentation might easily be interpreted as a reference to Gel's sets. Avoid this kind of casual usage of key terms.

Most of our documentation (including this guide) lives in the geldata repository in the docs directory.

The geldata repository contains all of its documentation in the docs/ directory. Run make docs to build the documentation in the geldata repo. The repository contains a Makefile for all of Sphinx's necessary build options. The documentation will be built to docs/build.

To run tests, first build Gel locally. Then run edb test -k doc.

Building the docs from this repo will not give you a high-fidelity representation of what users will see on the web site. For that, you may want to do a full documentation build.

A full documentation build requires more setup, but it is the only way to see your documentation exactly as the user will see it. This is not required, but it can be useful to help us review and approve your request more quickly by avoiding mistakes that would be easier to spot when they are fully rendered.

To build, clone our website repository and follow the installation instructions. Then run yarn dev to start a development server which also triggers a build of all the documentation.

The watch task builds documentation changes, but it cannot trigger auto-reload in the browser. You will need to manually reload the browser to see changes made to the documentation.

Our documentation is first built through Sphinx and is written in reStructuredText. If you're unfamiliar with reStructuredText, the official primer is a good place to start. The official cheatsheet serves as a great companion reference while you write. Sphinx also offers their own reStructuredText primer.

Sphinx not only builds the documentation but also extends reStructuredText to allow for a more ergonomic experience when crafting docs.

ReStructuredText is an easy-to-learn markup language built for documentation. Here are the most commonly used elements across our documentation.

ReStructuredText headings are underlined (and sometimes overlined) with various characters. It's flexible about which characters map to which heading levels and will automatically assign heading levels to characters based on the hierarchy of the document.

To make it easier to quickly discern the level of a heading across our documentation, we use a consistent hierarchy across all pages.

  1. = under and over- Used for the top-level heading which is usually the page title.

  2. = under only

  3. -

  4. ^

Example

==========
Page Title
==========

Section
=======

Sub-Section
-----------

Sub-Sub-Section
^^^^^^^^^^^^^^^

If you need additional heading levels, you may use the .. rubric:: directive and pass it your heading by adding the heading text on the same line.

Example

.. rubric:: Yet Another Heading

Text can be italicized by surrounding it with asterisks.

*italicized*

Bold text by surrounding it with double asterisks.

**Bold**

Call out a paragraph as a note or warning using the appropriate directives.

Example

.. note::

    This paragraph is a note.

Rendered

This paragraph is a note.

Example

.. warning::

    This paragraph is a warning.

Rendered

This paragraph is a warning.

You may also add a title to any of these paragraphs by passing it to the directive by placing it on the same line.

Example

.. note:: A Note

    This paragraph is a note.

Rendered

A Note

This paragraph is a note.

If you have documentation that will be reused in multiple contexts, you can write it in a separate .rst file and include that file everywhere it should appear.

.. include:: ../stdlib/constraint_table.rst

We use tables and lists in a few different contexts.

Example

.. list-table::

    * - Arrays
      - ``array<str>``
    * - Tuples (unnamed)
      - ``tuple<str, int64, bool>``
    * - Tuples (named)
      - ``tuple<name: str, age: int64, is_awesome: bool>``
    * - Ranges
      - ``range<float64>``

Rendered

Arrays

array<str>

Tuples (unnamed)

tuple<str, int64, bool>

Tuples (named)

tuple<name: str, age: int64, is_awesome: bool>

Ranges

range<float64>

Example

.. list-table::
    :class: seealso

    * - **See also**
    * - :ref:`Schema > Access policies <ref_datamodel_access_policies>`
    * - :ref:`SDL > Access policies <ref_eql_sdl_access_policies>`

Rendered

The seealso class adds a spacer above the table to push the table away from the main page content.

Example

====================================== =============================
Syntax                                 Inferred type
====================================== =============================
:eql:code:`select 3;`                  :eql:type:`int64`
:eql:code:`select 3.14;`               :eql:type:`float64`
:eql:code:`select 314e-2;`             :eql:type:`float64`
:eql:code:`select 42n;`                :eql:type:`bigint`
:eql:code:`select 42.0n;`              :eql:type:`decimal`
:eql:code:`select 42e+100n;`           :eql:type:`decimal`
====================================== =============================

Rendered

Syntax

Inferred type

select 3;

int64

select 3.14;

float64

select 314e-2;

float64

select 42n;

bigint

select 42.0n;

decimal

select 42e+100n;

decimal

Sphinx requires that every page in the documentation be referenced from a table of contents. Use the .. toctree:: directive to create a table of contents.

Example

.. toctree::
    :maxdepth: 3
    :hidden:

    code
    documentation

Most of our tables of contents use the roles you see in this example to set a maximum depth of 3 and to hide the table of contents. This is not required though if other options make sense in your context. Even though the tables are hidden, their content still gets rendered in the left sidebar navigation.

We generally use relative references in the toctree directive which reference the pages relative to the location of the page that contains the directive. The order of the references in the directive determines their order in the sidebar navigation.

If any document is not included in any toctree, it will cause Sphinx to error on the build unless you add the :orphan: role to the top of the page. We don't want to use this technique for most pages although there are exceptions.

Use these tools to render code in your documentation contribution.

Render inline code by surrounding it with double backticks:

Example

With the help of a ``with`` block, we can add filters, ordering, and
pagination clauses.

Rendered

With the help of a with block, we can add filters, ordering, and pagination clauses.

Marking up inline code with single backticks a la Markdown will throw an error in Sphinx when building the documentation.

.. code-block:: [<language>]

    <code goes here>

Render a block of code. You can optionally provide a language argument. Below are the most common languages used in our docs:

  • bash- Include the prompt and optionally the output. When a user clicks the "copy" button to copy the code, it will copy only the input without the prompt and output.

    Example

    .. code-block:: bash
    
        $ gel configure set listen_addresses 127.0.0.1 ::1

    Rendered

    Copy
    $ 
    gel configure set listen_addresses 127.0.0.1 ::1
  • edgeql- Used for queries.

    Example

    .. code-block:: edgeql
    
        select BlogPost filter .id = <uuid>$blog_id;

    Rendered

    Copy
    select BlogPost filter .id = <uuid>$blog_id;
  • edgeql-repl- An alternative to vanilla edgeql. Include the prompt and optionally the output. When a user clicks the "copy" button to copy the code, it will copy only the input without the prompt and output.

    Example

    .. code-block:: edgeql-repl
    
        db> insert Person { name := <str>$name };
        Parameter <str>$name: Pat
        {default::Person {id: e9009b00-8d4e-11ed-a556-c7b5bdd6cf7a}}

    Rendered

    Copy
    db> 
    insert Person { name := <str>$name };
    Parameter <str>$name: Pat
    {default::Person {id: e9009b00-8d4e-11ed-a556-c7b5bdd6cf7a}}
  • go

  • javascript

  • python

    Example

    .. code-block:: javascript
    
        await client.query("select 'I ❤️ ' ++ <str>$name ++ '!';", {
          name: "rock and roll"
        });

    Rendered

    Copy
    await client.query("select 'I ❤️ ' ++ <str>$name ++ '!';", {
      name: "rock and roll"
    });
  • sdl- Used for defining schema.

    Example

    .. code-block:: sdl
    
        module default {
          type Person {
            required property name -> str { constraint exclusive };
          }
        }

    Rendered

    Copy
    module default {
      type Person {
        required property name -> str { constraint exclusive };
      }
    }
  • <language>-diff- Shows changes in a code block. Each line of code in these blocks must be prefixed by a character: + for an added line, - for a removed line, or an empty space for an unchanged line.

    Example

    .. code-block:: sdl-diff
    
            type Movie {
        -     property title -> str;
        +     required property title -> str;
              multi link actors -> Person;
            }

    Rendered

    Copy
      type Movie {
        property title -> str;
        required property title -> str;
        multi link actors -> Person;
      }
    
  • No language- Formats the text as a code block but without syntax highlighting. Use this for syntaxes that do not offer highlighting or in cases where highlighting is unnecessary.

    Example

    .. code-block::
    
        [
          {"id": "ea7bad4c-35d6-11ec-9519-0361f8abd380"},
          {"id": "6ddbb04a-3c23-11ec-b81f-7b7516f2a868"},
          {"id": "b233ca98-3c23-11ec-b81f-6ba8c4f0084e"},
        ]

    Rendered

    [
      {"id": "ea7bad4c-35d6-11ec-9519-0361f8abd380"},
      {"id": "6ddbb04a-3c23-11ec-b81f-7b7516f2a868"},
      {"id": "b233ca98-3c23-11ec-b81f-6ba8c4f0084e"},
    ]

    Code blocks without a language specified do not have a "copy" button.

.. tabs::

Tabs are used to present code examples in multiple languages. This can be useful when you want to show a query in, for example, both EdgeQL and the TypeScript query builder.

Example

.. tabs::

    .. code-tab:: edgeql

        insert Movie {
          title := 'Doctor Strange 2',
          release_year := 2022
        };

    .. code-tab:: typescript

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

        const result = await query.run(client);

Rendered

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

const result = await query.run(client);

Tools to help document EdgeQL are in the :eql: domain.

To document a function use a .. eql:function:: directive. Include these elements:

  • Specify the full function signature with a fully qualified name on the same line as the directive.

  • Add a description of each parameter using :param $<name>: description:. $<name> must match the the name of the parameter in function's signature. If a parameter is positional rather than named, its number should be used instead (e.g. $1).

  • Add a type for each parameter using :paramtype $<name>: <type>. For example: :paramtype $<name>: int64 declares that the type of the $<name> parameter is int64. If a parameter has more than one valid type, list them separated by "or" like this: :paramtype $<name>: int64 or str.

  • Document the return value of the function with :return: and :returntype:. :return: marks a description of the return value and :returntype: its type.

  • Finish with a few descriptive paragraphs and code samples. The first paragraph must be a single sentence no longer than 79 characters describing the function.

Example

.. eql:function:: std::array_agg(set of any, $a: any) -> array<any>

    :param $1: input set
    :paramtype $1: set of any

    :param $a: description of this param
    :paramtype $a: int64 or str

    :return: array made of input set elements
    :returntype: array<any>

    Return the array made from all of the input set elements.

    The ordering of the input set will be preserved if specified.

You can link to a function's documentation by using the :eql:func: role. For instance:

  • :eql:func:`array_agg`;

  • :eql:func:`std::array_agg`;

These will link to a function using the function's name as you have written in between the backticks followed by parentheses. Here are the above links rendered:

You can customize a link's label with this syntax: :eql:func:`aggregate a set as an array <array_agg>`. Here's the rendered output: aggregate a set as an array

Use the .. eql:operator:: directive to document an operator. On the same line as the directive, provide a string argument of the format <operator-id>: <operator-signature>

Add a :optype <operand-name>: <type> field for each of the operator signature's operands to declare their types.

Example

.. eql:operator:: PLUS: A + B

    :optype A: int64 or str or bytes
    :optype B: any
    :resulttype: any

    Arithmetic addition.

You can link to an operator's documentation by using the :eql:op: role, followed by the operator's ID you specified in your argument to .. eql:operator::. For instance: :eql:op:`plus` which renders as plus. You can customize the link label like this: :eql:op:`+ <plus>`, which renders as +.

Use the :eql-statement: field to sections that describe a statement. Add the :eql-haswith: field if the statement supports a with block.

Select
======

:eql-statement:
:eql-haswith:

``select``--retrieve or compute a set of values.

.. eql:synopsis::

    [ with <with-item> [, ...] ]

    select <expr>

    [ filter <filter-expr> ]

    [ order by <order-expr> [direction] [then ...] ]

    [ offset <offset-expr> ]

    [ limit  <limit-expr> ] ;

After laying out the formal syntax, describe the function of each clause with a synopsis like this:

:eql:synopsis:`filter <filter-expr>`
    The optional ``filter`` clause, where :eql:synopsis:`<filter-expr>`
    is any expression that has a result of type :eql:type:`bool`.
    The condition is evaluated for every element in the set produced by
    the ``select`` clause.  The result of the evaluation of the
    ``filter`` clause is a set of boolean values.  If at least one value
    in this set is ``true``, the input element is included, otherwise
    it is eliminated from the output.

These descriptions can each contain as many paragraphs as needed to adequately describe the clause. Follow the format used in the PostgreSQL documentation. See the PostgreSQL SELECT statement reference page for an example.

Use :eql:stmt:`select` to link to the statement's documentation. When rendered the link looks like this: select. Customize the label with :eql:stmt:`the select statement <select>` which renders as this: the select statement.

To document a type, use the .. eql:type:: directive. Follow the directive with the fully-qualified name of the type on the same line. The block should contain the type's description.

.. eql:type:: std::bytes

    A sequence of bytes.

To link to a type's documentation, use :eql:type:`bytes` which renders as bytes. You may use the fully qualified name in your reference — :eql:type:`std::bytes` — which renders as std::bytes. Both forms reference the same location in the documentation. Link labels can be customized with :eql:type:`the bytes type <bytes>` which renders like this: the bytes type.

Document a keyword using the .. eql:keyword:: directive.

.. eql:keyword:: with

    The ``with`` block in EdgeQL is used to define aliases.

If a keyword is compound use a hyphen between each word.

.. eql:keyword:: set-of

To link to a keyword's documentation, use the :eql:kw: role like this: :eql:kw:`detached` which renders as detached. You can customize the link label like this: :eql:kw:`the "detached" keyword <detached>` which renders as the "detached" keyword.

Use :gelcmd: role to document or refer to CLI commands, use |gelcmd| to render just gel in the text.

Example

Use |gelcmd| to cook yourself a delicious meal. Use :gelcmd:`eat` to
eat it.

Rendered

Use gel to cook yourself a delicious meal. Use gel eat to eat it.

Document a CLI command using the cli:synopsis directive like this:

Example

.. cli:synopsis::

    gel dump [<options>] <path>

Rendered

gel dump [options] path

The synopsis should follow the format used in the PostgreSQL documentation. See the PostgreSQL SELECT statement reference page for an example.

You can then document arguments and options using the :cli:synopsis: role.

Example

:cli:synopsis:`<path>`
    The name of the file to backup the database into.

Rendered

path

The name of the file to backup the database into.

There's a few substitutions and ReST toles that are useful when documenting certain terms and concepts:

ReST markup

Description

|gelcmd| and :gelcmd:`blah`

Renders to $ gel and $ gel blah, with a context tooltip explaining that the CLI command used to be called edgedb.

|geluri| and :geluri:`u:p@h:p/b`

Renders to gel:// and gel://u:p@h:p/b, with a context tooltip explaining that the URI used to be edgedb://.

|Gel| and |Gel's|

Renders to "Gel" and "Gel's", with a context tooltip explaining that the Gel used to be called "EdgeDB".

|branch| and |branches|

Renders to "branch" and "branches", with a context tooltip explaining that the term used to be called "database" in EdgeDB < 5.

|EdgeDB|

Renders to "EdgeDB", with a context tooltip explaining that EdgeDB was renamed to Gel.

|.gel|

Renders to .gel, with a context tooltip explaining that the file extension used to be .esdl.

:dotgel:`foo`

Renders to foo.gel, with a context tooltip explaining that the file extension used to be .esdl.

:gelenv:`BLAH`

Renders to GEL_BLAH, with a context tooltip explaining that this environment variable used to be EDGEDB_BLAH.

|gel.toml|

Renders to gel.toml, with a context tooltip explaining that this file used to be called edgedb.toml.

|gel-server|

Renders to $ gel-server, with a context tooltip explaining that this command used to be called edgedb-server.

|admin|

Renders to admin, with a context tooltip explaining that this username used to be called edgedb.

|main|

Renders to main, with a context tooltip explaining that this branch used to be called edgedb.

Since Gel functionality is mostly consistent across versions, we offer a simple method of versioning documentation using two directives.

Although these are directives included in Sphinx, we have customized them to behave differently. Please read this documentation even if you're already familiar with the Sphinx directives mentioned here.

Content addressing anything new in a given version are marked with the versionadded directive. Provide the applicable version as an argument by placing it just after the directive on the same line.

The directive behaves differently depending on the context.

  • When the directive has content (i.e., an indented paragraphs below the directive), that content will be shown or hidden based on the version switch.

  • When the directive is placed immediately after a section header or inside a description block for a function, type, operator, statement, or keyword, that entire section or block is marked to be shown or hidden based on the version selected.

  • When the directive is placed on the top line of any page before any content or reStructuredText labels (e.g., .. _ref_eql_select:), it applies to the entire page.

Example with Content

.. versionadded:: 7.0

    This is a new feature that was added in Gel 7.0.

Rendered

Added in v7.0

This is a new feature that was added in Gel 7.0.

Change the version in the version selector dropdown to see how the rendered example changes.

Section Example

Source deletion
^^^^^^^^^^^^^^^

.. versionadded:: 7.0

Source deletion policies determine what action should be taken when the
*source* of a given link is deleted. They are declared with the ``on source
delete`` clause.
...

Rendered

See the "Source deletion" section of the "Links" documentation for a rendered section example of .. versionadded:: 2.0.

Description Block Example

.. eql:type:: cal::date_duration

    A type for representing a span of time in days.

Rendered

See cal::date_duration for a rendered description block example of .. versionadded:: 2.0.

Full-Page Example

.. versionadded:: 2.0

.. _ref_datamodel_globals:

=======
Globals
=======
...

Rendered

See the "Globals" documentation page for a full-page example of .. versionadded:: 2.0.

Use the versionchanged directive to mark content related to a change in existing functionality across Gel versions. Provide the applicable version as an argument by placing it just after the directive on the same line.

Example

.. versionchanged:: 8.0

    Starting with the upcoming Gel 8.0, access policy restrictions will
    **not** apply to any access policy expression. This means that when
    reasoning about access policies it is no longer necessary to take other
    policies into account. Instead, all data is visible for the purpose of
    *defining* an access policy.

Rendered

Starting with the upcoming Gel 8.0, access policy restrictions will not apply to any access policy expression. This means that when reasoning about access policies it is no longer necessary to take other policies into account. Instead, all data is visible for the purpose of defining an access policy.

Change the version in the version selector dropdown to see how the rendered example changes.

Embed only videos from the Gel YouTube channel

.. edb:youtube-embed:: OZ_UURzDkow