Skip to content

Convert network configuration transactions to CTEs in diesel #5277

@internet-diglett

Description

@internet-diglett

We have a lot of "has many" relationships in our networking-related Nexus db schema. For creating these records
in a single, idempotent operation, I would like to be able to perform a query like this, or an equivalent query that accomplishes the same:

WITH

-- find the id of the desired parent record if it exists
-- if it doesn't exist, generate a new id to be used in a subsequent creation query
NewOrExisting AS (
    SELECT id
    FROM omicron.public.address_lot
    WHERE (name, kind) = ($1, $2)
    UNION ALL
    SELECT gen_random_uuid()
    WHERE NOT EXISTS (
        SELECT 1
        FROM omicron.public.address_lot
        WHERE (name, kind) = ($1, $2)
    )
    LIMIT 1
),

-- if a parent record wasn't found, insert a new one
InsertedLot AS (
    INSERT INTO omicron.public.address_lot (id, name, kind)
    SELECT id, $1, $2
    FROM NewOrExisting
    WHERE NOT EXISTS (
        SELECT 1
        FROM omicron.public.address_lot
        WHERE (name, kind) = ($1, $2)
    )
    RETURNING id
),

-- accept arrays of parameters and unnest them, allowing us to create multiple child records
-- in a single query
PreparedBlocks AS (
    SELECT id, first_address, last_address
    FROM InsertedLot, UNNEST($3::inet[], $4::inet[]) AS params(first_address, last_address)
),

-- if any of the child records already exist, filter them from the PreparedBlocks
FilteredBlocks AS (
    SELECT *
    FROM PreparedBlocks pb
    WHERE NOT EXISTS (
        SELECT 1
        FROM omicron.public.address_lot_block alb
        WHERE alb.address_lot_id = pb.id
          AND alb.first_address = pb.first_address
          AND alb.last_address = pb.last_address
    )
)

-- insert the child records
INSERT INTO omicron.public.address_lot_block (address_lot_id, first_address, last_address)
SELECT id, first_address, last_address
FROM FilteredBlocks;

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions