Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: expand SQL adapter docs #7895

Merged
merged 5 commits into from
Nov 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/reference/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Reference
backend_ha
configuration
http
sql_support
sql_adapter
protocol/index
bindings/index
admin/index
Expand Down
216 changes: 198 additions & 18 deletions docs/reference/sql_support.rst → docs/reference/sql_adapter.rst
Original file line number Diff line number Diff line change
@@ -1,22 +1,31 @@
.. versionadded:: 3.0

.. _ref_sql_support:
.. _ref_sql_adapter:

===========
SQL support
SQL adapter
===========

.. edb:youtube-embed:: 0KdY2MPb2oc

Connecting
==========

EdgeDB supports running read-only SQL queries via the Postgres protocol to
enable connecting EdgeDB to existing BI and analytics solutions. Any
Postgres-compatible client can connect to your EdgeDB database by using the
EdgeDB server supports PostgreSQL connection interface. It implements PostgreSQL
wire protocol as well as SQL query language.

As of EdgeDB 6.0, it also supports a subset of Data Modification Language,
namely INSERT, DELETE and UPDATE statements.

It does not, however, support PostgreSQL Data Definition Language
(e.g. ``CREATE TABLE``). This means that it is not possible to use SQL
connections to EdgeDB to modify its schema. Instead, the schema should be
managed using ESDL (EdgeDB Schema Definition Language) and migration commands.

Any Postgres-compatible client can connect to an EdgeDB database by using the
same port that is used for the EdgeDB protocol and the
:versionreplace:`database;5.0:branch` name, username, and password you already
use for your database.
:versionreplace:`database;5.0:branch` name, username, and password already used
for the database.

.. versionchanged:: _default

Expand Down Expand Up @@ -52,7 +61,7 @@ use for your database.

The insecure DSN returned by the CLI for EdgeDB Cloud instances will not
contain the password. You will need to either :ref:`create a new role and
set the password <ref_sql_support_new_role>`, using those values to connect
set the password <ref_sql_adapter_new_role>`, using those values to connect
to your SQL client, or change the password of the existing role, using that
role name along with the newly created password.

Expand All @@ -76,7 +85,7 @@ use for your database.
``libpq.dll``, click "Properties," and find the version on the "Details"
tab.

.. _ref_sql_support_new_role:
.. _ref_sql_adapter_new_role:

Creating a new role
-------------------
Expand Down Expand Up @@ -177,24 +186,29 @@ Multi properties are in separate tables. ``source`` is the ``id`` of the Movie.

SELECT source, target FROM "Movie.labels";

When types are extended, parent object types' tables will by default contain
all objects of both the type and any types extended by it. The query below will
When using inheritance, parent object types' tables will by default contain
all objects of both the parent type and any child types. The query below will
return all ``common::Content`` objects as well as all ``Movie`` objects.

.. code-block:: sql

SELECT id, title FROM common."Content";

To omit objects of extended types, use ``ONLY``. This query will return
To omit objects of child types, use ``ONLY``. This query will return
``common::Content`` objects but not ``Movie`` objects.

.. code-block:: sql

SELECT id, title FROM ONLY common."Content";

The SQL connector supports read-only statements and will throw errors if the
client attempts ``INSERT``, ``UPDATE``, ``DELETE``, or any DDL command. It
supports all SQL expressions supported by Postgres.
The SQL adapter supports a large majority of SQL language, including:

- ``SELECT`` and all read-only constructs (``WITH``, sub-query, ``JOIN``, ...),
- ``INSERT`` / ``UPDATE`` / ``DELETE``,
- ``COPY ... FROM``,
- ``SET`` / ``RESET`` / ``SHOW``,
- transaction commands,
- ``PREPARE`` / ``EXECUTE`` / ``DEALLOCATE``.

.. code-block:: sql

Expand All @@ -207,8 +221,8 @@ supports all SQL expressions supported by Postgres.
WHERE act.source = m.id
);

EdgeDB accomplishes this by emulating the ``information_schema`` and
``pg_catalog`` views to mimic the catalogs provided by Postgres 13.
The SQL adapter emulates the ``information_schema`` and ``pg_catalog`` views to
mimic the catalogs provided by Postgres 13.

.. note::

Expand Down Expand Up @@ -244,7 +258,7 @@ Tested SQL tools
include `XMIN Replication`_, incremental updates using "a user-defined
monotonically increasing id," and full table updates.
.. [2] dbt models are built and stored in the database as either tables or
views. Because the EdgeDB SQL connector does not allow writing or even
views. Because the EdgeDB SQL adapter does not allow writing or even
creating schemas, view, or tables, any attempt to materialize dbt models
will result in errors. If you want to build the models, we suggest first
transferring your data to a true Postgres instance via pg_dump or Airbyte.
Expand All @@ -254,3 +268,169 @@ Tested SQL tools
https://www.postgresql.org/docs/current/runtime-config-replication.html
.. _XMIN Replication:
https://www.postgresql.org/docs/15/ddl-system-columns.html


ESDL to PostgreSQL
==================

As mentioned, the SQL schema of the database is managed trough EdgeDB Schema
Definition Language (ESDL). Here is a breakdown of how each of the ESDL
construct is mapped to PostgreSQL schema:

- Objects types are mapped into tables.
Each table has columns ``id UUID`` and ``__type__ UUID`` and one column for
each single property or link.

- Single properties are mapped to tables columns.

- Single links are mapped to table columns with suffix ``_id`` and are of type
``UUID``. They contain the ids of the link's target type.

- Multi properties are mapped to tables with two columns:
- ``source UUID``, which contains the id of the property's source object type,
- ``target``, which contains values of the property.

- Multi links are mapped to tables with columns:
- ``source UUID``, which contains the id of the property's source object type,
- ``target UUID``, which contains the ids of the link's target object type,
- one column for each link property, using the same rules as properties on
object types.

- Aliases are not mapped to PostgreSQL schema.

- Globals are mapped to connection settings, prefixed with ``global ``.
For example, a ``global default::username: str`` can be set using
``SET "global default::username" TO 'Tom'``.

- Access policies are applied to object type tables when setting
``apply_access_policies_sql`` is set to ``true``.

- Mutation rewrites and triggers are applied to all DML commands.


DML commands
============

When using ``INSERT``, ``DELETE`` or ``UPDATE`` on any table, mutation rewrites
and triggers are applied. These commands do not have a straight-forward
translation to EdgeQL DML commands, but instead use the following mapping:

- ``INSERT INTO "Foo"`` object table maps to ``insert Foo``,

- ``INSERT INTO "Foo.keywords"`` link/property table maps to an
``update Foo { keywords += ... }``,

- ``DELETE FROM "Foo"`` object table maps to ``delete Foo``,

- ``DELETE FROM "Foo.keywords"`` link property/table maps to
``update Foo { keywords -= ... }``,

- ``UPDATE "Foo"`` object table maps to ``update Foo set { ... }``,

- ``UPDATE "Foo.keywords"`` is not supported.


Connection settings
===================

SQL adapter supports a limited subset of PostgreSQL connection settings.
There are the following additionally connection settings:

- ``allow_user_specified_id`` (default ``false``),
- ``apply_access_policies_sql`` (default ``false``),
- settings prefixed with ``"global "`` can use used to set values of globals.

Note that if ``allow_user_specified_id`` or ``apply_access_policies_sql`` are
unset, they default to configuration set by ``configure current database``
EdgeQL command.


Example: gradual transition from ORMs to EdgeDB
===============================================

When a project is using Object-Relational Mappings (e.g. SQLAlchemy, Django,
Hibernate ORM, TypeORM) and is considering the migration to EdgeDB, it might
want to execute the transition gradually, as opposed to a total rewrite of the
project.

In this case, the project can start the transition by migrating the ORM models
to EdgeDB Schema Definition Language.

For example, such Hibernate ORM model in Java:

.. code-block::

@Entity
class Movie {
@Id
@GeneratedValue(strategy = GenerationType.UUID)
UUID id;

private String title;

@NotNull
private Integer releaseYear;

// ... getters and setters ...
}

... would be translated to the following EdgeDB SDL:

.. code-block:: sdl

type Movie {
title: str;

required releaseYear: int32;
}

A new EdgeDB instance can now be created and migrated to the translated schema.
At this stage, EdgeDB will allow SQL connections to write into the ``"Movie"``
table, just as it would have been created with the following DDL command:

.. code-block:: sql

CREATE TABLE "Movie" (
id UUID PRIMARY KEY DEFAULT (...),
__type__ UUID NOT NULL DEFAULT (...),
title TEXT,
releaseYear INTEGER NOT NULL
);

When translating the old ORM model to EdgeDB SDL, one should aim to make the
SQL schema of EdgeDB match the SQL schema that the ORM expects.

When this match is accomplished, any query that used to work with the old, plain
PostgreSQL, should now also work with the EdgeDB. For example, we can execute
the following query:

.. code-block:: sql

INSERT INTO "Movie" (title, releaseYear)
VALUES ("Madagascar", 2012)
RETURNING id, title, releaseYear;

To complete the migration, the data can be exported from our old database into
an ``.sql`` file, which can be import it into EdgeDB:

.. code-block:: bash

$ pg_dump {your PostgreSQL connection params} \
--data-only --inserts --no-owner --no-privileges \
> dump.sql

$ psql {your EdgeDB connection params} --file dump.sql

Now, the ORM can be pointed to EdgeDB instead of the old PostgreSQL database,
which has been fully replaced.

Arguably, the development of new features with the ORM is now more complex for
the duration of the transition, since the developer has to modify two model
definitions: the ORM and the EdgeDB schema.

But it allows any new models to use EdgeDB schema, EdgeQL and code generators
for the client language of choice. The ORM-based code can now also be gradually
rewritten to use EdgeQL, one model at the time.

For a detailed migration example, see repository
`edgedb/hibernate-example <https://github.com/edgedb/hibernate-example>`_.
2 changes: 1 addition & 1 deletion docs/stdlib/cfg.rst
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,7 @@ Client connections
- EdgeDB binary protocol
* - ``cfg::ConnectionTransport.TCP_PG``
- Postgres protocol for the
:ref:`SQL query mode <ref_sql_support>`
:ref:`SQL query mode <ref_sql_adapter>`
* - ``cfg::ConnectionTransport.HTTP``
- EdgeDB binary protocol
:ref:`tunneled over HTTP <ref_http_tunnelling>`
Expand Down