Adds section about multiple insertion/update to api/writing docs [#405]

This commit is contained in:
Diogo Biazus
2016-01-20 23:10:24 -05:00
parent 03bec64097
commit 5ee44c6c21
+87
View File
@@ -71,6 +71,93 @@ returns something like
[ { "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
* ❌ Cannot be cached or prefetched