Adds section about multiple insertion/update to api/writing docs [#405]
This commit is contained in:
@@ -71,6 +71,93 @@ returns something like
|
|||||||
[ { "id": 1 }, { "id": 2 } ]
|
[ { "id": 1 }, { "id": 2 } ]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Multiple Tables Insertion or Update
|
||||||
|
|
||||||
|
The cleanest way to insert or update data into multiple tables using only one POST/PATCH request
|
||||||
|
is to create a view that will join all target tables and present a single endpoint.
|
||||||
|
In our example let's assume one users table and one companies table.
|
||||||
|
In this case, we want a signup endpoint to create the first user within a company.
|
||||||
|
And for this endpoint we want to insert with one request both user and company.
|
||||||
|
|
||||||
|
```SQL
|
||||||
|
CREATE TABLE companies (
|
||||||
|
id serial primary key,
|
||||||
|
name text unique
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE users (
|
||||||
|
id serial primary key,
|
||||||
|
name text not null,
|
||||||
|
pass text,
|
||||||
|
company_id integer not null references companies
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
Having both tables created we create a view that joins them to be used
|
||||||
|
as a ```/signup``` endpoint.
|
||||||
|
|
||||||
|
```SQL
|
||||||
|
CREATE VIEW signup AS
|
||||||
|
SELECT
|
||||||
|
c.name AS company_name,
|
||||||
|
u.name AS user_name,
|
||||||
|
u.pass
|
||||||
|
FROM
|
||||||
|
public.users u
|
||||||
|
JOIN public.companies c ON c.id = u.company_id;
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
After the signup view creation, we can issue ```GET``` requests to read data
|
||||||
|
from users and companies, but any atempt to ```POST``` or ```PATCH``` data will fail.
|
||||||
|
PostgreSQL won't allow any data change on views that have a ```JOIN```
|
||||||
|
clause in their ```FROM``` without a proper ```INSTEAD OF``` trigger.
|
||||||
|
So in the example bellow we create a trigger to allow insertion of data in the signup view.
|
||||||
|
The trigger is a simple PL/pgSQL function that first inserts into the companies table and
|
||||||
|
uses the newly create company_id to create its first user.
|
||||||
|
|
||||||
|
|
||||||
|
```SQL
|
||||||
|
CREATE FUNCTION signup()
|
||||||
|
RETURNS trigger
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $$
|
||||||
|
DECLARE
|
||||||
|
vcompany_id int;
|
||||||
|
BEGIN
|
||||||
|
INSERT INTO companies (name) VALUES (new.company_name) RETURNING id INTO vcompany_id;
|
||||||
|
INSERT INTO users (name, pass, company_id) VALUES (new.user_name, new.pass, vcompany_id);
|
||||||
|
RETURN new;
|
||||||
|
END;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
CREATE TRIGGER signup
|
||||||
|
INSTEAD OF INSERT ON signup
|
||||||
|
FOR EACH ROW
|
||||||
|
EXECUTE PROCEDURE signup();
|
||||||
|
```
|
||||||
|
|
||||||
|
After the trigger creation we can issue a normal ```POST``` request to our signup endpoint:
|
||||||
|
|
||||||
|
```HTTP
|
||||||
|
POST /signup
|
||||||
|
{ "company_name": "foo", "user_name": "bar" }
|
||||||
|
```
|
||||||
|
|
||||||
|
For an endpoint such as signup its usually not desirable to have a ```PATCH``` route for updates,
|
||||||
|
and we will skip this example for the sake of brevity. But it would be implemented in a very
|
||||||
|
similar way to our ```POST``` example.
|
||||||
|
|
||||||
|
<div class="admonition note">
|
||||||
|
<p class="admonition-title">Design Consideration</p>
|
||||||
|
|
||||||
|
<p>It's advisable to create a separate trigger for <code>UPDATE</code> and <code>INSERT</code>
|
||||||
|
avoiding conditionals that decide which is the trigger current operation.
|
||||||
|
This makes it easier to change code for (or even disable) one operation without intefering with others while
|
||||||
|
improving readability.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
### Bulk Updates
|
### Bulk Updates
|
||||||
|
|
||||||
* ❌ Cannot be cached or prefetched
|
* ❌ Cannot be cached or prefetched
|
||||||
|
|||||||
Reference in New Issue
Block a user