Hi,
I wanted to ask if the following complex CTE query which comprises of inserts, deletions, and updates could be modeled with this library.
Suppose we have a post system with attachments. Post attachments are identified by ETag's. ETag's can be associated with many posts, and posts can be associated with several ETag's at once. A many-to-many relations table is used to define this relationship.
CREATE TABLE public.posts (
id text NOT NULL,
author_id text NOT NULL,
content text NOT NULL,
created_at timestamp(3) without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
updated_at timestamp(3) without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL
);
CREATE TABLE public.etags_on_posts (
post_id text NOT NULL,
storage_id public."Storage" NOT NULL,
etag_id text NOT NULL
);
CREATE TABLE public.etags (
storage_id public."Storage" NOT NULL,
id text NOT NULL,
type text NOT NULL,
num_posts_attached integer DEFAULT 0 NOT NULL,
num_avatars_attached integer DEFAULT 0 NOT NULL
);
CREATE TYPE public."Storage" AS ENUM (
'r2'
);
Suppose we want to update a post's content and attachment given {postId: string, content: string, etags: { storageId: "r2", id: string, type: string }}[].
- Old entries to "etags_on_posts" should be removed, and their corresponding entries in "etags" should have "num_posts_attached" decremented by 1.
- New entries to "etags_on_posts" should be added, and their corresponding entries in "etags" should have "num_posts_attached" incremented by 1. If no corresponding entries in "etags" exist, they are created with the etag's type inserted as well.
- The entry of the post in "posts" should have its content updated.
The following raw porsager/postgres code represents the query:
async updatePostOrComment(sql: Sql, id: string, content: string, etags: { type: string, etag: string }[]) {
const input = etags.map(e => (["r2", e.etag, e.type]));
return sql`
with updated_post as (update posts set ${sql({ content, updatedAt: new Date() })} where id = ${id} returning *),
new_posts as (select * from posts union select * from updated_post)
${etags.length > 0 ?
sql`
, input as (select storage_id::"Storage", id::text, type::text from (values ${sql(input)}) as input(storage_id, id, type))
, removed_etags_on_post as (delete from etags_on_posts where post_id = (select id from updated_post) and (storage_id, etag_id) not in (select storage_id, id as etag_id from input) returning *)
, etags_on_post_to_add as (select (select id from updated_post) as post_id, storage_id, id as etag_id from input where (storage_id, id) not in (select storage_id, etag_id from removed_etags_on_post))
, added_etags_on_post as (insert into etags_on_posts select * from etags_on_post_to_add returning *)
, update_added_etags as (
insert into etags (storage_id, id, type) select * from input where (storage_id, id) in (select storage_id, etag_id as id from added_etags_on_post)
on conflict (storage_id, id) do update set num_posts_attached = excluded.num_posts_attached + 1 returning *
)
, update_removed_etags as (
update etags set num_posts_attached = num_posts_attached - 1
where (storage_id, id) in (select storage_id, etag_id as id from removed_etags_on_post) returning *
)
, new_etags_on_posts as (select * from etags_on_posts union select * from added_etags_on_post except select * from removed_etags_on_post)
, new_etags as (select * from etags union select * from update_added_etags union select * from update_removed_etags)`
:
sql``}
${this.submissions(sql, sql`updated_post`, { posts: sql`new_posts`, etagsOnPosts: etags.length > 0 ? sql`new_etags_on_posts` : sql`etags_on_posts`, etags: etags.length > 0 ? sql`new_etags` : sql`etags` })}`.then(([post]) => post);
},
... where this.submissions joins some additional fields and performs some extra transformations to updated_post.
If perhaps the following query might be too complicated, could it be significantly simplified with this library then?
Hi,
I wanted to ask if the following complex CTE query which comprises of inserts, deletions, and updates could be modeled with this library.
Suppose we have a post system with attachments. Post attachments are identified by ETag's. ETag's can be associated with many posts, and posts can be associated with several ETag's at once. A many-to-many relations table is used to define this relationship.
Suppose we want to update a post's content and attachment given
{postId: string, content: string, etags: { storageId: "r2", id: string, type: string }}[].The following raw porsager/postgres code represents the query:
... where
this.submissionsjoins some additional fields and performs some extra transformations toupdated_post.If perhaps the following query might be too complicated, could it be significantly simplified with this library then?