TL;DR, I’m wondering if it’s possible in postgres to create one resource, then create another resource that references it, all within the same statement. I’d like to do this in order to reduce round-trip times and simplify my backend logic.
I currently have two resources, foo and bar. Bar is a child resource of foo that references it:
CREATE TABLE foos (
id serial PRIMARY KEY,
name VARCHAR ( 50 ) UNIQUE NOT NULL
);
CREATE TABLE bars (
id serial PRIMARY KEY,
name VARCHAR ( 50 ) NOT NULL,
description VARCHAR ( 50 ),
foo_id int NOT NULL,
FOREIGN KEY (foo_id)
REFERENCES foos (id),
UNIQUE (foo_id, name)
);
I currently have the following sql statement to upsert a foo and bar at an endpoint v1/foos/{foo_name}/bars/{bar_name}
:
WITH upsert_foo AS
(
INSERT INTO "foos"
("name")
VALUES
($1)
ON CONFLICT ("name") DO NOTHING
),
upsert_bar AS
(
INSERT INTO "bars"
("name", "description", "foo_id" )
VALUES
($2, $3,
(SELECT "id" FROM "foos" WHERE "name" = $1) )
ON CONFLICT ("name", "foo_id") DO
UPDATE SET
"description" = EXCLUDED."description",
RETURNING *
)
SELECT upsert_bar.*;
When a user upserts a bar, a foo with the name from the URI should be created if it doesn’t already exist, then the bar should be created if it doesn’t exist. Otherwise, the bar should be updated.
However, this statement only works in the update case, when the foo resource already exists. It seems that the new foo isn't showing up in (SELECT "id" FROM "foos" WHERE "name" = $1)
when it's newly created.
Is there a way that I can capture the ID of the foo that was created (or already exists) and use it when I create the bar object?