diff --git a/_static/orders.png b/_static/orders.png new file mode 100644 index 000000000..db709c873 Binary files /dev/null and b/_static/orders.png differ diff --git a/api.rst b/api.rst index 06082c2f7..2910f7e3a 100644 --- a/api.rst +++ b/api.rst @@ -746,6 +746,110 @@ Response: } } +.. _embed_disamb: + +Embedding Disambiguation +------------------------ + +For doing resource embedding, PostgREST infers the relationship between two tables based on a foreign key between them. +However, in cases where there's more than one foreign key between two tables, it's not possible to infer the relationship unambiguosly +by just specifying the tables names. + +Target Disambiguation +~~~~~~~~~~~~~~~~~~~~~ + +For example, suppose you have the following ``orders`` and ``addresses`` tables: + +.. image:: _static/orders.png + +And you try to embed ``orders`` with ``addresses`` (this is the **target**): + +.. code-block:: http + + GET /orders?select=*,addresses(*) HTTP/1.1 + +Since the ``orders`` table has two foreign keys to the ``addresses`` table — an order has a billing address and a shipping address — +the request is ambiguous and PostgREST will respond with an error: + +.. code-block:: http + + HTTP/1.1 300 Multiple Choices + +If this happens, you need to disambiguate the request by adding precision to the **target**. +Instead of the **table name**, you can specify the **foreign key constraint name** or the **column name** that is part of the foreign key. + +Let's try first with the **foreign key constraint name**. To make it clearer we can name it: + +.. code-block:: postgresql + + ALTER TABLE orders + ADD CONSTRAINT billing_address foreign key (billing_address_id) references addresses(id), + ADD CONSTRAINT shipping_address foreign key (shipping_address_id) references addresses(id); + + -- Or if the constraints names were already generated by PostgreSQL we can rename them + -- ALTER TABLE orders + -- RENAME CONSTRAINT orders_billing_address_id_fkey TO billing_address, + -- RENAME CONSTRAINT orders_shipping_address_id_fkey TO shipping_address; + +Now we can unambiguously embed the billing address by specifying the ``billing_address`` foreign key constraint as the **target**. + +.. code-block:: http + + GET /orders?select=name,billing_address(name) HTTP/1.1 + + [ + { + "name": "Personal Water Filter", + "billing_address": { + "name": "32 Glenlake Dr.Dearborn, MI 48124" + } + } + ] + +Alternatively, you can specify the **column name** of the foreign key constraint as the **target**. This can be aliased to make +the result more clear. + +.. code-block:: http + + GET /orders?select=name,billing_address:billing_address_id(name) HTTP/1.1 + + [ + { + "name": "Personal Water Filter", + "billing_address": { + "name": "32 Glenlake Dr.Dearborn, MI 48124" + } + } + ] + +Hint Disambiguation +~~~~~~~~~~~~~~~~~~~ + +If specifying the **target** is not enough for unambiguous embedding, you can add a **hint**. For example, let's assume we create +two VIEWs of ``addresses``: ``central_addresses`` and ``eastern_addresses``. + +Since PostgREST supports :ref:`embedding_views` by detecting **source foreign keys** in the views, embedding with the foreign key +as the **target** will not be enough for an unambiguous embed: + +.. code-block:: http + + GET /orders?select=*,billing_address(*) HTTP/1.1 + + HTTP/1.1 300 Multiple Choices + +For solving this case, in addition to the **target**, we can add a **hint**. +Here we specify ``central_addresses`` as the **target** and the ``billing_address`` foreign key as the **hint**: + +.. code-block:: http + + GET /orders?select=*,central_addresses!billing_address(*) HTTP/1.1 + + HTTP/1.1 200 OK + + [ ... ] + +Similarly to the **target**, the **hint** can be a **table name**, **foreign key constraint name** or **column name**. + .. _custom_queries: Custom Queries diff --git a/erd/README.md b/erd/README.md new file mode 100644 index 000000000..d71e8e263 --- /dev/null +++ b/erd/README.md @@ -0,0 +1,7 @@ +This files were created with https://github.com/BurntSushi/erd/. + +You can go download erd from https://github.com/BurntSushi/erd/releases and then do: + +```bash +./erd_static-x86-64 -i erd/film.er -o _static/film.png +``` diff --git a/erd/orders.er b/erd/orders.er new file mode 100644 index 000000000..bdd93de2e --- /dev/null +++ b/erd/orders.er @@ -0,0 +1,15 @@ +[Addresses] +*id +name +city +state +postal_code + +[Orders] +*id +name ++billing_address_id ++shipping_address_id + +Orders *--1 Addresses +Orders *--1 Addresses