Skip to content

Commit

Permalink
Add typing to withConfig, document config methods, add portable sha…
Browse files Browse the repository at this point in the history
…pes (#441)

* Implement e.shape

* Document config

* Fix docs formatting

* Remove references to driver

* Update connection link

* Fix lint

* Update defaults

* Document portable shapes

* Fix typing on SimpleOptions

* Add simple test for config methods

* Fix v1 test

* Remove test

* Fix test

* Use duration.from
  • Loading branch information
colinhacks authored Sep 7, 2022
1 parent eb5a985 commit 1e5ad72
Show file tree
Hide file tree
Showing 14 changed files with 266 additions and 114 deletions.
194 changes: 124 additions & 70 deletions docs/driver.rst
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
.. _edgedb-js-driver:


Driver
======
Clients
=======

The driver implements the core functionality required to establish a
The ``Client`` class implements the basic functionality required to establish a
connection to your database and execute queries.

.. _edgedb-js-create-client:
Expand Down Expand Up @@ -40,13 +40,62 @@ If you're using TypeScript or have ES modules enabled, you can use
const client = edgedb.createClient();
Configuring the connection
--------------------------
Connections
^^^^^^^^^^^

Notice we didn't pass any arguments into ``createClient``. That's intentional.

**In development**, we recommend using ``edgedb project init`` to create an
instance and link it to your project directory. As long as you're inside this
directory, ``createClient()`` with auto-detect the project and connect to the
associated instance automatically.

**In production** you should use environment variables to provide connection
information to ``createClient``. See the :ref:`Connection parameters
<ref_reference_connection>` docs for details.

Configuring clients
^^^^^^^^^^^^^^^^^^^

Clients can be configured using a set of *immutable* methods that start with
``with``.

.. note::

These methods return a *new Client instance* that *shares a connection pool*
with the original client! This is important. Each call to ``createClient``
instantiates a new connection pool.

Notice we didn't pass any arguments into ``createClient``. That's intentional;
we recommend using EdgeDB projects or environment variables to configure your
database connections. See the :ref:`Client Library Connection
<edgedb_client_connection>` docs for details on configuring connections.
The code example below demonstrates all available configuration settings. The
value specified below is the *default value* for that setting.

.. code-block:: typescript
import {createClient, Duration, IsolationLevel} from "edgedb";
const baseClient = createClient();
const client = baseClient
.withConfig({
// 10 seconds
session_idle_transaction_timeout: Duration.from({seconds: 10}),
// 0 seconds === no timeout
query_execution_timeout: Duration.from({seconds: 0}),
allow_bare_ddl: "NeverAllow",
allow_user_specified_id: false,
apply_access_policies: true,
})
.withRetryOptions({
attempts: 3,
backoff: (attemptNo: number) => {
// exponential backoff
return 2 ** attemptNo * 100 + Math.random() * 100;
},
})
.withTransactionOptions({
isolation: IsolationLevel.Serializable, // only supported value
deferrable: false,
readonly: false,
});
Running queries
---------------
Expand Down Expand Up @@ -74,11 +123,74 @@ In TypeScript, you can supply a type hint to receive a strongly typed result.
const result = await client.query<number>(`select 2 + 2;`);
// number[]
``.query`` method
^^^^^^^^^^^^^^^^^

The ``.query`` method always returns an array of results. It places no
constraints on cardinality.

.. code-block:: js
await client.query(`select 2 + 2;`); // [4]
await client.query(`select [1, 2, 3];`); // [[1, 2, 3]]
await client.query(`select <int64>{};`); // []
await client.query(`select {1, 2, 3};`); // [1, 2, 3]
``.querySingle`` method
^^^^^^^^^^^^^^^^^^^^^^^

If you know your query will only return a single element, you can tell EdgeDB
to expect a *singleton result* by using the ``.querySingle`` method. This is
intended for queries that return *zero or one* elements. If the query returns
a set with more than one elements, the ``Client`` will throw a runtime error.

.. note::

Note that if you're selecting an array or tuple, the returned value may
still be an array.

.. code-block:: js
await client.querySingle(`select 2 + 2;`); // [4]
await client.querySingle(`select [1, 2, 3];`); // [1, 2, 3]
await client.querySingle(`select <int64>{};`); // null
await client.querySingle(`select {1, 2, 3};`); // Error
``.queryRequiredSingle`` method
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Use ``queryRequiredSingle`` for queries that return *exactly one* element. If
the query returns an empty set or a set with multiple elements, the ``Client``
will throw a runtime error.

.. code-block:: js
await client.queryRequiredSingle(`select 2 + 2;`); // 4
await client.queryRequiredSingle(`select [1, 2, 3];`); // [1, 2, 3]
await client.queryRequiredSingle(`select <int64>{};`); // Error
await client.queryRequiredSingle(`select {1, 2, 3};`); // Error
TypeScript
^^^^^^^^^^

The TypeScript signatures of these methods reflects their behavior.

.. code-block:: typescript
await client.query<number>(`select 2 + 2;`);
// number[]
await client.querySingle<number>(`select 2 + 2;`);
// number | null
await client.queryRequiredSingle<number>(`select 2 + 2;`);
// number
Type conversion
---------------

The driver converts EdgeDB types into a corresponding JavaScript data
The client converts EdgeDB types into a corresponding JavaScript data
structure. Some EdgeDB types like ``duration`` don't have a corresponding type
in the JavaScript type system, so we've implemented classes like
:js:class:`Duration` to represent them.
Expand Down Expand Up @@ -135,7 +247,7 @@ in the JavaScript type system, so we've implemented classes like
- :js:class:`Range`


To learn more about the driver's built-in type classes, refer to the reference
To learn more about the client's built-in type classes, refer to the reference
documentation.

- :js:class:`Duration`
Expand All @@ -155,64 +267,6 @@ documentation.
.. Everything below this point isn't necessary/applicable for query builder users. Continue to the :ref:`Query Builder <edgedb-js-qb>` docs.
Enforcing cardinality
---------------------

There are additional methods for running queries that have an *expected
cardinality*. This is a useful way to tell the driver how many elements you
expect the query to return.

``.query`` method
^^^^^^^^^^^^^^^^^

The ``query`` method places no constraints on cardinality. It returns an
array, no matter what.

.. code-block:: js
await client.query(`select 2 + 2;`); // [4]
await client.query(`select <int64>{};`); // []
await client.query(`select {1, 2, 3};`); // [1, 2, 3]
``.querySingle`` method
^^^^^^^^^^^^^^^^^^^^^^^

Use ``querySingle`` if you expect your query to return *zero or one* elements.
Unlike ``query``, it either returns a single element or ``null``. Note that if
you're selecting an array, tuple, or set, the returned 'single' element will be
an array.

.. code-block:: js
await client.querySingle(`select 2 + 2;`); // [4]
await client.querySingle(`select <int64>{};`); // null
await client.querySingle(`select {1, 2, 3};`); // Error
``.queryRequiredSingle`` method
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Use ``queryRequiredSingle`` for queries that return *exactly one* element.

.. code-block:: js
await client.queryRequiredSingle(`select 2 + 2;`); // 4
await client.queryRequiredSingle(`select <int64>{};`); // Error
await client.queryRequiredSingle(`select {1, 2, 3};`); // Error
The TypeScript signatures of these methods reflects their behavior.

.. code-block:: typescript
await client.query<number>(`select 2 + 2;`);
// number[]
await client.querySingle<number>(`select 2 + 2;`);
// number | null
await client.queryRequiredSingle<number>(`select 2 + 2;`);
// number
JSON results
------------

Expand Down Expand Up @@ -406,4 +460,4 @@ If you're a TypeScript user and want autocompletion and type inference, head
over to the :ref:`Query Builder docs <edgedb-js-qb>`. If you're using plain
JavaScript that likes writing queries with composable code-first syntax, you
should check out the query builder too! If you're content writing queries as
strings, the vanilla driver API will meet your needs.
strings, the vanilla Client API will meet your needs.
1 change: 1 addition & 0 deletions docs/generation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ builder API. Avoid using the following names in your schema.
- ``index``
- ``slice``
- ``destructure``
- ``shape``


Generated interfaces
Expand Down
14 changes: 7 additions & 7 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ or Deno backend.

There are two components of this library:

- Use the :ref:`Driver API <edgedb-js-intro-driver>` to establish a connection
- Use the :ref:`Client API <edgedb-js-intro-driver>` to establish a connection
to your database and execute EdgeQL queries (written as strings).
- Use the :ref:`Query Builder API <edgedb-js-intro-qb>` to write queries in a
code-first, typesafe way. Recommended for TypeScript users.
Expand Down Expand Up @@ -73,12 +73,12 @@ Deno users: Import from ``deno.land/x/edgedb``:
.. _edgedb-js-intro-driver:

The driver
==========
The ``Client`` API
==================

The driver implements the core functionality required to establish a
The ``Client`` class implements the core functionality required to establish a
connection to your database and execute queries. If you prefer writing queries
as strings, the driver API is all you need.
as strings, the Client API is all you need.

.. code-block:: javascript
Expand All @@ -94,7 +94,7 @@ as strings, the driver API is all you need.
run();
If you're not using TypeScript, you can skip straight to :ref:`the Driver docs
If you're not using TypeScript, you can skip straight to :ref:`the Client docs
<edgedb-js-driver>`.


Expand Down Expand Up @@ -141,7 +141,7 @@ users and JavaScript users who prefer writing queries as code.
How do I get started?
---------------------

We recommend reading the :ref:`Driver docs <edgedb-js-driver>` first. If you
We recommend reading the :ref:`Client docs <edgedb-js-driver>` first. If you
are happy writing your EdgeQL as plain strings, then that's all you need! If
you're a TypeScript user, or simply prefer writing queries in a code-first
way, continue on to the :ref:`Query builder <edgedb-js-generation>` docs.
4 changes: 2 additions & 2 deletions docs/literals.rst
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,9 @@ type system: ``duration``, ``cal::relative_duration``, ``cal::date_duration``,
``cal::local_date``, ``cal::local_time``, and ``cal::local_datetime``,

To resolve this, each of these datatypes can be represented with an instance
of a corresponding class, as defined in ``edgedb`` module. The driver uses
of a corresponding class, as defined in ``edgedb`` module. Clients use
these classes to represent these values in query results; they are documented
on the :ref:`Driver <edgedb-js-datatypes>` page.
on the :ref:`Client API <edgedb-js-datatypes>` docs.

.. list-table::

Expand Down
2 changes: 1 addition & 1 deletion docs/parameters.rst
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ A type can be made optional with the ``e.optional`` function.
// works with duration
const result = await query.run(client, {
title: 'The Eternals',
duration: new Duration(0, 2, 3)
duration: Duration.from({hours: 2, minutes: 3})
});
// or without duration
Expand Down
4 changes: 2 additions & 2 deletions docs/querybuilder.rst
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,8 @@ Create a client

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. See the :ref:`Driver <edgedb-js-driver>` docs for full
details.
to our EdgeDB instance. See the :ref:`Client API <edgedb-js-driver>` docs for
full details.

.. code-block:: typescript-diff
Expand Down
2 changes: 1 addition & 1 deletion docs/reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -473,7 +473,7 @@ Client
Type conversion
===============

The driver automatically converts EdgeDB types to the corresponding JavaScript
The client automatically converts EdgeDB types to the corresponding JavaScript
types and vice versa.

The table below shows the correspondence between EdgeDB and JavaScript types.
Expand Down
Loading

0 comments on commit 1e5ad72

Please sign in to comment.