From 2d575216ebfe6141805b71e408ce7910208f602e Mon Sep 17 00:00:00 2001 From: Mitch Downey Date: Mon, 12 Aug 2024 02:12:58 -0500 Subject: [PATCH 01/73] Continue adding init database sql, and add inheritance tables --- docs/database/0001_init_database.sql | 479 ++++++++++++++++++++------- 1 file changed, 366 insertions(+), 113 deletions(-) diff --git a/docs/database/0001_init_database.sql b/docs/database/0001_init_database.sql index 6311b1d..382d160 100644 --- a/docs/database/0001_init_database.sql +++ b/docs/database/0001_init_database.sql @@ -1,5 +1,6 @@ /* -NOTES: + +PODCASTING 2.0 DATABASE SCHEMA - The `id` column is a SERIAL column that is used as the primary key for every table. @@ -18,18 +19,11 @@ NOTES: */ --- TODO: many TEXT columns should be changed to VARCHAR(255) or similar to prevent abuse. - -- Helpers -CREATE DOMAIN medium_type AS TEXT CHECK (VALUE IN ( - 'podcast', 'music', 'video', 'film', 'audiobook', 'newsletter', 'blog', 'publisher', 'course', - 'podcastL', 'musicL', 'videoL', 'filmL', 'audiobookL', 'newsletterL', 'blogL', 'publisherL', 'courseL', 'mixed' -)); - CREATE DOMAIN short_id AS VARCHAR(14); CREATE DOMAIN varchar_short AS VARCHAR(50); -CREATE DOMAIN varchar_medium AS VARCHAR(255); +CREATE DOMAIN varchar_normal AS VARCHAR(255); CREATE DOMAIN varchar_long AS VARCHAR(5000); CREATE DOMAIN varchar_fqdn AS VARCHAR(253); CREATE DOMAIN varchar_uri AS VARCHAR(2083); @@ -42,16 +36,43 @@ CREATE DOMAIN numeric_20_11 AS NUMERIC(20, 11); -- TODO: should every table have a created_at and updated_at column? -- or only some tables? or none? +--** FEED + +CREATE TABLE feed ( + id SERIAL PRIMARY KEY, + url varchar_url UNIQUE NOT NULL, + content_type varchar_short, + -- 0 to 5, 0 will only be parsed when PI API reports an update, + -- higher parsing_priority will be parsed more frequently on a schedule. + parsing_priority INTEGER DEFAULT 0, + last_http_status INTEGER, + last_crawl_time TIMESTAMP, + last_good_http_status_time TIMESTAMP, + last_parse_time TIMESTAMP, + last_update_time TIMESTAMP, + crawl_errors INTEGER DEFAULT 0, + parse_errors INTEGER DEFAULT 0, + locked BOOLEAN DEFAULT FALSE, + + -- Used to prevent another thread from parsing the same feed. + -- Set to current time at beginning of parsing, and NULL at end of parsing. + -- This is to prevent multiple threads from parsing the same feed. + -- If is_parsing is over X minutes old, assume last parsing failed and proceed to parse. + is_parsing TIMESTAMP, + container_id VARCHAR(12) +); + +--** CHANNEL + CREATE TABLE channel ( id SERIAL PRIMARY KEY, + feed_id INTEGER NOT NULL REFERENCES feed(id) ON DELETE CASCADE, id_text short_id UNIQUE NOT NULL, podcast_index_id INTEGER UNIQUE NOT NULL, - feed_url varchar_url UNIQUE NOT NULL, podcast_guid UUID UNIQUE, -- As defined by the Podcast Index spec. - title varchar_medium, + title varchar_normal, sortable_title varchar_short, -- all lowercase, ignores articles at beginning of title description varchar_long, - medium medium_type, -- channels with seasons need to be rendered in client apps differently. -- you can only determine if a channel is in a "season" format is by finding @@ -67,37 +88,20 @@ CREATE TABLE channel ( -- from the Podcast Index API. has_podcast_index_value_tags BOOLEAN DEFAULT FALSE, - -- Used to prevent another thread from parsing the same feed. - -- Set to current time at beginning of parsing, and NULL at end of parsing. - -- This is to prevent multiple threads from parsing the same feed. - -- If is_parsing is over X minutes old, assume last parsing failed and proceed to parse. - is_parsing TIMESTAMP + -- hidden items are no longer available in the rss feed, but are still in the database. + hidden BOOLEAN DEFAULT FALSE, + -- markedForDeletion items are no longer available in the rss feed, and may be able to be deleted. + marked_for_deletion BOOLEAN DEFAULT FALSE ); CREATE UNIQUE INDEX channel_podcast_guid_unique ON channel(podcast_guid) WHERE podcast_guid IS NOT NULL; -CREATE TABLE item ( - id SERIAL PRIMARY KEY, - id_text short_id UNIQUE NOT NULL, - channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, - guid varchar_uri -- Deprecated. The older RSS guid style, which is less reliable. - -- TODO: add item columns -); - -CREATE TABLE live_item ( - id SERIAL PRIMARY KEY, - channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, - item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, - status TEXT NOT NULL CHECK (status IN ('pending', 'live', 'ended')), - start_time TIMESTAMP NOT NULL, - end_time TIMESTAMP, - chat_web_url varchar_url -); +--** CHANNEL > ABOUT CREATE TABLE channel_about ( id SERIAL PRIMARY KEY, channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, - author varchar_medium, + author varchar_normal, episode_count INTEGER, explicit BOOLEAN, itunes_type TEXT CHECK (itunes_type IN ('episodic', 'serial')), @@ -105,12 +109,7 @@ CREATE TABLE channel_about ( website_link_url varchar_url ); -CREATE TABLE channel_funding ( - id SERIAL PRIMARY KEY, - channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, - url varchar_url NOT NULL, - title varchar_medium -); +--** CHANNEL > INTERNAL SETTINGS CREATE TABLE channel_internal_settings ( id SERIAL PRIMARY KEY, @@ -119,91 +118,175 @@ CREATE TABLE channel_internal_settings ( flag_status TEXT CHECK (flag_status IN ('none', 'spam', 'takedown', 'other', 'always-allow')) ); +--** CHANNEL > PODROLL + +-- CREATE TABLE channel_podroll ( id SERIAL PRIMARY KEY, channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE ); +--** CHANNEL > SEASON + +-- NOTE: A channel season does not exist in the Podcasting 2.0 spec, +-- but it is useful for organizing seasons at the channel level, +-- and might be in the P2.0 spec someday. +CREATE TABLE channel_season ( + id SERIAL PRIMARY KEY, + channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, + number INTEGER NOT NULL, + name varchar_normal +); + +--** CHANNEL > TRAILER + +-- CREATE TABLE channel_trailer ( id SERIAL PRIMARY KEY, channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, - title varchar_medium, + title varchar_normal, url varchar_url NOT NULL, - pub_date TIMESTAMP NOT NULL, -- TODO: does this need timezone handling? + pub_date TIMESTAMPTZ NOT NULL, length INTEGER, type varchar_short, season INTEGER ); -CREATE TABLE chat ( +--** ITEM + +-- corresponds with +CREATE TABLE item ( id SERIAL PRIMARY KEY, + id_text short_id UNIQUE NOT NULL, channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, - item_id INTEGER REFERENCES item(id) ON DELETE CASCADE, - live_item_id INTEGER REFERENCES live_item(id) ON DELETE CASCADE, - server varchar_fqdn NOT NULL, - protocol varchar_short, - account_id varchar_medium, - space varchar_medium + guid varchar_uri + description varchar_long, + pub_date TIMESTAMPTZ, + title varchar_normal, + + -- hidden items are no longer available in the rss feed, but are still in the database. + hidden BOOLEAN DEFAULT FALSE, + -- markedForDeletion items are no longer available in the rss feed, and may be able to be deleted. + marked_for_deletion BOOLEAN DEFAULT FALSE, + + -- TODO: add item columns ); -CREATE TABLE feed ( - id SERIAL PRIMARY KEY, - channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, - publisher_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, - CHECK ( - (channel_id IS NOT NULL AND publisher_id IS NULL) OR - (channel_id IS NULL AND publisher_id IS NOT NULL) - ), - content_type varchar_short, - -- 0 to 5, 0 will only be parsed when PI API reports an update, - -- higher parsing_priority will be parsed more frequently on a schedule. - parsing_priority INTEGER DEFAULT 0, - last_http_status INTEGER, - last_crawl_time TIMESTAMP, - last_good_http_status_time TIMESTAMP, - last_parse_time TIMESTAMP, - last_update_time TIMESTAMP, - crawl_errors INTEGER DEFAULT 0, - parse_errors INTEGER DEFAULT 0, - locked BOOLEAN DEFAULT FALSE +--** ITEM > ABOUT + +CREATE TABLE item_about ( + id SERIAL PRIMARY KEY, + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + duration INTEGER, + explicit BOOLEAN, + website_link_url varchar_url, + itunes_episode_type TEXT CHECK (itunes_episode_type IN ('full', 'trailer', 'bonus')) ); -CREATE TABLE image ( +--** ITEM > CONTENT LINK + +-- +CREATE TABLE content_link ( id SERIAL PRIMARY KEY, - channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, item_id INTEGER REFERENCES item(id) ON DELETE CASCADE, - url varchar_url NOT NULL, - image_width_size INTEGER, -- must have a width specified, but older image tags will not, so allow null. - -- If true, then the image is hosted by us in a service like S3. - -- When is_resized images are deleted, the corresponding image in S3 - -- should also be deleted. - is_resized BOOLEAN DEFAULT FALSE + href varchar_url NOT NULL, + title varchar_normal ); +--** ITEM > CHAPTERS + +-- CREATE TABLE item_chapters ( id SERIAL PRIMARY KEY, item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, url varchar_url NOT NULL, type varchar_short NOT NULL, - version varchar_short NOT NULL + last_http_status INTEGER, + last_crawl_time TIMESTAMP, + last_good_http_status_time TIMESTAMP, + last_parse_time TIMESTAMP, + last_update_time TIMESTAMP, + crawl_errors INTEGER DEFAULT 0, + parse_errors INTEGER DEFAULT 0 ); +-- corresponds with jsonChapters.md example file CREATE TABLE item_chapter ( id SERIAL PRIMARY KEY, item_chapters_file_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, start_time numeric_20_11 NOT NULL, - title varchar_medium + end_time numeric_20_11, + title varchar_normal, + img varchar_url, + web_url varchar_url, + table_of_contents BOOLEAN DEFAULT TRUE +); + +--** ITEM > ENCLOSURE (AKA ALTERNATE ENCLOSURE) + +-- +-- NOTE: the older tag style is integrated into the item_enclosure table. +CREATE TABLE item_enclosure ( + id SERIAL PRIMARY KEY, + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + type varchar_short NOT NULL, + length INTEGER, + bitrate numeric_20_11, + height INTEGER, + language varchar_short, + title varchar_short, + rel varchar_short, + codecs varchar_short, + default BOOLEAN DEFAULT FALSE +); + +CREATE TABLE item_enclosure_source ( + id SERIAL PRIMARY KEY, + item_enclosure_id INTEGER NOT NULL REFERENCES item_enclosure(id) ON DELETE CASCADE, + uri varchar_uri NOT NULL, + content_type varchar_short +); + +CREATE TABLE item_enclosure_integrity ( + id SERIAL PRIMARY KEY, + item_enclosure_id INTEGER NOT NULL REFERENCES item_enclosure_source(id) ON DELETE CASCADE, + type TEXT NOT NULL CHECK (type IN ('sri', 'pgp-signature')), + value varchar_long NOT NULL +); + +--** ITEM > SEASON + +-- corresponds with +CREATE TABLE item_season ( + id SERIAL PRIMARY KEY, + channel_season_id INTEGER NOT NULL REFERENCES channel_season(id) ON DELETE CASCADE, + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + title varchar_normal ); +--** ITEM > SEASON > EPISODE + +-- corresponds with +CREATE TABLE item_season_episode ( + id SERIAL PRIMARY KEY, + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + display varchar_short, + episode_number numeric_20_11 NOT NULL +); + +--** ITEM > SOUNDBITE + CREATE TABLE item_soundbite ( id SERIAL PRIMARY KEY, item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, url varchar_url NOT NULL, start_time INTEGER NOT NULL, duration INTEGER NOT NULL, - title varchar_medium + title varchar_normal ); +--** ITEM > TRANSCRIPT + CREATE TABLE item_transcript ( id SERIAL PRIMARY KEY, item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, @@ -213,85 +296,255 @@ CREATE TABLE item_transcript ( rel VARCHAR(50) CHECK (rel IS NULL OR rel = 'captions') ); -CREATE TABLE location ( +--** LIVE ITEM + +CREATE TABLE live_item ( + id SERIAL PRIMARY KEY, + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + status TEXT NOT NULL CHECK (status IN ('pending', 'live', 'ended')), + start_time TIMESTAMPTZ NOT NULL, + end_time TIMESTAMPTZ, + chat_web_url varchar_url +); + +--** CROSS-CUTTING INHERITANCE TABLES + +--** CHAT + +-- +CREATE TABLE chat_base ( id SERIAL PRIMARY KEY, + server varchar_fqdn NOT NULL, + protocol varchar_short, + account_id varchar_normal, + space varchar_normal +) + +CREATE TABLE channel_chat ( channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, - item_id INTEGER REFERENCES item(id) ON DELETE CASCADE, - geo varchar_medium, - osm varchar_medium, +) INHERITS (chat_base); + +CREATE TABLE item_chat ( + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, +) INHERITS (chat_base); + +--** FUNDING + +-- +CREATE TABLE funding_base ( + id SERIAL PRIMARY KEY, + url varchar_url NOT NULL, + title varchar_normal +); + +CREATE TABLE channel_funding ( + channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE +) INHERITS (funding_base); + +CREATE TABLE item_funding ( + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE +) INHERITS (funding_base); + +--** IMAGE + +-- AND all other image tags in the rss feed. +-- older image tag data will be adapted into the image_base table. +CREATE TABLE image_base ( + id SERIAL PRIMARY KEY, + url varchar_url NOT NULL, + image_width_size INTEGER, -- must have a width specified, but older image tags will not, so allow null. + + -- If true, then the image is hosted by us in a service like S3. + -- When is_resized images are deleted, the corresponding image in S3 + -- should also be deleted. + is_resized BOOLEAN DEFAULT FALSE +); + +CREATE TABLE channel_image ( + channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE +) INHERITS (image_base); + +CREATE TABLE item_image ( + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE +) INHERITS (image_base); + +--** LICENSE + +-- +CREATE TABLE license_base ( + id SERIAL PRIMARY KEY, + type varchar_normal NOT NULL, + url varchar_url NOT NULL +); + +CREATE TABLE channel_license ( + channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE +) INHERITS (license_base); + +CREATE TABLE item_license ( + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE +) INHERITS (license_base); + +--** LOCATION + +CREATE TABLE location_base ( + id SERIAL PRIMARY KEY, + chapter_id INTEGER REFERENCES item_chapter(id) ON DELETE CASCADE, + geo varchar_normal, + osm varchar_normal, CHECK ( (geo IS NOT NULL AND osm IS NULL) OR (geo IS NULL AND osm IS NOT NULL) ) ); --- TODO: write notifications table +CREATE TABLE channel_location ( + channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE +) INHERITS (location_base); + +CREATE TABLE item_location ( + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE +) INHERITS (location_base); -CREATE TABLE person ( +--** MEDIUM + +CREATE TABLE medium_value ( id SERIAL PRIMARY KEY, - channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, - item_id INTEGER REFERENCES item(id) ON DELETE CASCADE, - name varchar_medium, - role varchar_medium, - person_group TEXT DEFAULT 'cast', -- group is a reserved keyword in sql - img varchar_url, - href varchar_url + value TEXT UNIQUE CHECK (VALUE IN ( + 'publisher', + 'podcast', 'music', 'video', 'film', 'audiobook', 'newsletter', 'blog', 'publisher', 'course', + 'mixed', 'podcastL', 'musicL', 'videoL', 'filmL', 'audiobookL', 'newsletterL', 'blogL', 'publisherL', 'courseL' + )); ); --- TODO: write the publisher table schema --- see https://github.com/Podcastindex-org/podcast-namespace/blob/ccfb191c98762ba31f98620bd1ba30c1822f6fbd/publishers/publishers.md -CREATE TABLE publisher ( +INSERT INTO medium_value (value) VALUES + ('publisher'), + ('podcast'), ('music'), ('video'), ('film'), ('audiobook'), ('newsletter'), ('blog'), ('course'), + ('mixed'), ('podcastL'), ('musicL'), ('videoL'), ('filmL'), ('audiobookL'), ('newsletterL'), ('blogL'), ('publisherL'), ('courseL') +; + +CREATE TABLE medium_base ( id SERIAL PRIMARY KEY, + medium_value_id INTEGER NOT NULL REFERENCES medium_value(id) ON DELETE CASCADE +); + +CREATE TABLE channel_medium ( channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE +) INHERITS (medium_base); + +CREATE TABLE remote_item_medium ( + remote_item_id INTEGER NOT NULL REFERENCES remote_item(id) ON DELETE CASCADE +) INHERITS (medium_base); + +--** PERSON + +CREATE TABLE person_base ( + id SERIAL PRIMARY KEY, + name varchar_normal, + role varchar_normal, + person_group varchar_normal DEFAULT 'cast', -- group is a reserved keyword in sql + img varchar_url, + href varchar_url ); -CREATE TABLE remote_item ( +CREATE TABLE channel_person ( + channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE +) INHERITS (person_base); + +CREATE TABLE item_person ( + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE +) INHERITS (person_base); + +--** REMOTE ITEM + +CREATE TABLE remote_item_base ( id SERIAL PRIMARY KEY, - channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, - podroll_id INTEGER REFERENCES channel_podroll(id), - publisher_id INTEGER REFERENCES publisher(id), - item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, feed_guid UUID NOT NULL, feed_url varchar_url, item_guid varchar_uri, - medium medium_type, - title varchar_medium + title varchar_normal ); -CREATE TABLE social_interact ( +CREATE TABLE channel_remote_item ( + channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE +) INHERITS (remote_item_base); + +CREATE TABLE item_remote_item ( + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE +) INHERITS (remote_item_base); + +CREATE TABLE podroll_remote_item ( + podroll_id INTEGER NOT NULL REFERENCES channel_podroll(id) ON DELETE CASCADE +) INHERITS (remote_item_base); + +--** SOCIAL INTERACT + +CREATE TABLE social_interact_base ( id SERIAL PRIMARY KEY, - channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, - item_id INTEGER REFERENCES item(id) ON DELETE CASCADE, protocol varchar_short NOT NULL, uri varchar_uri NOT NULL, - account_id varchar_medium, + account_id varchar_normal, account_url varchar_url, priority INTEGER ); --- TODO: write stats solution (further down the road) +CREATE TABLE channel_social_interact ( + channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE +) INHERITS (social_interact_base); + +CREATE TABLE item_social_interact ( + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE +) INHERITS (social_interact_base); -CREATE TABLE value_tag ( +--** TXT + +CREATE TABLE txt_tag_base ( + id SERIAL PRIMARY KEY, + verify varchar_normal NOT NULL, + value varchar_long NOT NULL +); + +CREATE TABLE channel_txt_tag ( + channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE +) INHERITS (txt_tag_base); + +CREATE TABLE item_txt_tag ( + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE +) INHERITS (txt_tag_base); + +--** VALUE TAG + +CREATE TABLE value_tag_base ( id SERIAL PRIMARY KEY, - channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, - item_id INTEGER REFERENCES item(id) ON DELETE CASCADE, type varchar_short NOT NULL, method varchar_short NOT NULL, suggested numeric_20_11 ); +CREATE TABLE channel_value_tag ( + channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE +) INHERITS (value_tag_base); + +CREATE TABLE item_value_tag ( + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE +) INHERITS (value_tag_base); + +--** VALUE TAG > RECEIPIENT + CREATE TABLE value_tag_receipient ( id SERIAL PRIMARY KEY, value_tag_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, type varchar_short NOT NULL, address varchar_long NOT NULL, split numeric_20_11 NOT NULL, - name varchar_medium, + name varchar_normal, custom_key varchar_long, custom_value varchar_long, fee BOOLEAN DEFAULT FALSE ); +--** VALUE TAG > TIME SPLIT + CREATE TABLE value_tag_time_split ( id SERIAL PRIMARY KEY, value_tag_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, From 6f21f91b3b33c5925d9c4ec1d25e4a997614d9d7 Mon Sep 17 00:00:00 2001 From: Mitch Downey Date: Tue, 13 Aug 2024 23:13:00 -0500 Subject: [PATCH 02/73] Continue adding initial database schema --- docs/database/0001_init_database.sql | 186 ++++++++++++++++++--------- 1 file changed, 126 insertions(+), 60 deletions(-) diff --git a/docs/database/0001_init_database.sql b/docs/database/0001_init_database.sql index 382d160..c7629fe 100644 --- a/docs/database/0001_init_database.sql +++ b/docs/database/0001_init_database.sql @@ -36,12 +36,21 @@ CREATE DOMAIN numeric_20_11 AS NUMERIC(20, 11); -- TODO: should every table have a created_at and updated_at column? -- or only some tables? or none? +--** FEED > FLAG STATUS + +CREATE TABLE feed_flag_status ( + id SERIAL PRIMARY KEY, + status TEXT UNIQUE CHECK (status IN ('none', 'spam', 'takedown', 'other', 'always-allow')) +); + +INSERT INTO feed_flag_status (status) VALUES ('none'), ('spam'), ('takedown'), ('other'), ('always-allow'); + --** FEED CREATE TABLE feed ( id SERIAL PRIMARY KEY, url varchar_url UNIQUE NOT NULL, - content_type varchar_short, + -- 0 to 5, 0 will only be parsed when PI API reports an update, -- higher parsing_priority will be parsed more frequently on a schedule. parsing_priority INTEGER DEFAULT 0, @@ -52,7 +61,8 @@ CREATE TABLE feed ( last_update_time TIMESTAMP, crawl_errors INTEGER DEFAULT 0, parse_errors INTEGER DEFAULT 0, - locked BOOLEAN DEFAULT FALSE, + + feed_flag_status_id INTEGER REFERENCES feed_flag_status(id), -- Used to prevent another thread from parsing the same feed. -- Set to current time at beginning of parsing, and NULL at end of parsing. @@ -64,20 +74,15 @@ CREATE TABLE feed ( --** CHANNEL +-- CREATE TABLE channel ( id SERIAL PRIMARY KEY, feed_id INTEGER NOT NULL REFERENCES feed(id) ON DELETE CASCADE, id_text short_id UNIQUE NOT NULL, podcast_index_id INTEGER UNIQUE NOT NULL, - podcast_guid UUID UNIQUE, -- As defined by the Podcast Index spec. + podcast_guid UUID UNIQUE, -- title varchar_normal, sortable_title varchar_short, -- all lowercase, ignores articles at beginning of title - description varchar_long, - - -- channels with seasons need to be rendered in client apps differently. - -- you can only determine if a channel is in a "season" format is by finding - -- the tag in an item in that channel. - has_season BOOLEAN DEFAULT FALSE, -- TODO: should we hash the last parsed feed, so we can compare it to the hash of -- a feed before completely parsing it, to check if it has changed before continuing? @@ -96,17 +101,27 @@ CREATE TABLE channel ( CREATE UNIQUE INDEX channel_podcast_guid_unique ON channel(podcast_guid) WHERE podcast_guid IS NOT NULL; +--** CHANNEL > ABOUT > ITUNES TYPE + +-- +CREATE TABLE channel_itunes_type ( + id SERIAL PRIMARY KEY, + itunes_type TEXT UNIQUE CHECK (itunes_type IN ('episodic', 'serial')) +); + +INSERT INTO channel_itunes_type (itunes_type) VALUES ('episodic'), ('serial'); + --** CHANNEL > ABOUT CREATE TABLE channel_about ( id SERIAL PRIMARY KEY, channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, - author varchar_normal, - episode_count INTEGER, - explicit BOOLEAN, - itunes_type TEXT CHECK (itunes_type IN ('episodic', 'serial')), - language varchar_short NOT NULL, - website_link_url varchar_url + author varchar_normal, -- and + episode_count INTEGER, -- aggregated count for convenience + explicit BOOLEAN, -- + itunes_type_id INTEGER REFERENCES channel_itunes_type(id), + language varchar_short NOT NULL, -- + website_link_url varchar_url -- ); --** CHANNEL > INTERNAL SETTINGS @@ -114,8 +129,9 @@ CREATE TABLE channel_about ( CREATE TABLE channel_internal_settings ( id SERIAL PRIMARY KEY, channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, - embed_approved_media_url_paths TEXT, - flag_status TEXT CHECK (flag_status IN ('none', 'spam', 'takedown', 'other', 'always-allow')) + -- needed to approve which web domains can override the player with query params. + -- this prevents malicious parties from misrepresenting the podcast contents on another website. + embed_approved_media_url_paths TEXT ); --** CHANNEL > PODROLL @@ -128,13 +144,19 @@ CREATE TABLE channel_podroll ( --** CHANNEL > SEASON +-- channels with seasons need to be rendered in client apps differently. +-- you can only determine if a channel is in a "season" format is by finding +-- the tag in an item in that channel. + -- NOTE: A channel season does not exist in the Podcasting 2.0 spec, -- but it is useful for organizing seasons at the channel level, --- and might be in the P2.0 spec someday. +-- and could be in the P2.0 spec someday. + CREATE TABLE channel_season ( id SERIAL PRIMARY KEY, channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, number INTEGER NOT NULL, + UNIQUE (channel_id, number), name varchar_normal ); @@ -154,33 +176,40 @@ CREATE TABLE channel_trailer ( --** ITEM --- corresponds with +-- CREATE TABLE item ( id SERIAL PRIMARY KEY, id_text short_id UNIQUE NOT NULL, channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, - guid varchar_uri - description varchar_long, - pub_date TIMESTAMPTZ, - title varchar_normal, + guid varchar_uri, -- + pub_date TIMESTAMPTZ, -- + title varchar_normal, -- -- hidden items are no longer available in the rss feed, but are still in the database. hidden BOOLEAN DEFAULT FALSE, -- markedForDeletion items are no longer available in the rss feed, and may be able to be deleted. - marked_for_deletion BOOLEAN DEFAULT FALSE, + marked_for_deletion BOOLEAN DEFAULT FALSE +); + +--** ITEM > ABOUT > ITUNES TYPE - -- TODO: add item columns +-- <itunes:episodeType> +CREATE TABLE item_itunes_episode_type ( + id SERIAL PRIMARY KEY, + itunes_episode_type TEXT UNIQUE CHECK (itunes_episode_type IN ('full', 'trailer', 'bonus')) ); +INSERT INTO item_itunes_episode_type (itunes_episode_type) VALUES ('full'), ('trailer'), ('bonus'); + --** ITEM > ABOUT CREATE TABLE item_about ( id SERIAL PRIMARY KEY, item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, - duration INTEGER, - explicit BOOLEAN, - website_link_url varchar_url, - itunes_episode_type TEXT CHECK (itunes_episode_type IN ('full', 'trailer', 'bonus')) + duration INTEGER, -- <itunes:duration> + explicit BOOLEAN, -- <itunes:explicit> + website_link_url varchar_url, -- <link> + item_itunes_episode_type_id INTEGER REFERENCES item_itunes_episode_type(id) ); --** ITEM > CONTENT LINK @@ -237,7 +266,7 @@ CREATE TABLE item_enclosure ( title varchar_short, rel varchar_short, codecs varchar_short, - default BOOLEAN DEFAULT FALSE + item_enclosure_default BOOLEAN DEFAULT FALSE ); CREATE TABLE item_enclosure_source ( @@ -256,7 +285,7 @@ CREATE TABLE item_enclosure_integrity ( --** ITEM > SEASON --- corresponds with <podcast:season> +-- <podcast:season> CREATE TABLE item_season ( id SERIAL PRIMARY KEY, channel_season_id INTEGER NOT NULL REFERENCES channel_season(id) ON DELETE CASCADE, @@ -266,7 +295,7 @@ CREATE TABLE item_season ( --** ITEM > SEASON > EPISODE --- corresponds with <podcast:episode> +-- <podcast:episode> CREATE TABLE item_season_episode ( id SERIAL PRIMARY KEY, item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, @@ -276,6 +305,7 @@ CREATE TABLE item_season_episode ( --** ITEM > SOUNDBITE +-- <podcast:soundbite> CREATE TABLE item_soundbite ( id SERIAL PRIMARY KEY, item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, @@ -287,6 +317,7 @@ CREATE TABLE item_soundbite ( --** ITEM > TRANSCRIPT +-- <podcast:transcript> CREATE TABLE item_transcript ( id SERIAL PRIMARY KEY, item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, @@ -296,12 +327,22 @@ CREATE TABLE item_transcript ( rel VARCHAR(50) CHECK (rel IS NULL OR rel = 'captions') ); +--** LIVE ITEM > STATUS + +CREATE TABLE live_item_status ( + id SERIAL PRIMARY KEY, + status TEXT UNIQUE CHECK (status IN ('pending', 'live', 'ended')) +); + +INSERT INTO live_item_status (status) VALUES ('pending'), ('live'), ('ended'); + --** LIVE ITEM +-- <podcast:liveItem> CREATE TABLE live_item ( id SERIAL PRIMARY KEY, item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, - status TEXT NOT NULL CHECK (status IN ('pending', 'live', 'ended')), + live_item_status_id INTEGER REFERENCES live_item_status(id), start_time TIMESTAMPTZ NOT NULL, end_time TIMESTAMPTZ, chat_web_url varchar_url @@ -318,16 +359,32 @@ CREATE TABLE chat_base ( protocol varchar_short, account_id varchar_normal, space varchar_normal -) +); CREATE TABLE channel_chat ( - channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, + channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE ) INHERITS (chat_base); CREATE TABLE item_chat ( - item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE ) INHERITS (chat_base); +--** DESCRIPTION + +-- <description> AND possibly other tags that contain a description. +CREATE TABLE description_base ( + id SERIAL PRIMARY KEY, + value varchar_long NOT NULL +); + +CREATE TABLE channel_description ( + channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE +) INHERITS (description_base); + +CREATE TABLE item_description ( + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE +) INHERITS (description_base); + --** FUNDING -- <podcast:funding> @@ -387,6 +444,7 @@ CREATE TABLE item_license ( --** LOCATION +-- <podcast:location> CREATE TABLE location_base ( id SERIAL PRIMARY KEY, chapter_id INTEGER REFERENCES item_chapter(id) ON DELETE CASCADE, @@ -406,15 +464,39 @@ CREATE TABLE item_location ( item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE ) INHERITS (location_base); +--** REMOTE ITEM + +-- <podcast:remoteItem> +CREATE TABLE remote_item_base ( + id SERIAL PRIMARY KEY, + feed_guid UUID NOT NULL, + feed_url varchar_url, + item_guid varchar_uri, + title varchar_normal +); + +CREATE TABLE channel_remote_item ( + channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE +) INHERITS (remote_item_base); + +CREATE TABLE item_remote_item ( + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE +) INHERITS (remote_item_base); + +CREATE TABLE podroll_remote_item ( + podroll_id INTEGER NOT NULL REFERENCES channel_podroll(id) ON DELETE CASCADE +) INHERITS (remote_item_base); + --** MEDIUM +-- <podcast:medium> CREATE TABLE medium_value ( id SERIAL PRIMARY KEY, value TEXT UNIQUE CHECK (VALUE IN ( 'publisher', 'podcast', 'music', 'video', 'film', 'audiobook', 'newsletter', 'blog', 'publisher', 'course', 'mixed', 'podcastL', 'musicL', 'videoL', 'filmL', 'audiobookL', 'newsletterL', 'blogL', 'publisherL', 'courseL' - )); + )) ); INSERT INTO medium_value (value) VALUES @@ -433,11 +515,12 @@ CREATE TABLE channel_medium ( ) INHERITS (medium_base); CREATE TABLE remote_item_medium ( - remote_item_id INTEGER NOT NULL REFERENCES remote_item(id) ON DELETE CASCADE + remote_item_id INTEGER NOT NULL REFERENCES remote_item_base(id) ON DELETE CASCADE ) INHERITS (medium_base); --** PERSON +-- <podcast:person> CREATE TABLE person_base ( id SERIAL PRIMARY KEY, name varchar_normal, @@ -455,30 +538,9 @@ CREATE TABLE item_person ( item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE ) INHERITS (person_base); ---** REMOTE ITEM - -CREATE TABLE remote_item_base ( - id SERIAL PRIMARY KEY, - feed_guid UUID NOT NULL, - feed_url varchar_url, - item_guid varchar_uri, - title varchar_normal -); - -CREATE TABLE channel_remote_item ( - channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE -) INHERITS (remote_item_base); - -CREATE TABLE item_remote_item ( - item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE -) INHERITS (remote_item_base); - -CREATE TABLE podroll_remote_item ( - podroll_id INTEGER NOT NULL REFERENCES channel_podroll(id) ON DELETE CASCADE -) INHERITS (remote_item_base); - --** SOCIAL INTERACT +-- <podcast:socialInteract> CREATE TABLE social_interact_base ( id SERIAL PRIMARY KEY, protocol varchar_short NOT NULL, @@ -498,6 +560,7 @@ CREATE TABLE item_social_interact ( --** TXT +-- <podcast:txt> CREATE TABLE txt_tag_base ( id SERIAL PRIMARY KEY, verify varchar_normal NOT NULL, @@ -514,6 +577,7 @@ CREATE TABLE item_txt_tag ( --** VALUE TAG +-- <podcast:value> CREATE TABLE value_tag_base ( id SERIAL PRIMARY KEY, type varchar_short NOT NULL, @@ -531,6 +595,7 @@ CREATE TABLE item_value_tag ( --** VALUE TAG > RECEIPIENT +-- <podcast:valueRecipient> CREATE TABLE value_tag_receipient ( id SERIAL PRIMARY KEY, value_tag_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, @@ -545,6 +610,7 @@ CREATE TABLE value_tag_receipient ( --** VALUE TAG > TIME SPLIT +-- <podcast:valueTimeSplit> CREATE TABLE value_tag_time_split ( id SERIAL PRIMARY KEY, value_tag_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, From b18ccdf977e919d41c269e6ed6a730372fee810e Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Tue, 13 Aug 2024 23:18:16 -0500 Subject: [PATCH 03/73] Rename Podcasting 2.0 database init file --- ...001_init_database.sql => 0001_init_podcasting_20_database.sql} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename docs/database/{0001_init_database.sql => 0001_init_podcasting_20_database.sql} (100%) diff --git a/docs/database/0001_init_database.sql b/docs/database/0001_init_podcasting_20_database.sql similarity index 100% rename from docs/database/0001_init_database.sql rename to docs/database/0001_init_podcasting_20_database.sql From 173ef690828560ea2abcc12150edaa9e2e753a5a Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Wed, 14 Aug 2024 00:51:49 -0500 Subject: [PATCH 04/73] Add categories and missing NOT NULL to relationships --- .../0001_init_podcasting_20_database.sql | 38 ++++++++++++++++--- 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/docs/database/0001_init_podcasting_20_database.sql b/docs/database/0001_init_podcasting_20_database.sql index c7629fe..def7873 100644 --- a/docs/database/0001_init_podcasting_20_database.sql +++ b/docs/database/0001_init_podcasting_20_database.sql @@ -25,7 +25,12 @@ CREATE DOMAIN short_id AS VARCHAR(14); CREATE DOMAIN varchar_short AS VARCHAR(50); CREATE DOMAIN varchar_normal AS VARCHAR(255); CREATE DOMAIN varchar_long AS VARCHAR(5000); + +CREATE DOMAIN varchar_email AS VARCHAR(255) CHECK (VALUE ~ '^.+@.+\..+$'); CREATE DOMAIN varchar_fqdn AS VARCHAR(253); +CREATE DOMAIN varchar_guid AS VARCHAR(36); +CREATE DOMAIN varchar_password AS VARCHAR(36); +CREATE DOMAIN varchar_slug AS VARCHAR(100); CREATE DOMAIN varchar_uri AS VARCHAR(2083); CREATE DOMAIN varchar_url AS VARCHAR(2083) CHECK (VALUE ~ '^https?://|^http?://'); @@ -62,7 +67,7 @@ CREATE TABLE feed ( crawl_errors INTEGER DEFAULT 0, parse_errors INTEGER DEFAULT 0, - feed_flag_status_id INTEGER REFERENCES feed_flag_status(id), + feed_flag_status_id INTEGER NOT NULL REFERENCES feed_flag_status(id), -- Used to prevent another thread from parsing the same feed. -- Set to current time at beginning of parsing, and NULL at end of parsing. @@ -77,13 +82,13 @@ CREATE TABLE feed ( -- <channel> CREATE TABLE channel ( id SERIAL PRIMARY KEY, - feed_id INTEGER NOT NULL REFERENCES feed(id) ON DELETE CASCADE, id_text short_id UNIQUE NOT NULL, + slug varchar_slug, + feed_id INTEGER NOT NULL REFERENCES feed(id) ON DELETE CASCADE, podcast_index_id INTEGER UNIQUE NOT NULL, podcast_guid UUID UNIQUE, -- <podcast:guid> title varchar_normal, sortable_title varchar_short, -- all lowercase, ignores articles at beginning of title - -- TODO: should we hash the last parsed feed, so we can compare it to the hash of -- a feed before completely parsing it, to check if it has changed before continuing? @@ -100,6 +105,7 @@ CREATE TABLE channel ( ); CREATE UNIQUE INDEX channel_podcast_guid_unique ON channel(podcast_guid) WHERE podcast_guid IS NOT NULL; +CREATE UNIQUE INDEX channel_slug ON channel(slug) WHERE slug IS NOT NULL; --** CHANNEL > ABOUT > ITUNES TYPE @@ -124,6 +130,18 @@ CREATE TABLE channel_about ( website_link_url varchar_url -- <link> ); +CREATE TABLE category ( + node_text varchar_normal NOT NULL, -- <itunes:category> + display_name varchar_normal NOT NULL, -- our own display name for the category + slug varchar_normal NOT NULL +); + +CREATE TABLE channel_category ( + id SERIAL PRIMARY KEY, + channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, + parent_id INTEGER REFERENCES channel_category(id) ON DELETE CASCADE +); + --** CHANNEL > INTERNAL SETTINGS CREATE TABLE channel_internal_settings ( @@ -180,6 +198,7 @@ CREATE TABLE channel_trailer ( CREATE TABLE item ( id SERIAL PRIMARY KEY, id_text short_id UNIQUE NOT NULL, + slug varchar_slug, channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, guid varchar_uri, -- <guid> pub_date TIMESTAMPTZ, -- <pubDate> @@ -191,6 +210,8 @@ CREATE TABLE item ( marked_for_deletion BOOLEAN DEFAULT FALSE ); +CREATE UNIQUE INDEX item_slug ON item(slug) WHERE slug IS NOT NULL; + --** ITEM > ABOUT > ITUNES TYPE -- <itunes:episodeType> @@ -217,7 +238,7 @@ CREATE TABLE item_about ( -- <podcast:contentLink> CREATE TABLE content_link ( id SERIAL PRIMARY KEY, - item_id INTEGER REFERENCES item(id) ON DELETE CASCADE, + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, href varchar_url NOT NULL, title varchar_normal ); @@ -242,6 +263,7 @@ CREATE TABLE item_chapters ( -- corresponds with jsonChapters.md example file CREATE TABLE item_chapter ( id SERIAL PRIMARY KEY, + text_id short_id UNIQUE NOT NULL, item_chapters_file_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, start_time numeric_20_11 NOT NULL, end_time numeric_20_11, @@ -308,6 +330,7 @@ CREATE TABLE item_season_episode ( -- <podcast:soundbite> CREATE TABLE item_soundbite ( id SERIAL PRIMARY KEY, + id_text short_id UNIQUE NOT NULL, item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, url varchar_url NOT NULL, start_time INTEGER NOT NULL, @@ -342,7 +365,7 @@ INSERT INTO live_item_status (status) VALUES ('pending'), ('live'), ('ended'); CREATE TABLE live_item ( id SERIAL PRIMARY KEY, item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, - live_item_status_id INTEGER REFERENCES live_item_status(id), + live_item_status_id INTEGER NOT NULL REFERENCES live_item_status(id), start_time TIMESTAMPTZ NOT NULL, end_time TIMESTAMPTZ, chat_web_url varchar_url @@ -447,7 +470,6 @@ CREATE TABLE item_license ( -- <podcast:location> CREATE TABLE location_base ( id SERIAL PRIMARY KEY, - chapter_id INTEGER REFERENCES item_chapter(id) ON DELETE CASCADE, geo varchar_normal, osm varchar_normal, CHECK ( @@ -456,6 +478,10 @@ CREATE TABLE location_base ( ) ); +CREATE TABLE item_chapter_location ( + item_chapter_id INTEGER NOT NULL REFERENCES item_chapter(id) ON DELETE CASCADE +) INHERITS (location_base); + CREATE TABLE channel_location ( channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE ) INHERITS (location_base); From b156bd9818b52b7b4a228244c3466a3c5ec52e70 Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Wed, 14 Aug 2024 00:51:59 -0500 Subject: [PATCH 05/73] Add account table --- docs/database/0002_account.sql | 55 ++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 docs/database/0002_account.sql diff --git a/docs/database/0002_account.sql b/docs/database/0002_account.sql new file mode 100644 index 0000000..f9e46d4 --- /dev/null +++ b/docs/database/0002_account.sql @@ -0,0 +1,55 @@ +CREATE TABLE account ( + id SERIAL PRIMARY KEY, + id_text short_id UNIQUE NOT NULL +); + +CREATE TABLE account_credentials ( + id SERIAL PRIMARY KEY, + account_id integer REFERENCES account(id), + email varchar_email UNIQUE NOT NULL, + password varchar_password NOT NULL +); + +CREATE TABLE account_profile ( + id SERIAL PRIMARY KEY, + account_id integer REFERENCES account(id), + display_name varchar_normal, + bio varchar_long, + is_public BOOLEAN DEFAULT FALSE +); + +CREATE TABLE account_reset_password ( + id SERIAL PRIMARY KEY, + account_id integer REFERENCES account(id), + reset_token varchar_guid, + reset_token_expires_at TIMESTAMP +); + +CREATE TABLE account_verification ( + id SERIAL PRIMARY KEY, + account_id integer REFERENCES account(id), + verification_token varchar_guid, + verification_token_expires_at TIMESTAMP, + verified BOOLEAN DEFAULT FALSE +); + +CREATE TABLE account_membership ( + id SERIAL PRIMARY KEY, + tier TEXT UNIQUE CHECK (tier IN ('trial', 'basic')) +); + +INSERT INTO account_membership (tier) VALUES ('trial'), ('basic'); + +CREATE TABLE account_membership_status ( + id SERIAL PRIMARY KEY, + account_id INTEGER NOT NULL REFERENCES account(id), + account_membership_id INTEGER NOT NULL REFERENCES account_membership(id), + membership_expires_at TIMESTAMP +); + +CREATE TABLE account_admin_roles ( + id SERIAL PRIMARY KEY, + account_id INTEGER NOT NULL REFERENCES account(id), + dev_admin BOOLEAN DEFAULT FALSE, + podping_admin BOOLEAN DEFAULT FALSE +); From 3f4d5c35adc85eb91a904f2e6c3f0b5da02b9c86 Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Wed, 14 Aug 2024 01:03:15 -0500 Subject: [PATCH 06/73] Set varchar_long to 2500; add chapter hash column --- docs/database/0001_init_podcasting_20_database.sql | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/docs/database/0001_init_podcasting_20_database.sql b/docs/database/0001_init_podcasting_20_database.sql index def7873..2683a30 100644 --- a/docs/database/0001_init_podcasting_20_database.sql +++ b/docs/database/0001_init_podcasting_20_database.sql @@ -24,7 +24,7 @@ PODCASTING 2.0 DATABASE SCHEMA CREATE DOMAIN short_id AS VARCHAR(14); CREATE DOMAIN varchar_short AS VARCHAR(50); CREATE DOMAIN varchar_normal AS VARCHAR(255); -CREATE DOMAIN varchar_long AS VARCHAR(5000); +CREATE DOMAIN varchar_long AS VARCHAR(2500); CREATE DOMAIN varchar_email AS VARCHAR(255) CHECK (VALUE ~ '^.+@.+\..+$'); CREATE DOMAIN varchar_fqdn AS VARCHAR(253); @@ -265,10 +265,14 @@ CREATE TABLE item_chapter ( id SERIAL PRIMARY KEY, text_id short_id UNIQUE NOT NULL, item_chapters_file_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + + -- the hash is used for comparison, to determine if new chapters should be inserted + -- after re-parsing an existing chapters file. + hash varchar_guid NOT NULL, + start_time numeric_20_11 NOT NULL, end_time numeric_20_11, title varchar_normal, - img varchar_url, web_url varchar_url, table_of_contents BOOLEAN DEFAULT TRUE ); @@ -444,6 +448,10 @@ CREATE TABLE channel_image ( channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE ) INHERITS (image_base); +CREATE TABLE chapter_image ( + chapter_id INTEGER NOT NULL REFERENCES chapter(id) ON DELETE CASCADE +) INHERITS (image_base); + CREATE TABLE item_image ( item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE ) INHERITS (image_base); From ddbc6f2fef77eca0fe4f6e826188632d1286d73f Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Wed, 14 Aug 2024 02:50:25 -0500 Subject: [PATCH 07/73] Add unique id to inherits tables that can only have one row per foreign key --- .../0001_init_podcasting_20_database.sql | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/docs/database/0001_init_podcasting_20_database.sql b/docs/database/0001_init_podcasting_20_database.sql index 2683a30..a313595 100644 --- a/docs/database/0001_init_podcasting_20_database.sql +++ b/docs/database/0001_init_podcasting_20_database.sql @@ -405,11 +405,13 @@ CREATE TABLE description_base ( ); CREATE TABLE channel_description ( - channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE + channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, + UNIQUE (channel_id) ) INHERITS (description_base); CREATE TABLE item_description ( - item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + UNIQUE (item_id) ) INHERITS (description_base); --** FUNDING @@ -466,11 +468,13 @@ CREATE TABLE license_base ( ); CREATE TABLE channel_license ( - channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE + channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, + UNIQUE (channel_id) ) INHERITS (license_base); CREATE TABLE item_license ( - item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + UNIQUE (item_id) ) INHERITS (license_base); --** LOCATION @@ -545,11 +549,13 @@ CREATE TABLE medium_base ( ); CREATE TABLE channel_medium ( - channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE + channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, + UNIQUE (channel_id) ) INHERITS (medium_base); CREATE TABLE remote_item_medium ( - remote_item_id INTEGER NOT NULL REFERENCES remote_item_base(id) ON DELETE CASCADE + remote_item_id INTEGER NOT NULL REFERENCES remote_item_base(id) ON DELETE CASCADE, + UNIQUE (remote_item_id) ) INHERITS (medium_base); --** PERSON From f9f08c065ab6c22d7193b89304f1f43aa230065e Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Wed, 14 Aug 2024 02:51:13 -0500 Subject: [PATCH 08/73] Add clip table --- docs/database/0003_clip.sql | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 docs/database/0003_clip.sql diff --git a/docs/database/0003_clip.sql b/docs/database/0003_clip.sql new file mode 100644 index 0000000..ec8938f --- /dev/null +++ b/docs/database/0003_clip.sql @@ -0,0 +1,10 @@ +CREATE TABLE clip ( + id SERIAL PRIMARY KEY, + id_text short_id UNIQUE NOT NULL, + account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, + start_time numeric_20_11 NOT NULL, + end_time numeric_20_11, + title varchar_normal, + description varchar_long, + isPublic BOOLEAN DEFAULT FALSE +); From f33f1c045023c00dd842ee072d013cfd359eeadd Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Wed, 14 Aug 2024 18:53:55 -0500 Subject: [PATCH 09/73] Add sharable_status to account and clip --- docs/database/0002_account.sql | 17 ++++++++++++----- docs/database/0003_clip.sql | 2 +- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/docs/database/0002_account.sql b/docs/database/0002_account.sql index f9e46d4..7b15125 100644 --- a/docs/database/0002_account.sql +++ b/docs/database/0002_account.sql @@ -1,6 +1,15 @@ +CREATE TABLE sharable_status ( + id SERIAL PRIMARY KEY, + status TEXT UNIQUE CHECK (status IN ('public', 'unlisted', 'private')) +); + +INSERT INTO sharable_status (status) VALUES ('public'), ('unlisted'), ('private'); + CREATE TABLE account ( id SERIAL PRIMARY KEY, - id_text short_id UNIQUE NOT NULL + id_text short_id UNIQUE NOT NULL, + verified BOOLEAN DEFAULT FALSE, + sharable_status_id INTEGER NOT NULL REFERENCES sharable_status(id) ); CREATE TABLE account_credentials ( @@ -14,8 +23,7 @@ CREATE TABLE account_profile ( id SERIAL PRIMARY KEY, account_id integer REFERENCES account(id), display_name varchar_normal, - bio varchar_long, - is_public BOOLEAN DEFAULT FALSE + bio varchar_long ); CREATE TABLE account_reset_password ( @@ -29,8 +37,7 @@ CREATE TABLE account_verification ( id SERIAL PRIMARY KEY, account_id integer REFERENCES account(id), verification_token varchar_guid, - verification_token_expires_at TIMESTAMP, - verified BOOLEAN DEFAULT FALSE + verification_token_expires_at TIMESTAMP ); CREATE TABLE account_membership ( diff --git a/docs/database/0003_clip.sql b/docs/database/0003_clip.sql index ec8938f..a89625b 100644 --- a/docs/database/0003_clip.sql +++ b/docs/database/0003_clip.sql @@ -6,5 +6,5 @@ CREATE TABLE clip ( end_time numeric_20_11, title varchar_normal, description varchar_long, - isPublic BOOLEAN DEFAULT FALSE + sharable_status_id INTEGER NOT NULL REFERENCES sharable_status(id) ); From 3c1001acb77278e3cd6df92c2edef8dc16ed83fb Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Wed, 14 Aug 2024 18:55:07 -0500 Subject: [PATCH 10/73] Fix item_chapter reference --- docs/database/0001_init_podcasting_20_database.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/database/0001_init_podcasting_20_database.sql b/docs/database/0001_init_podcasting_20_database.sql index a313595..1fec15e 100644 --- a/docs/database/0001_init_podcasting_20_database.sql +++ b/docs/database/0001_init_podcasting_20_database.sql @@ -451,7 +451,7 @@ CREATE TABLE channel_image ( ) INHERITS (image_base); CREATE TABLE chapter_image ( - chapter_id INTEGER NOT NULL REFERENCES chapter(id) ON DELETE CASCADE + chapter_id INTEGER NOT NULL REFERENCES item_chapter(id) ON DELETE CASCADE ) INHERITS (image_base); CREATE TABLE item_image ( From bcaa8d8524df8e2f8a6d4cbe00e764ac5b1c0e8d Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Wed, 14 Aug 2024 18:55:41 -0500 Subject: [PATCH 11/73] Add playlist and playlist_item tables --- docs/database/0004_playlist.sql | 41 +++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 docs/database/0004_playlist.sql diff --git a/docs/database/0004_playlist.sql b/docs/database/0004_playlist.sql new file mode 100644 index 0000000..70590a0 --- /dev/null +++ b/docs/database/0004_playlist.sql @@ -0,0 +1,41 @@ + + +CREATE TABLE playlist ( + id SERIAL PRIMARY KEY, + id_text short_id UNIQUE NOT NULL, + account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, + sharable_status_id INTEGER NOT NULL REFERENCES sharable_status(id), + title varchar_normal, + description varchar_long, + is_default_favorites BOOLEAN DEFAULT FALSE, + is_public BOOLEAN DEFAULT FALSE, + item_count INTEGER DEFAULT 0 +); + +CREATE TABLE playlist_medium ( + playlist_id INTEGER NOT NULL REFERENCES playlist(id) ON DELETE CASCADE, + UNIQUE (playlist_id) +) INHERITS (medium_base); + +CREATE TABLE playlist_item_base ( + id SERIAL PRIMARY KEY, + playlist_id INTEGER NOT NULL REFERENCES playlist(id) ON DELETE CASCADE, + position numeric_20_11 NOT NULL, + UNIQUE (playlist_id, position) +); + +CREATE TABLE playlist_item_item ( + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE +) INHERITS (playlist_item_base); + +CREATE TABLE playlist_item_chapter ( + chapter_id INTEGER NOT NULL REFERENCES chapter(id) ON DELETE CASCADE +) INHERITS (playlist_item_base); + +CREATE TABLE playlist_item_clip ( + clip_id INTEGER NOT NULL REFERENCES clip(id) ON DELETE CASCADE +) INHERITS (playlist_item_base); + +CREATE TABLE playlist_item_soundbite ( + soundbite_id INTEGER NOT NULL REFERENCES soundbite(id) ON DELETE CASCADE +) INHERITS (playlist_item_base); From cb89380c1905b7dde050b5632bff5f3dd798c56b Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Wed, 14 Aug 2024 18:57:32 -0500 Subject: [PATCH 12/73] Rename clip table to item_clip --- docs/database/0003_clip.sql | 2 +- docs/database/0004_playlist.sql | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/database/0003_clip.sql b/docs/database/0003_clip.sql index a89625b..2beb9d8 100644 --- a/docs/database/0003_clip.sql +++ b/docs/database/0003_clip.sql @@ -1,4 +1,4 @@ -CREATE TABLE clip ( +CREATE TABLE item_clip ( id SERIAL PRIMARY KEY, id_text short_id UNIQUE NOT NULL, account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, diff --git a/docs/database/0004_playlist.sql b/docs/database/0004_playlist.sql index 70590a0..0ac3236 100644 --- a/docs/database/0004_playlist.sql +++ b/docs/database/0004_playlist.sql @@ -29,13 +29,13 @@ CREATE TABLE playlist_item_item ( ) INHERITS (playlist_item_base); CREATE TABLE playlist_item_chapter ( - chapter_id INTEGER NOT NULL REFERENCES chapter(id) ON DELETE CASCADE + chapter_id INTEGER NOT NULL REFERENCES item_chapter(id) ON DELETE CASCADE ) INHERITS (playlist_item_base); CREATE TABLE playlist_item_clip ( - clip_id INTEGER NOT NULL REFERENCES clip(id) ON DELETE CASCADE + clip_id INTEGER NOT NULL REFERENCES item_clip(id) ON DELETE CASCADE ) INHERITS (playlist_item_base); CREATE TABLE playlist_item_soundbite ( - soundbite_id INTEGER NOT NULL REFERENCES soundbite(id) ON DELETE CASCADE + soundbite_id INTEGER NOT NULL REFERENCES item_soundbite(id) ON DELETE CASCADE ) INHERITS (playlist_item_base); From 858c50523dc0fef4cbb411efc16059453b2bcff5 Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Wed, 14 Aug 2024 18:58:26 -0500 Subject: [PATCH 13/73] Remove extra linebreaks --- docs/database/0004_playlist.sql | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/database/0004_playlist.sql b/docs/database/0004_playlist.sql index 0ac3236..4ede95d 100644 --- a/docs/database/0004_playlist.sql +++ b/docs/database/0004_playlist.sql @@ -1,5 +1,3 @@ - - CREATE TABLE playlist ( id SERIAL PRIMARY KEY, id_text short_id UNIQUE NOT NULL, From ee460196752988ae198b75b2efe6ad70a7fabf86 Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Wed, 14 Aug 2024 19:23:31 -0500 Subject: [PATCH 14/73] Change short_id to short_id_v2 --- docs/database/0001_init_podcasting_20_database.sql | 14 +++++++++----- docs/database/0002_account.sql | 2 +- docs/database/0003_clip.sql | 2 +- docs/database/0004_playlist.sql | 2 +- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/docs/database/0001_init_podcasting_20_database.sql b/docs/database/0001_init_podcasting_20_database.sql index 1fec15e..b94445f 100644 --- a/docs/database/0001_init_podcasting_20_database.sql +++ b/docs/database/0001_init_podcasting_20_database.sql @@ -21,7 +21,11 @@ PODCASTING 2.0 DATABASE SCHEMA -- Helpers -CREATE DOMAIN short_id AS VARCHAR(14); +-- In the previous version of the app, short_id was 7-14 characters long. +-- To make migration to v2 easier, we will use a 15 character long short_id, +-- so we can easily distinguish between v1 and v2 short_ids. +CREATE DOMAIN short_id_v2 AS VARCHAR(15); + CREATE DOMAIN varchar_short AS VARCHAR(50); CREATE DOMAIN varchar_normal AS VARCHAR(255); CREATE DOMAIN varchar_long AS VARCHAR(2500); @@ -82,7 +86,7 @@ CREATE TABLE feed ( -- <channel> CREATE TABLE channel ( id SERIAL PRIMARY KEY, - id_text short_id UNIQUE NOT NULL, + id_text short_id_v2 UNIQUE NOT NULL, slug varchar_slug, feed_id INTEGER NOT NULL REFERENCES feed(id) ON DELETE CASCADE, podcast_index_id INTEGER UNIQUE NOT NULL, @@ -197,7 +201,7 @@ CREATE TABLE channel_trailer ( -- <item> CREATE TABLE item ( id SERIAL PRIMARY KEY, - id_text short_id UNIQUE NOT NULL, + id_text short_id_v2 UNIQUE NOT NULL, slug varchar_slug, channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, guid varchar_uri, -- <guid> @@ -263,7 +267,7 @@ CREATE TABLE item_chapters ( -- corresponds with jsonChapters.md example file CREATE TABLE item_chapter ( id SERIAL PRIMARY KEY, - text_id short_id UNIQUE NOT NULL, + text_id short_id_v2 UNIQUE NOT NULL, item_chapters_file_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, -- the hash is used for comparison, to determine if new chapters should be inserted @@ -334,7 +338,7 @@ CREATE TABLE item_season_episode ( -- <podcast:soundbite> CREATE TABLE item_soundbite ( id SERIAL PRIMARY KEY, - id_text short_id UNIQUE NOT NULL, + id_text short_id_v2 UNIQUE NOT NULL, item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, url varchar_url NOT NULL, start_time INTEGER NOT NULL, diff --git a/docs/database/0002_account.sql b/docs/database/0002_account.sql index 7b15125..329919a 100644 --- a/docs/database/0002_account.sql +++ b/docs/database/0002_account.sql @@ -7,7 +7,7 @@ INSERT INTO sharable_status (status) VALUES ('public'), ('unlisted'), ('private' CREATE TABLE account ( id SERIAL PRIMARY KEY, - id_text short_id UNIQUE NOT NULL, + id_text short_id_v2 UNIQUE NOT NULL, verified BOOLEAN DEFAULT FALSE, sharable_status_id INTEGER NOT NULL REFERENCES sharable_status(id) ); diff --git a/docs/database/0003_clip.sql b/docs/database/0003_clip.sql index 2beb9d8..42c2f3b 100644 --- a/docs/database/0003_clip.sql +++ b/docs/database/0003_clip.sql @@ -1,6 +1,6 @@ CREATE TABLE item_clip ( id SERIAL PRIMARY KEY, - id_text short_id UNIQUE NOT NULL, + id_text short_id_v2 UNIQUE NOT NULL, account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, start_time numeric_20_11 NOT NULL, end_time numeric_20_11, diff --git a/docs/database/0004_playlist.sql b/docs/database/0004_playlist.sql index 4ede95d..be5eb04 100644 --- a/docs/database/0004_playlist.sql +++ b/docs/database/0004_playlist.sql @@ -1,6 +1,6 @@ CREATE TABLE playlist ( id SERIAL PRIMARY KEY, - id_text short_id UNIQUE NOT NULL, + id_text short_id_v2 UNIQUE NOT NULL, account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, sharable_status_id INTEGER NOT NULL REFERENCES sharable_status(id), title varchar_normal, From 54b4edbff23c1c7d76d68ad8684318c27a8b8c0e Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Wed, 14 Aug 2024 19:58:27 -0500 Subject: [PATCH 15/73] Rename item_clip to clip --- docs/database/0003_clip.sql | 2 +- docs/database/0004_playlist.sql | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/database/0003_clip.sql b/docs/database/0003_clip.sql index 42c2f3b..4f62dfe 100644 --- a/docs/database/0003_clip.sql +++ b/docs/database/0003_clip.sql @@ -1,4 +1,4 @@ -CREATE TABLE item_clip ( +CREATE TABLE clip ( id SERIAL PRIMARY KEY, id_text short_id_v2 UNIQUE NOT NULL, account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, diff --git a/docs/database/0004_playlist.sql b/docs/database/0004_playlist.sql index be5eb04..be3885c 100644 --- a/docs/database/0004_playlist.sql +++ b/docs/database/0004_playlist.sql @@ -30,8 +30,8 @@ CREATE TABLE playlist_item_chapter ( chapter_id INTEGER NOT NULL REFERENCES item_chapter(id) ON DELETE CASCADE ) INHERITS (playlist_item_base); -CREATE TABLE playlist_item_clip ( - clip_id INTEGER NOT NULL REFERENCES item_clip(id) ON DELETE CASCADE +CREATE TABLE playlist_clip ( + clip_id INTEGER NOT NULL REFERENCES clip(id) ON DELETE CASCADE ) INHERITS (playlist_item_base); CREATE TABLE playlist_item_soundbite ( From 02436e6c0d85762e5c3e7c9af47d6da6d05c2981 Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Wed, 14 Aug 2024 19:58:52 -0500 Subject: [PATCH 16/73] Add playlist_item_item_add_by_rss table --- docs/database/0004_playlist.sql | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/database/0004_playlist.sql b/docs/database/0004_playlist.sql index be3885c..75818ac 100644 --- a/docs/database/0004_playlist.sql +++ b/docs/database/0004_playlist.sql @@ -26,6 +26,10 @@ CREATE TABLE playlist_item_item ( item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE ) INHERITS (playlist_item_base); +CREATE TABLE playlist_item_item_add_by_rss ( + item_data jsonb NOT NULL +) INHERITS (playlist_item_base); + CREATE TABLE playlist_item_chapter ( chapter_id INTEGER NOT NULL REFERENCES item_chapter(id) ON DELETE CASCADE ) INHERITS (playlist_item_base); From b9eb4a6e26adfa4711c96923f2c1c71d6a59483f Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Wed, 14 Aug 2024 20:03:55 -0500 Subject: [PATCH 17/73] Rename playlist_item to playlist_content --- docs/database/0004_playlist.sql | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/database/0004_playlist.sql b/docs/database/0004_playlist.sql index 75818ac..70c0668 100644 --- a/docs/database/0004_playlist.sql +++ b/docs/database/0004_playlist.sql @@ -15,29 +15,29 @@ CREATE TABLE playlist_medium ( UNIQUE (playlist_id) ) INHERITS (medium_base); -CREATE TABLE playlist_item_base ( +CREATE TABLE playlist_content_base ( id SERIAL PRIMARY KEY, playlist_id INTEGER NOT NULL REFERENCES playlist(id) ON DELETE CASCADE, position numeric_20_11 NOT NULL, UNIQUE (playlist_id, position) ); -CREATE TABLE playlist_item_item ( +CREATE TABLE playlist_content_item ( item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE -) INHERITS (playlist_item_base); +) INHERITS (playlist_content_base); -CREATE TABLE playlist_item_item_add_by_rss ( +CREATE TABLE playlist_content_item_add_by_rss ( item_data jsonb NOT NULL -) INHERITS (playlist_item_base); +) INHERITS (playlist_content_base); -CREATE TABLE playlist_item_chapter ( +CREATE TABLE playlist_content_chapter ( chapter_id INTEGER NOT NULL REFERENCES item_chapter(id) ON DELETE CASCADE -) INHERITS (playlist_item_base); +) INHERITS (playlist_content_base); CREATE TABLE playlist_clip ( clip_id INTEGER NOT NULL REFERENCES clip(id) ON DELETE CASCADE -) INHERITS (playlist_item_base); +) INHERITS (playlist_content_base); -CREATE TABLE playlist_item_soundbite ( +CREATE TABLE playlist_content_soundbite ( soundbite_id INTEGER NOT NULL REFERENCES item_soundbite(id) ON DELETE CASCADE -) INHERITS (playlist_item_base); +) INHERITS (playlist_content_base); From 4478fe31cfa850d9805258b6160675a5dd929aa8 Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Wed, 14 Aug 2024 21:38:03 -0500 Subject: [PATCH 18/73] More initial helpers to their own sql file --- docs/database/0000_init_helpers.sql | 32 +++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 docs/database/0000_init_helpers.sql diff --git a/docs/database/0000_init_helpers.sql b/docs/database/0000_init_helpers.sql new file mode 100644 index 0000000..e837537 --- /dev/null +++ b/docs/database/0000_init_helpers.sql @@ -0,0 +1,32 @@ +-- Helpers + +-- In the previous version of the app, short_id was 7-14 characters long. +-- To make migration to v2 easier, we will use a 15 character long short_id, +-- so we can easily distinguish between v1 and v2 short_ids. +CREATE DOMAIN short_id_v2 AS VARCHAR(15); + +CREATE DOMAIN varchar_short AS VARCHAR(50); +CREATE DOMAIN varchar_normal AS VARCHAR(255); +CREATE DOMAIN varchar_long AS VARCHAR(2500); + +CREATE DOMAIN varchar_email AS VARCHAR(255) CHECK (VALUE ~ '^.+@.+\..+$'); +CREATE DOMAIN varchar_fqdn AS VARCHAR(253); +CREATE DOMAIN varchar_guid AS VARCHAR(36); +CREATE DOMAIN varchar_password AS VARCHAR(36); +CREATE DOMAIN varchar_slug AS VARCHAR(100); +CREATE DOMAIN varchar_uri AS VARCHAR(2083); +CREATE DOMAIN varchar_url AS VARCHAR(2083) CHECK (VALUE ~ '^https?://|^http?://'); + +CREATE DOMAIN server_time AS BIGINT; +CREATE DOMAIN server_time_with_default AS BIGINT DEFAULT EXTRACT(EPOCH FROM NOW()); + +CREATE DOMAIN numeric_20_11 AS NUMERIC(20, 11); + +-- Function to set created_at and updated_at +CREATE OR REPLACE FUNCTION set_updated_at_field() +RETURNS TRIGGER AS $$ +BEGIN + NEW.updated_at := EXTRACT(EPOCH FROM NOW()); + RETURN NEW; +END; +$$ LANGUAGE plpgsql; From e7911f3b09cf413907d2528c07158c3251a6b6c3 Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Wed, 14 Aug 2024 21:38:32 -0500 Subject: [PATCH 19/73] Add updated_at handling to a couple columns --- .../0001_init_podcasting_20_database.sql | 92 +++++++++---------- 1 file changed, 41 insertions(+), 51 deletions(-) diff --git a/docs/database/0001_init_podcasting_20_database.sql b/docs/database/0001_init_podcasting_20_database.sql index b94445f..47fdb51 100644 --- a/docs/database/0001_init_podcasting_20_database.sql +++ b/docs/database/0001_init_podcasting_20_database.sql @@ -19,68 +19,58 @@ PODCASTING 2.0 DATABASE SCHEMA */ --- Helpers - --- In the previous version of the app, short_id was 7-14 characters long. --- To make migration to v2 easier, we will use a 15 character long short_id, --- so we can easily distinguish between v1 and v2 short_ids. -CREATE DOMAIN short_id_v2 AS VARCHAR(15); - -CREATE DOMAIN varchar_short AS VARCHAR(50); -CREATE DOMAIN varchar_normal AS VARCHAR(255); -CREATE DOMAIN varchar_long AS VARCHAR(2500); - -CREATE DOMAIN varchar_email AS VARCHAR(255) CHECK (VALUE ~ '^.+@.+\..+$'); -CREATE DOMAIN varchar_fqdn AS VARCHAR(253); -CREATE DOMAIN varchar_guid AS VARCHAR(36); -CREATE DOMAIN varchar_password AS VARCHAR(36); -CREATE DOMAIN varchar_slug AS VARCHAR(100); -CREATE DOMAIN varchar_uri AS VARCHAR(2083); -CREATE DOMAIN varchar_url AS VARCHAR(2083) CHECK (VALUE ~ '^https?://|^http?://'); - -CREATE DOMAIN numeric_20_11 AS NUMERIC(20, 11); - -- Init tables --- TODO: should every table have a created_at and updated_at column? --- or only some tables? or none? - --** FEED > FLAG STATUS CREATE TABLE feed_flag_status ( id SERIAL PRIMARY KEY, - status TEXT UNIQUE CHECK (status IN ('none', 'spam', 'takedown', 'other', 'always-allow')) + status TEXT UNIQUE CHECK (status IN ('none', 'spam', 'takedown', 'other', 'always-allow')), + created_at server_time_with_default, + updated_at server_time_with_default ); +CREATE TRIGGER set_updated_at_feed_flag_status +BEFORE UPDATE ON feed +FOR EACH ROW +EXECUTE FUNCTION set_updated_at_field(); + INSERT INTO feed_flag_status (status) VALUES ('none'), ('spam'), ('takedown'), ('other'), ('always-allow'); --** FEED CREATE TABLE feed ( - id SERIAL PRIMARY KEY, - url varchar_url UNIQUE NOT NULL, - - -- 0 to 5, 0 will only be parsed when PI API reports an update, - -- higher parsing_priority will be parsed more frequently on a schedule. - parsing_priority INTEGER DEFAULT 0, - last_http_status INTEGER, - last_crawl_time TIMESTAMP, - last_good_http_status_time TIMESTAMP, - last_parse_time TIMESTAMP, - last_update_time TIMESTAMP, - crawl_errors INTEGER DEFAULT 0, - parse_errors INTEGER DEFAULT 0, - - feed_flag_status_id INTEGER NOT NULL REFERENCES feed_flag_status(id), - - -- Used to prevent another thread from parsing the same feed. - -- Set to current time at beginning of parsing, and NULL at end of parsing. - -- This is to prevent multiple threads from parsing the same feed. - -- If is_parsing is over X minutes old, assume last parsing failed and proceed to parse. - is_parsing TIMESTAMP, - container_id VARCHAR(12) + id SERIAL PRIMARY KEY, + url varchar_url UNIQUE NOT NULL, + + -- 0 to 5, 0 will only be parsed when PI API reports an update, + -- higher parsing_priority will be parsed more frequently on a schedule. + parsing_priority INTEGER DEFAULT 0, + last_http_status INTEGER, + last_crawl_time server_time, + last_good_http_status_time server_time, + last_parse_time server_time, + last_update_time server_time, + crawl_errors INTEGER DEFAULT 0, + parse_errors INTEGER DEFAULT 0, + + feed_flag_status_id INTEGER NOT NULL REFERENCES feed_flag_status(id), + + -- Used to prevent another thread from parsing the same feed. + -- Set to current time at beginning of parsing, and NULL at end of parsing. + -- This is to prevent multiple threads from parsing the same feed. + -- If is_parsing is over X minutes old, assume last parsing failed and proceed to parse. + is_parsing server_time, + container_id VARCHAR(12), + created_at server_time_with_default, + updated_at server_time_with_default ); +CREATE TRIGGER set_updated_at_feed +BEFORE UPDATE ON feed +FOR EACH ROW +EXECUTE FUNCTION set_updated_at_field(); + --** CHANNEL -- <channel> @@ -256,10 +246,10 @@ CREATE TABLE item_chapters ( url varchar_url NOT NULL, type varchar_short NOT NULL, last_http_status INTEGER, - last_crawl_time TIMESTAMP, - last_good_http_status_time TIMESTAMP, - last_parse_time TIMESTAMP, - last_update_time TIMESTAMP, + last_crawl_time server_time, + last_good_http_status_time server_time, + last_parse_time server_time, + last_update_time server_time, crawl_errors INTEGER DEFAULT 0, parse_errors INTEGER DEFAULT 0 ); From 075f34d34b4d69e0621e600271d3c7998b59fc6b Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Wed, 14 Aug 2024 21:38:48 -0500 Subject: [PATCH 20/73] Add now_playing_content table --- docs/database/0005_now_playing_content.sql | 72 ++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 docs/database/0005_now_playing_content.sql diff --git a/docs/database/0005_now_playing_content.sql b/docs/database/0005_now_playing_content.sql new file mode 100644 index 0000000..cdfb2ea --- /dev/null +++ b/docs/database/0005_now_playing_content.sql @@ -0,0 +1,72 @@ +CREATE TABLE now_playing_content_base ( + id SERIAL PRIMARY KEY, + account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, + playback_position numeric_20_11 NOT NULL +); + +CREATE TABLE now_playing_content_item ( + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + UNIQUE (account_id) +) INHERITS (now_playing_content_base); + +CREATE TABLE now_playing_content_item_add_by_rss ( + item_data jsonb NOT NULL, + UNIQUE (account_id) +) INHERITS (now_playing_content_base); + +CREATE TABLE now_playing_content_item_chapter ( + item_chapter_id INTEGER NOT NULL REFERENCES item_chapter(id) ON DELETE CASCADE, + UNIQUE (account_id) +) INHERITS (now_playing_content_base); + +CREATE TABLE now_playing_content_clip ( + clip_id INTEGER NOT NULL REFERENCES clip(id) ON DELETE CASCADE, + UNIQUE (account_id) +) INHERITS (now_playing_content_base); + +CREATE TABLE now_playing_content_item_soundbite ( + soundbite_id INTEGER NOT NULL REFERENCES item_soundbite(id) ON DELETE CASCADE, + UNIQUE (account_id) +) INHERITS (now_playing_content_base); + +/* Ensure that an account can only have one of any type assigned to it at a time */ + +CREATE OR REPLACE FUNCTION check_account_id_uniqueness() +RETURNS TRIGGER AS $$ +BEGIN + IF EXISTS ( + SELECT 1 FROM now_playing_content_item WHERE account_id = NEW.account_id + UNION + SELECT 1 FROM now_playing_content_item_add_by_rss WHERE account_id = NEW.account_id + UNION + SELECT 1 FROM now_playing_content_item_chapter WHERE account_id = NEW.account_id + UNION + SELECT 1 FROM now_playing_content_clip WHERE account_id = NEW.account_id + UNION + SELECT 1 FROM now_playing_content_soundbite WHERE account_id = NEW.account_id + ) THEN + RAISE EXCEPTION 'account_id % already exists in another table', NEW.account_id; + END IF; + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +CREATE TRIGGER check_account_id_uniqueness_item +BEFORE INSERT ON now_playing_content_item +FOR EACH ROW EXECUTE FUNCTION check_account_id_uniqueness(); + +CREATE TRIGGER check_account_id_uniqueness_item_add_by_rss +BEFORE INSERT ON now_playing_content_item_add_by_rss +FOR EACH ROW EXECUTE FUNCTION check_account_id_uniqueness(); + +CREATE TRIGGER check_account_id_uniqueness_item_chapter +BEFORE INSERT ON now_playing_content_item_chapter +FOR EACH ROW EXECUTE FUNCTION check_account_id_uniqueness(); + +CREATE TRIGGER check_account_id_uniqueness_clip +BEFORE INSERT ON now_playing_content_clip +FOR EACH ROW EXECUTE FUNCTION check_account_id_uniqueness(); + +CREATE TRIGGER check_account_id_uniqueness_soundbite +BEFORE INSERT ON now_playing_content_soundbite +FOR EACH ROW EXECUTE FUNCTION check_account_id_uniqueness(); From 1c45c623e3c8d12b86d04bde5917a11631d572f5 Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Wed, 14 Aug 2024 21:39:32 -0500 Subject: [PATCH 21/73] Add queue_content table --- docs/database/0006_queue_content.sql | 30 ++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 docs/database/0006_queue_content.sql diff --git a/docs/database/0006_queue_content.sql b/docs/database/0006_queue_content.sql new file mode 100644 index 0000000..68ca125 --- /dev/null +++ b/docs/database/0006_queue_content.sql @@ -0,0 +1,30 @@ +CREATE TABLE queue_content_base ( + id SERIAL PRIMARY KEY, + account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, + position numeric_20_11 NOT NULL +); + +CREATE TABLE queue_content_item ( + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + UNIQUE (account_id) +) INHERITS (queue_content_base); + +CREATE TABLE queue_content_item_add_by_rss ( + item_data jsonb NOT NULL, + UNIQUE (account_id) +) INHERITS (queue_content_base); + +CREATE TABLE queue_content_item_chapter ( + item_chapter_id INTEGER NOT NULL REFERENCES item_chapter(id) ON DELETE CASCADE, + UNIQUE (account_id) +) INHERITS (queue_content_base); + +CREATE TABLE queue_clip ( + clip_id INTEGER NOT NULL REFERENCES clip(id) ON DELETE CASCADE, + UNIQUE (account_id) +) INHERITS (queue_content_base); + +CREATE TABLE queue_soundbite ( + soundbite_id INTEGER NOT NULL REFERENCES item_soundbite(id) ON DELETE CASCADE, + UNIQUE (account_id) +) INHERITS (queue_content_base); From 59f68272aa0b0e0d047ac743552bb1cd34ab398e Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Wed, 14 Aug 2024 21:56:13 -0500 Subject: [PATCH 22/73] Fix invalid table names --- docs/database/0001_init_podcasting_20_database.sql | 2 +- docs/database/0005_now_playing_content.sql | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/database/0001_init_podcasting_20_database.sql b/docs/database/0001_init_podcasting_20_database.sql index 47fdb51..04a051e 100644 --- a/docs/database/0001_init_podcasting_20_database.sql +++ b/docs/database/0001_init_podcasting_20_database.sql @@ -31,7 +31,7 @@ CREATE TABLE feed_flag_status ( ); CREATE TRIGGER set_updated_at_feed_flag_status -BEFORE UPDATE ON feed +BEFORE UPDATE ON feed_flag_status FOR EACH ROW EXECUTE FUNCTION set_updated_at_field(); diff --git a/docs/database/0005_now_playing_content.sql b/docs/database/0005_now_playing_content.sql index cdfb2ea..c0dba01 100644 --- a/docs/database/0005_now_playing_content.sql +++ b/docs/database/0005_now_playing_content.sql @@ -43,7 +43,7 @@ BEGIN UNION SELECT 1 FROM now_playing_content_clip WHERE account_id = NEW.account_id UNION - SELECT 1 FROM now_playing_content_soundbite WHERE account_id = NEW.account_id + SELECT 1 FROM now_playing_content_item_soundbite WHERE account_id = NEW.account_id ) THEN RAISE EXCEPTION 'account_id % already exists in another table', NEW.account_id; END IF; @@ -68,5 +68,5 @@ BEFORE INSERT ON now_playing_content_clip FOR EACH ROW EXECUTE FUNCTION check_account_id_uniqueness(); CREATE TRIGGER check_account_id_uniqueness_soundbite -BEFORE INSERT ON now_playing_content_soundbite +BEFORE INSERT ON now_playing_content_item_soundbite FOR EACH ROW EXECUTE FUNCTION check_account_id_uniqueness(); From 38c2bf743c7e659b4f8360f5e88579107ec12081 Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Fri, 16 Aug 2024 19:45:01 -0500 Subject: [PATCH 23/73] Add cascade delete rules to account sub-tables --- docs/database/0002_account.sql | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/database/0002_account.sql b/docs/database/0002_account.sql index 329919a..c4c317c 100644 --- a/docs/database/0002_account.sql +++ b/docs/database/0002_account.sql @@ -14,28 +14,28 @@ CREATE TABLE account ( CREATE TABLE account_credentials ( id SERIAL PRIMARY KEY, - account_id integer REFERENCES account(id), + account_id integer REFERENCES account(id) ON DELETE CASCADE, email varchar_email UNIQUE NOT NULL, password varchar_password NOT NULL ); CREATE TABLE account_profile ( id SERIAL PRIMARY KEY, - account_id integer REFERENCES account(id), + account_id integer REFERENCES account(id) ON DELETE CASCADE, display_name varchar_normal, bio varchar_long ); CREATE TABLE account_reset_password ( id SERIAL PRIMARY KEY, - account_id integer REFERENCES account(id), + account_id integer REFERENCES account(id) ON DELETE CASCADE, reset_token varchar_guid, reset_token_expires_at TIMESTAMP ); CREATE TABLE account_verification ( id SERIAL PRIMARY KEY, - account_id integer REFERENCES account(id), + account_id integer REFERENCES account(id) ON DELETE CASCADE, verification_token varchar_guid, verification_token_expires_at TIMESTAMP ); @@ -49,14 +49,14 @@ INSERT INTO account_membership (tier) VALUES ('trial'), ('basic'); CREATE TABLE account_membership_status ( id SERIAL PRIMARY KEY, - account_id INTEGER NOT NULL REFERENCES account(id), + account_id integer REFERENCES account(id) ON DELETE CASCADE, account_membership_id INTEGER NOT NULL REFERENCES account_membership(id), membership_expires_at TIMESTAMP ); CREATE TABLE account_admin_roles ( id SERIAL PRIMARY KEY, - account_id INTEGER NOT NULL REFERENCES account(id), + account_id integer REFERENCES account(id) ON DELETE CASCADE, dev_admin BOOLEAN DEFAULT FALSE, podping_admin BOOLEAN DEFAULT FALSE ); From 8264b6b92bad56523afa84e83b7bf881f54bb198 Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Fri, 16 Aug 2024 20:44:02 -0500 Subject: [PATCH 24/73] Continue initial database --- docs/database/0000_init_helpers.sql | 2 + .../0001_init_podcasting_20_database.sql | 12 ++-- docs/database/0003_clip.sql | 7 +- docs/database/0004_playlist.sql | 8 +-- docs/database/0005_now_playing_content.sql | 72 ------------------- docs/database/0005_queue_resource.sql | 34 +++++++++ docs/database/0006_queue_content.sql | 30 -------- 7 files changed, 50 insertions(+), 115 deletions(-) delete mode 100644 docs/database/0005_now_playing_content.sql create mode 100644 docs/database/0005_queue_resource.sql delete mode 100644 docs/database/0006_queue_content.sql diff --git a/docs/database/0000_init_helpers.sql b/docs/database/0000_init_helpers.sql index e837537..7a946ff 100644 --- a/docs/database/0000_init_helpers.sql +++ b/docs/database/0000_init_helpers.sql @@ -20,6 +20,8 @@ CREATE DOMAIN varchar_url AS VARCHAR(2083) CHECK (VALUE ~ '^https?://|^http?://' CREATE DOMAIN server_time AS BIGINT; CREATE DOMAIN server_time_with_default AS BIGINT DEFAULT EXTRACT(EPOCH FROM NOW()); +CREATE DOMAIN media_player_time AS NUMERIC(10, 2); +CREATE DOMAIN list_position AS NUMERIC(22, 21); CREATE DOMAIN numeric_20_11 AS NUMERIC(20, 11); -- Function to set created_at and updated_at diff --git a/docs/database/0001_init_podcasting_20_database.sql b/docs/database/0001_init_podcasting_20_database.sql index 04a051e..20d1d10 100644 --- a/docs/database/0001_init_podcasting_20_database.sql +++ b/docs/database/0001_init_podcasting_20_database.sql @@ -264,8 +264,8 @@ CREATE TABLE item_chapter ( -- after re-parsing an existing chapters file. hash varchar_guid NOT NULL, - start_time numeric_20_11 NOT NULL, - end_time numeric_20_11, + start_time media_player_time NOT NULL, + end_time media_player_time, title varchar_normal, web_url varchar_url, table_of_contents BOOLEAN DEFAULT TRUE @@ -280,7 +280,7 @@ CREATE TABLE item_enclosure ( item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, type varchar_short NOT NULL, length INTEGER, - bitrate numeric_20_11, + bitrate INTEGER, height INTEGER, language varchar_short, title varchar_short, @@ -320,7 +320,7 @@ CREATE TABLE item_season_episode ( id SERIAL PRIMARY KEY, item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, display varchar_short, - episode_number numeric_20_11 NOT NULL + episode_number FLOAT NOT NULL ); --** ITEM > SOUNDBITE @@ -616,7 +616,7 @@ CREATE TABLE value_tag_base ( id SERIAL PRIMARY KEY, type varchar_short NOT NULL, method varchar_short NOT NULL, - suggested numeric_20_11 + suggested FLOAT ); CREATE TABLE channel_value_tag ( @@ -635,7 +635,7 @@ CREATE TABLE value_tag_receipient ( value_tag_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, type varchar_short NOT NULL, address varchar_long NOT NULL, - split numeric_20_11 NOT NULL, + split FLOAT NOT NULL, name varchar_normal, custom_key varchar_long, custom_value varchar_long, diff --git a/docs/database/0003_clip.sql b/docs/database/0003_clip.sql index 4f62dfe..1c0f6ee 100644 --- a/docs/database/0003_clip.sql +++ b/docs/database/0003_clip.sql @@ -1,9 +1,10 @@ -CREATE TABLE clip ( +CREATE TABLE account_clip ( id SERIAL PRIMARY KEY, id_text short_id_v2 UNIQUE NOT NULL, account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, - start_time numeric_20_11 NOT NULL, - end_time numeric_20_11, + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + start_time media_player_time NOT NULL, + end_time media_player_time, title varchar_normal, description varchar_long, sharable_status_id INTEGER NOT NULL REFERENCES sharable_status(id) diff --git a/docs/database/0004_playlist.sql b/docs/database/0004_playlist.sql index 70c0668..318f3fb 100644 --- a/docs/database/0004_playlist.sql +++ b/docs/database/0004_playlist.sql @@ -18,8 +18,8 @@ CREATE TABLE playlist_medium ( CREATE TABLE playlist_content_base ( id SERIAL PRIMARY KEY, playlist_id INTEGER NOT NULL REFERENCES playlist(id) ON DELETE CASCADE, - position numeric_20_11 NOT NULL, - UNIQUE (playlist_id, position) + list_position list_position NOT NULL CHECK (list_position != 0 OR list_position = 0::numeric), + UNIQUE (playlist_id, list_position) ); CREATE TABLE playlist_content_item ( @@ -34,8 +34,8 @@ CREATE TABLE playlist_content_chapter ( chapter_id INTEGER NOT NULL REFERENCES item_chapter(id) ON DELETE CASCADE ) INHERITS (playlist_content_base); -CREATE TABLE playlist_clip ( - clip_id INTEGER NOT NULL REFERENCES clip(id) ON DELETE CASCADE +CREATE TABLE playlist_content_account_clip ( + account_clip_id INTEGER NOT NULL REFERENCES account_clip(id) ON DELETE CASCADE ) INHERITS (playlist_content_base); CREATE TABLE playlist_content_soundbite ( diff --git a/docs/database/0005_now_playing_content.sql b/docs/database/0005_now_playing_content.sql deleted file mode 100644 index c0dba01..0000000 --- a/docs/database/0005_now_playing_content.sql +++ /dev/null @@ -1,72 +0,0 @@ -CREATE TABLE now_playing_content_base ( - id SERIAL PRIMARY KEY, - account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, - playback_position numeric_20_11 NOT NULL -); - -CREATE TABLE now_playing_content_item ( - item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, - UNIQUE (account_id) -) INHERITS (now_playing_content_base); - -CREATE TABLE now_playing_content_item_add_by_rss ( - item_data jsonb NOT NULL, - UNIQUE (account_id) -) INHERITS (now_playing_content_base); - -CREATE TABLE now_playing_content_item_chapter ( - item_chapter_id INTEGER NOT NULL REFERENCES item_chapter(id) ON DELETE CASCADE, - UNIQUE (account_id) -) INHERITS (now_playing_content_base); - -CREATE TABLE now_playing_content_clip ( - clip_id INTEGER NOT NULL REFERENCES clip(id) ON DELETE CASCADE, - UNIQUE (account_id) -) INHERITS (now_playing_content_base); - -CREATE TABLE now_playing_content_item_soundbite ( - soundbite_id INTEGER NOT NULL REFERENCES item_soundbite(id) ON DELETE CASCADE, - UNIQUE (account_id) -) INHERITS (now_playing_content_base); - -/* Ensure that an account can only have one of any type assigned to it at a time */ - -CREATE OR REPLACE FUNCTION check_account_id_uniqueness() -RETURNS TRIGGER AS $$ -BEGIN - IF EXISTS ( - SELECT 1 FROM now_playing_content_item WHERE account_id = NEW.account_id - UNION - SELECT 1 FROM now_playing_content_item_add_by_rss WHERE account_id = NEW.account_id - UNION - SELECT 1 FROM now_playing_content_item_chapter WHERE account_id = NEW.account_id - UNION - SELECT 1 FROM now_playing_content_clip WHERE account_id = NEW.account_id - UNION - SELECT 1 FROM now_playing_content_item_soundbite WHERE account_id = NEW.account_id - ) THEN - RAISE EXCEPTION 'account_id % already exists in another table', NEW.account_id; - END IF; - RETURN NEW; -END; -$$ LANGUAGE plpgsql; - -CREATE TRIGGER check_account_id_uniqueness_item -BEFORE INSERT ON now_playing_content_item -FOR EACH ROW EXECUTE FUNCTION check_account_id_uniqueness(); - -CREATE TRIGGER check_account_id_uniqueness_item_add_by_rss -BEFORE INSERT ON now_playing_content_item_add_by_rss -FOR EACH ROW EXECUTE FUNCTION check_account_id_uniqueness(); - -CREATE TRIGGER check_account_id_uniqueness_item_chapter -BEFORE INSERT ON now_playing_content_item_chapter -FOR EACH ROW EXECUTE FUNCTION check_account_id_uniqueness(); - -CREATE TRIGGER check_account_id_uniqueness_clip -BEFORE INSERT ON now_playing_content_clip -FOR EACH ROW EXECUTE FUNCTION check_account_id_uniqueness(); - -CREATE TRIGGER check_account_id_uniqueness_soundbite -BEFORE INSERT ON now_playing_content_item_soundbite -FOR EACH ROW EXECUTE FUNCTION check_account_id_uniqueness(); diff --git a/docs/database/0005_queue_resource.sql b/docs/database/0005_queue_resource.sql new file mode 100644 index 0000000..7fca37c --- /dev/null +++ b/docs/database/0005_queue_resource.sql @@ -0,0 +1,34 @@ +CREATE TABLE queue_resource_base ( + id SERIAL PRIMARY KEY, + account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, + list_position list_position NOT NULL CHECK (list_position != 0 OR list_position = 0::numeric), + UNIQUE (account_id, list_position), + playback_position media_player_time NOT NULL DEFAULT 0, + media_file_duration FLOAT NOT NULL DEFAULT 0, + completed BOOLEAN NOT NULL DEFAULT FALSE +); + +CREATE TABLE queue_resource_item ( + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + UNIQUE (account_id) +) INHERITS (queue_resource_base); + +CREATE TABLE queue_resource_item_add_by_rss ( + item_data jsonb NOT NULL, + UNIQUE (account_id) +) INHERITS (queue_resource_base); + +CREATE TABLE queue_resource_item_chapter ( + item_chapter_id INTEGER NOT NULL REFERENCES item_chapter(id) ON DELETE CASCADE, + UNIQUE (account_id) +) INHERITS (queue_resource_base); + +CREATE TABLE queue_resource_account_clip ( + account_clip_id INTEGER NOT NULL REFERENCES account_clip(id) ON DELETE CASCADE, + UNIQUE (account_id) +) INHERITS (queue_resource_base); + +CREATE TABLE queue_resource_item_soundbite ( + soundbite_id INTEGER NOT NULL REFERENCES item_soundbite(id) ON DELETE CASCADE, + UNIQUE (account_id) +) INHERITS (queue_resource_base); diff --git a/docs/database/0006_queue_content.sql b/docs/database/0006_queue_content.sql deleted file mode 100644 index 68ca125..0000000 --- a/docs/database/0006_queue_content.sql +++ /dev/null @@ -1,30 +0,0 @@ -CREATE TABLE queue_content_base ( - id SERIAL PRIMARY KEY, - account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, - position numeric_20_11 NOT NULL -); - -CREATE TABLE queue_content_item ( - item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, - UNIQUE (account_id) -) INHERITS (queue_content_base); - -CREATE TABLE queue_content_item_add_by_rss ( - item_data jsonb NOT NULL, - UNIQUE (account_id) -) INHERITS (queue_content_base); - -CREATE TABLE queue_content_item_chapter ( - item_chapter_id INTEGER NOT NULL REFERENCES item_chapter(id) ON DELETE CASCADE, - UNIQUE (account_id) -) INHERITS (queue_content_base); - -CREATE TABLE queue_clip ( - clip_id INTEGER NOT NULL REFERENCES clip(id) ON DELETE CASCADE, - UNIQUE (account_id) -) INHERITS (queue_content_base); - -CREATE TABLE queue_soundbite ( - soundbite_id INTEGER NOT NULL REFERENCES item_soundbite(id) ON DELETE CASCADE, - UNIQUE (account_id) -) INHERITS (queue_content_base); From 3d1b899a5d3a0d3664d4b61849fe40258426904e Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Fri, 16 Aug 2024 21:10:11 -0500 Subject: [PATCH 25/73] Add missing id serial to category --- docs/database/0001_init_podcasting_20_database.sql | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/database/0001_init_podcasting_20_database.sql b/docs/database/0001_init_podcasting_20_database.sql index 20d1d10..113d1a5 100644 --- a/docs/database/0001_init_podcasting_20_database.sql +++ b/docs/database/0001_init_podcasting_20_database.sql @@ -125,6 +125,7 @@ CREATE TABLE channel_about ( ); CREATE TABLE category ( + id SERIAL PRIMARY KEY, node_text varchar_normal NOT NULL, -- <itunes:category> display_name varchar_normal NOT NULL, -- our own display name for the category slug varchar_normal NOT NULL From e667ce0eff592102ba13d56c7b381ba5fdfb0b4b Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Fri, 16 Aug 2024 21:12:57 -0500 Subject: [PATCH 26/73] Rename playlist_content to playlist_resource --- docs/database/0004_playlist.sql | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/database/0004_playlist.sql b/docs/database/0004_playlist.sql index 318f3fb..b0f07c4 100644 --- a/docs/database/0004_playlist.sql +++ b/docs/database/0004_playlist.sql @@ -15,29 +15,29 @@ CREATE TABLE playlist_medium ( UNIQUE (playlist_id) ) INHERITS (medium_base); -CREATE TABLE playlist_content_base ( +CREATE TABLE playlist_resource_base ( id SERIAL PRIMARY KEY, playlist_id INTEGER NOT NULL REFERENCES playlist(id) ON DELETE CASCADE, list_position list_position NOT NULL CHECK (list_position != 0 OR list_position = 0::numeric), UNIQUE (playlist_id, list_position) ); -CREATE TABLE playlist_content_item ( +CREATE TABLE playlist_resource_item ( item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE -) INHERITS (playlist_content_base); +) INHERITS (playlist_resource_base); -CREATE TABLE playlist_content_item_add_by_rss ( +CREATE TABLE playlist_resource_item_add_by_rss ( item_data jsonb NOT NULL -) INHERITS (playlist_content_base); +) INHERITS (playlist_resource_base); -CREATE TABLE playlist_content_chapter ( +CREATE TABLE playlist_resource_chapter ( chapter_id INTEGER NOT NULL REFERENCES item_chapter(id) ON DELETE CASCADE -) INHERITS (playlist_content_base); +) INHERITS (playlist_resource_base); -CREATE TABLE playlist_content_account_clip ( +CREATE TABLE playlist_resource_account_clip ( account_clip_id INTEGER NOT NULL REFERENCES account_clip(id) ON DELETE CASCADE -) INHERITS (playlist_content_base); +) INHERITS (playlist_resource_base); -CREATE TABLE playlist_content_soundbite ( +CREATE TABLE playlist_resource_soundbite ( soundbite_id INTEGER NOT NULL REFERENCES item_soundbite(id) ON DELETE CASCADE -) INHERITS (playlist_content_base); +) INHERITS (playlist_resource_base); From 6787cee3c8b68293527529fd6bb9d8ce98f23886 Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Fri, 16 Aug 2024 23:21:04 -0500 Subject: [PATCH 27/73] Replace most INHERITS tables with separate tables --- .../0001_init_podcasting_20_database.sql | 697 +++++++++++------- docs/database/0003_clip.sql | 2 +- docs/database/0004_playlist.sql | 53 +- docs/database/0005_queue_resource.sql | 39 +- 4 files changed, 507 insertions(+), 284 deletions(-) diff --git a/docs/database/0001_init_podcasting_20_database.sql b/docs/database/0001_init_podcasting_20_database.sql index 113d1a5..99b7af0 100644 --- a/docs/database/0001_init_podcasting_20_database.sql +++ b/docs/database/0001_init_podcasting_20_database.sql @@ -19,10 +19,44 @@ PODCASTING 2.0 DATABASE SCHEMA */ --- Init tables +----------** DICTIONARY REFERENCE TABLES **---------- +--** --** These tables need to be instantiated before the tables that reference them, +--** --** and they will only have a specified set of values, like an enum. + +--** CATEGORY + +-- Allowed category values align with the standard categories and subcategories +-- supported by Apple iTunes through the <itunes:category> tag. +CREATE TABLE category ( + id SERIAL PRIMARY KEY, + node_text varchar_normal NOT NULL, -- <itunes:category> + display_name varchar_normal NOT NULL, -- our own display name for the category + slug varchar_normal NOT NULL +); + +--** MEDIUM VALUE (referenced by many tables) + +-- <podcast:medium> +CREATE TABLE medium_value ( + id SERIAL PRIMARY KEY, + value TEXT UNIQUE CHECK (VALUE IN ( + 'publisher', + 'podcast', 'music', 'video', 'film', 'audiobook', 'newsletter', 'blog', 'publisher', 'course', + 'mixed', 'podcastL', 'musicL', 'videoL', 'filmL', 'audiobookL', 'newsletterL', 'blogL', 'publisherL', 'courseL' + )) +); + +INSERT INTO medium_value (value) VALUES + ('publisher'), + ('podcast'), ('music'), ('video'), ('film'), ('audiobook'), ('newsletter'), ('blog'), ('course'), + ('mixed'), ('podcastL'), ('musicL'), ('videoL'), ('filmL'), ('audiobookL'), ('newsletterL'), ('blogL'), ('publisherL'), ('courseL') +; + +----------** TABLES **---------- --** FEED > FLAG STATUS +-- used internally for identifying and handling spam and other special flag statuses. CREATE TABLE feed_flag_status ( id SERIAL PRIMARY KEY, status TEXT UNIQUE CHECK (status IN ('none', 'spam', 'takedown', 'other', 'always-allow')), @@ -39,6 +73,7 @@ INSERT INTO feed_flag_status (status) VALUES ('none'), ('spam'), ('takedown'), ( --** FEED +-- The top-level table for storing feed data, and internal parsing data. CREATE TABLE feed ( id SERIAL PRIMARY KEY, url varchar_url UNIQUE NOT NULL, @@ -83,11 +118,11 @@ CREATE TABLE channel ( podcast_guid UUID UNIQUE, -- <podcast:guid> title varchar_normal, sortable_title varchar_short, -- all lowercase, ignores articles at beginning of title + medium_value_id INTEGER REFERENCES medium_value(id), + -- TODO: should we hash the last parsed feed, so we can compare it to the hash of -- a feed before completely parsing it, to check if it has changed before continuing? - -- TODO: categories, how to best handle to account for sub-categories? - -- channels that have a PI value tag require special handling to request value_tag data -- from the Podcast Index API. has_podcast_index_value_tags BOOLEAN DEFAULT FALSE, @@ -103,7 +138,7 @@ CREATE UNIQUE INDEX channel_slug ON channel(slug) WHERE slug IS NOT NULL; --** CHANNEL > ABOUT > ITUNES TYPE --- <itunes:type> +-- <channel> -> <itunes:type> CREATE TABLE channel_itunes_type ( id SERIAL PRIMARY KEY, itunes_type TEXT UNIQUE CHECK (itunes_type IN ('episodic', 'serial')) @@ -113,6 +148,7 @@ INSERT INTO channel_itunes_type (itunes_type) VALUES ('episodic'), ('serial'); --** CHANNEL > ABOUT +-- various channel data from multiple tags CREATE TABLE channel_about ( id SERIAL PRIMARY KEY, channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, @@ -124,12 +160,7 @@ CREATE TABLE channel_about ( website_link_url varchar_url -- <link> ); -CREATE TABLE category ( - id SERIAL PRIMARY KEY, - node_text varchar_normal NOT NULL, -- <itunes:category> - display_name varchar_normal NOT NULL, -- our own display name for the category - slug varchar_normal NOT NULL -); +--** CHANNEL > CATEGORY CREATE TABLE channel_category ( id SERIAL PRIMARY KEY, @@ -137,6 +168,53 @@ CREATE TABLE channel_category ( parent_id INTEGER REFERENCES channel_category(id) ON DELETE CASCADE ); +--** CHANNEL > CHAT + +-- <podcast:chat> +CREATE TABLE channel_chat ( + id SERIAL PRIMARY KEY, + channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, + server varchar_fqdn NOT NULL, + protocol varchar_short, + account_id varchar_normal, + space varchar_normal +); + +--** CHANNEL > DESCRIPTION + +-- <description> AND possibly other tags that contain a description. +CREATE TABLE channel_description ( + id SERIAL PRIMARY KEY, + channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, + UNIQUE (channel_id), + value varchar_long NOT NULL +); + +--** CHANNEL > FUNDING + +-- <podcast:funding> +CREATE TABLE channel_funding ( + id SERIAL PRIMARY KEY, + channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, + url varchar_url NOT NULL, + title varchar_normal +); + +--** CHANNEL > IMAGE + +-- <podcast:image> AND all other image tags in the rss feed +CREATE TABLE channel_image ( + id SERIAL PRIMARY KEY, + channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, + url varchar_url NOT NULL, + image_width_size INTEGER, -- <podcast:image> must have a width specified, but older image tags will not, so allow null. + + -- If true, then the image is hosted by us in a service like S3. + -- When is_resized images are deleted, the corresponding image in S3 + -- should also be deleted. + is_resized BOOLEAN DEFAULT FALSE +); + --** CHANNEL > INTERNAL SETTINGS CREATE TABLE channel_internal_settings ( @@ -147,6 +225,44 @@ CREATE TABLE channel_internal_settings ( embed_approved_media_url_paths TEXT ); +--** CHANNEL > LICENSE + +-- <podcast:license> +CREATE TABLE channel_license ( + id SERIAL PRIMARY KEY, + channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, + UNIQUE (channel_id), + type varchar_normal NOT NULL, + url varchar_url NOT NULL +); + +--** CHANNEL > LOCATION + +-- <podcast:location> +CREATE TABLE channel_location ( + id SERIAL PRIMARY KEY, + channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, + geo varchar_normal, + osm varchar_normal, + CHECK ( + (geo IS NOT NULL AND osm IS NULL) OR + (geo IS NULL AND osm IS NOT NULL) + ) +); + +--** CHANNEL > PERSON + +-- <podcast:person> +CREATE TABLE channel_person ( + id SERIAL PRIMARY KEY, + channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, + name varchar_normal, + role varchar_normal, + person_group varchar_normal DEFAULT 'cast', -- group is a reserved keyword in sql + img varchar_url, + href varchar_url +); + --** CHANNEL > PODROLL -- <podcast:podroll> @@ -155,6 +271,55 @@ CREATE TABLE channel_podroll ( channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE ); +--** CHANNEL > PODROLL > REMOTE ITEM + +-- <podcast:podroll> --> <podcast:remoteItem> +CREATE TABLE channel_podroll_remote_item ( + id SERIAL PRIMARY KEY, + channel_podroll_id INTEGER NOT NULL REFERENCES channel_podroll(id) ON DELETE CASCADE, + feed_guid UUID NOT NULL, + feed_url varchar_url, + item_guid varchar_uri, + title varchar_normal, + medium_value_id INTEGER REFERENCES medium_value(id) +); + +--** CHANNEL > PUBLISHER + +-- <channel> -> <podcast:publisher> +CREATE TABLE channel_publisher ( + id SERIAL PRIMARY KEY, + channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE +); + +--** CHANNEL > PUBLISHER > REMOTE ITEM + +-- <channel> -> <podcast:publisher> -> <podcast:remoteItem> +CREATE TABLE channel_publisher_remote_item ( + id SERIAL PRIMARY KEY, + channel_publisher_id INTEGER NOT NULL REFERENCES channel_publisher(id) ON DELETE CASCADE, + feed_guid UUID NOT NULL, + feed_url varchar_url, + item_guid varchar_uri, + title varchar_normal, + medium_value_id INTEGER REFERENCES medium_value(id) +); + +--** CHANNEL > REMOTE ITEM + +--** <channel> -> <podcast:remoteItem> +--** Remote items at the channel level are only used when the <podcast:medium> for the channel +--** is set to 'mixed' or another list medium like 'podcastL'. +CREATE TABLE channel_remote_item ( + id SERIAL PRIMARY KEY, + channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, + feed_guid UUID NOT NULL, + feed_url varchar_url, + item_guid varchar_uri, + title varchar_normal, + medium_value_id INTEGER REFERENCES medium_value(id) +); + --** CHANNEL > SEASON -- channels with seasons need to be rendered in client apps differently. @@ -173,6 +338,18 @@ CREATE TABLE channel_season ( name varchar_normal ); +--** CHANNEL > SOCIAL INTERACT + +CREATE TABLE channel_social_interact ( + id SERIAL PRIMARY KEY, + channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, + protocol varchar_short NOT NULL, + uri varchar_uri NOT NULL, + account_id varchar_normal, + account_url varchar_url, + priority INTEGER +); + --** CHANNEL > TRAILER -- <podcast:trailer> @@ -187,7 +364,80 @@ CREATE TABLE channel_trailer ( season INTEGER ); +--** CHANNEL > TXT TAG + +CREATE TABLE channel_txt_tag ( + id SERIAL PRIMARY KEY, + channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, + verify varchar_normal NOT NULL, + value varchar_long NOT NULL +); + +--** CHANNEL > VALUE TAG + +-- <podcast:value> +CREATE TABLE channel_value_tag ( + id SERIAL PRIMARY KEY, + channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, + type varchar_short NOT NULL, + method varchar_short NOT NULL, + suggested FLOAT +); + +--** CHANNEL > VALUE TAG > RECEIPIENT + +-- <podcast:valueRecipient> +CREATE TABLE channel_value_tag_receipient ( + id SERIAL PRIMARY KEY, + channel_value_tag_id INTEGER NOT NULL REFERENCES channel_value_tag(id) ON DELETE CASCADE, + type varchar_short NOT NULL, + address varchar_long NOT NULL, + split FLOAT NOT NULL, + name varchar_normal, + custom_key varchar_long, + custom_value varchar_long, + fee BOOLEAN DEFAULT FALSE +); + +--** CHANNEL > VALUE TAG > TIME SPLIT + +-- <podcast:valueTimeSplit> +CREATE TABLE channel_value_tag_time_split ( + id SERIAL PRIMARY KEY, + channel_value_tag_id INTEGER NOT NULL REFERENCES channel_value_tag(id) ON DELETE CASCADE, + start_time INTEGER NOT NULL, + duration INTEGER NOT NULL, + remote_start_time INTEGER DEFAULT 0, + remote_percentage INTEGER DEFAULT 100 +); + +--** ITEM > VALUE TAG > TIME SPLIT > REMOTE ITEM + +CREATE TABLE channel_value_tag_time_split_remote_item ( + id SERIAL PRIMARY KEY, + channel_value_tag_time_split_id INTEGER NOT NULL REFERENCES channel_value_tag_time_split(id) ON DELETE CASCADE, + feed_guid UUID NOT NULL, + feed_url varchar_url, + item_guid varchar_uri, + title varchar_normal +); + +--** ITEM > VALUE TAG > TIME SPLIT > VALUE RECIPEINT + +CREATE TABLE channel_value_tag_time_split_receipient ( + id SERIAL PRIMARY KEY, + channel_value_tag_time_split_id INTEGER NOT NULL REFERENCES channel_value_tag_time_split(id) ON DELETE CASCADE, + type varchar_short NOT NULL, + address varchar_long NOT NULL, + split FLOAT NOT NULL, + name varchar_normal, + custom_key varchar_long, + custom_value varchar_long, + fee BOOLEAN DEFAULT FALSE +); + --** ITEM +--** Technically the item table could be named channel_item, but it seems easier to understand as item. -- <item> CREATE TABLE item ( @@ -272,6 +522,56 @@ CREATE TABLE item_chapter ( table_of_contents BOOLEAN DEFAULT TRUE ); +--** ITEM > CHAPTER > IMAGE + +-- <podcast:image> AND all other image tags in the rss feed +CREATE TABLE item_chapter_image ( + id SERIAL PRIMARY KEY, + item_chapter_id INTEGER NOT NULL REFERENCES item_chapter(id) ON DELETE CASCADE, + url varchar_url NOT NULL, + image_width_size INTEGER, -- <podcast:image> must have a width specified, but older image tags will not, so allow null. + + -- If true, then the image is hosted by us in a service like S3. + -- When is_resized images are deleted, the corresponding image in S3 + -- should also be deleted. + is_resized BOOLEAN DEFAULT FALSE +); + +--** ITEM > CHAPTER > LOCATION + +CREATE TABLE item_chapter_location ( + id SERIAL PRIMARY KEY, + item_chapter_id INTEGER NOT NULL REFERENCES item_chapter(id) ON DELETE CASCADE, + geo varchar_normal, + osm varchar_normal, + CHECK ( + (geo IS NOT NULL AND osm IS NULL) OR + (geo IS NULL AND osm IS NOT NULL) + ) +); + +--** ITEM > CHAT + +-- <podcast:chat> +CREATE TABLE item_chat ( + id SERIAL PRIMARY KEY, + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + server varchar_fqdn NOT NULL, + protocol varchar_short, + account_id varchar_normal, + space varchar_normal +); + +--** ITEM > DESCRIPTION + +-- <description> AND possibly other tags that contain a description. +CREATE TABLE item_description ( + id SERIAL PRIMARY KEY, + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + UNIQUE (item_id), + value varchar_long NOT NULL +); + --** ITEM > ENCLOSURE (AKA ALTERNATE ENCLOSURE) -- <podcast:alternateEnclosure> @@ -304,134 +604,22 @@ CREATE TABLE item_enclosure_integrity ( value varchar_long NOT NULL ); ---** ITEM > SEASON +--** ITEM > FUNDING --- <podcast:season> -CREATE TABLE item_season ( +-- <podcast:funding> +CREATE TABLE item_funding ( id SERIAL PRIMARY KEY, - channel_season_id INTEGER NOT NULL REFERENCES channel_season(id) ON DELETE CASCADE, - item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, - title varchar_normal -); - ---** ITEM > SEASON > EPISODE - --- <podcast:episode> -CREATE TABLE item_season_episode ( - id SERIAL PRIMARY KEY, - item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, - display varchar_short, - episode_number FLOAT NOT NULL -); - ---** ITEM > SOUNDBITE - --- <podcast:soundbite> -CREATE TABLE item_soundbite ( - id SERIAL PRIMARY KEY, - id_text short_id_v2 UNIQUE NOT NULL, item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, url varchar_url NOT NULL, - start_time INTEGER NOT NULL, - duration INTEGER NOT NULL, title varchar_normal ); ---** ITEM > TRANSCRIPT - --- <podcast:transcript> -CREATE TABLE item_transcript ( - id SERIAL PRIMARY KEY, - item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, - url varchar_url NOT NULL, - type varchar_short NOT NULL, - language varchar_short, - rel VARCHAR(50) CHECK (rel IS NULL OR rel = 'captions') -); - ---** LIVE ITEM > STATUS - -CREATE TABLE live_item_status ( - id SERIAL PRIMARY KEY, - status TEXT UNIQUE CHECK (status IN ('pending', 'live', 'ended')) -); - -INSERT INTO live_item_status (status) VALUES ('pending'), ('live'), ('ended'); - ---** LIVE ITEM - --- <podcast:liveItem> -CREATE TABLE live_item ( - id SERIAL PRIMARY KEY, - item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, - live_item_status_id INTEGER NOT NULL REFERENCES live_item_status(id), - start_time TIMESTAMPTZ NOT NULL, - end_time TIMESTAMPTZ, - chat_web_url varchar_url -); - ---** CROSS-CUTTING INHERITANCE TABLES - ---** CHAT - --- <podcast:chat> -CREATE TABLE chat_base ( - id SERIAL PRIMARY KEY, - server varchar_fqdn NOT NULL, - protocol varchar_short, - account_id varchar_normal, - space varchar_normal -); - -CREATE TABLE channel_chat ( - channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE -) INHERITS (chat_base); - -CREATE TABLE item_chat ( - item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE -) INHERITS (chat_base); - ---** DESCRIPTION +--** ITEM > IMAGE --- <description> AND possibly other tags that contain a description. -CREATE TABLE description_base ( +-- <podcast:image> AND all other image tags in the rss feed +CREATE TABLE item_image ( id SERIAL PRIMARY KEY, - value varchar_long NOT NULL -); - -CREATE TABLE channel_description ( - channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, - UNIQUE (channel_id) -) INHERITS (description_base); - -CREATE TABLE item_description ( item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, - UNIQUE (item_id) -) INHERITS (description_base); - ---** FUNDING - --- <podcast:funding> -CREATE TABLE funding_base ( - id SERIAL PRIMARY KEY, - url varchar_url NOT NULL, - title varchar_normal -); - -CREATE TABLE channel_funding ( - channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE -) INHERITS (funding_base); - -CREATE TABLE item_funding ( - item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE -) INHERITS (funding_base); - ---** IMAGE - --- <podcast:image> AND all other image tags in the rss feed. --- older image tag data will be adapted into the image_base table. -CREATE TABLE image_base ( - id SERIAL PRIMARY KEY, url varchar_url NOT NULL, image_width_size INTEGER, -- <podcast:image> must have a width specified, but older image tags will not, so allow null. @@ -441,42 +629,22 @@ CREATE TABLE image_base ( is_resized BOOLEAN DEFAULT FALSE ); -CREATE TABLE channel_image ( - channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE -) INHERITS (image_base); - -CREATE TABLE chapter_image ( - chapter_id INTEGER NOT NULL REFERENCES item_chapter(id) ON DELETE CASCADE -) INHERITS (image_base); - -CREATE TABLE item_image ( - item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE -) INHERITS (image_base); - ---** LICENSE +--** ITEM > LICENSE -- <podcast:license> -CREATE TABLE license_base ( +CREATE TABLE item_license ( id SERIAL PRIMARY KEY, + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + UNIQUE (item_id), type varchar_normal NOT NULL, url varchar_url NOT NULL ); -CREATE TABLE channel_license ( - channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, - UNIQUE (channel_id) -) INHERITS (license_base); - -CREATE TABLE item_license ( - item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, - UNIQUE (item_id) -) INHERITS (license_base); - ---** LOCATION +--** ITEM > LOCATION --- <podcast:location> -CREATE TABLE location_base ( +CREATE TABLE item_location ( id SERIAL PRIMARY KEY, + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, geo varchar_normal, osm varchar_normal, CHECK ( @@ -485,79 +653,12 @@ CREATE TABLE location_base ( ) ); -CREATE TABLE item_chapter_location ( - item_chapter_id INTEGER NOT NULL REFERENCES item_chapter(id) ON DELETE CASCADE -) INHERITS (location_base); - -CREATE TABLE channel_location ( - channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE -) INHERITS (location_base); - -CREATE TABLE item_location ( - item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE -) INHERITS (location_base); - ---** REMOTE ITEM - --- <podcast:remoteItem> -CREATE TABLE remote_item_base ( - id SERIAL PRIMARY KEY, - feed_guid UUID NOT NULL, - feed_url varchar_url, - item_guid varchar_uri, - title varchar_normal -); - -CREATE TABLE channel_remote_item ( - channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE -) INHERITS (remote_item_base); - -CREATE TABLE item_remote_item ( - item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE -) INHERITS (remote_item_base); - -CREATE TABLE podroll_remote_item ( - podroll_id INTEGER NOT NULL REFERENCES channel_podroll(id) ON DELETE CASCADE -) INHERITS (remote_item_base); - ---** MEDIUM - --- <podcast:medium> -CREATE TABLE medium_value ( - id SERIAL PRIMARY KEY, - value TEXT UNIQUE CHECK (VALUE IN ( - 'publisher', - 'podcast', 'music', 'video', 'film', 'audiobook', 'newsletter', 'blog', 'publisher', 'course', - 'mixed', 'podcastL', 'musicL', 'videoL', 'filmL', 'audiobookL', 'newsletterL', 'blogL', 'publisherL', 'courseL' - )) -); - -INSERT INTO medium_value (value) VALUES - ('publisher'), - ('podcast'), ('music'), ('video'), ('film'), ('audiobook'), ('newsletter'), ('blog'), ('course'), - ('mixed'), ('podcastL'), ('musicL'), ('videoL'), ('filmL'), ('audiobookL'), ('newsletterL'), ('blogL'), ('publisherL'), ('courseL') -; - -CREATE TABLE medium_base ( - id SERIAL PRIMARY KEY, - medium_value_id INTEGER NOT NULL REFERENCES medium_value(id) ON DELETE CASCADE -); - -CREATE TABLE channel_medium ( - channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, - UNIQUE (channel_id) -) INHERITS (medium_base); - -CREATE TABLE remote_item_medium ( - remote_item_id INTEGER NOT NULL REFERENCES remote_item_base(id) ON DELETE CASCADE, - UNIQUE (remote_item_id) -) INHERITS (medium_base); - ---** PERSON +--** ITEM > PERSON -- <podcast:person> -CREATE TABLE person_base ( +CREATE TABLE item_person ( id SERIAL PRIMARY KEY, + channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, name varchar_normal, role varchar_normal, person_group varchar_normal DEFAULT 'cast', -- group is a reserved keyword in sql @@ -565,19 +666,31 @@ CREATE TABLE person_base ( href varchar_url ); -CREATE TABLE channel_person ( - channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE -) INHERITS (person_base); +--** ITEM > SEASON -CREATE TABLE item_person ( - item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE -) INHERITS (person_base); +-- <podcast:season> +CREATE TABLE item_season ( + id SERIAL PRIMARY KEY, + channel_season_id INTEGER NOT NULL REFERENCES channel_season(id) ON DELETE CASCADE, + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + title varchar_normal +); + +--** ITEM > SEASON > EPISODE + +-- <podcast:episode> +CREATE TABLE item_season_episode ( + id SERIAL PRIMARY KEY, + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + display varchar_short, + episode_number FLOAT NOT NULL +); ---** SOCIAL INTERACT +--** ITEM > SOCIAL INTERACT --- <podcast:socialInteract> -CREATE TABLE social_interact_base ( +CREATE TABLE item_social_interact ( id SERIAL PRIMARY KEY, + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, protocol varchar_short NOT NULL, uri varchar_uri NOT NULL, account_id varchar_normal, @@ -585,55 +698,56 @@ CREATE TABLE social_interact_base ( priority INTEGER ); -CREATE TABLE channel_social_interact ( - channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE -) INHERITS (social_interact_base); +--** ITEM > SOUNDBITE -CREATE TABLE item_social_interact ( - item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE -) INHERITS (social_interact_base); +-- <podcast:soundbite> +CREATE TABLE item_soundbite ( + id SERIAL PRIMARY KEY, + id_text short_id_v2 UNIQUE NOT NULL, + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + url varchar_url NOT NULL, + start_time INTEGER NOT NULL, + duration INTEGER NOT NULL, + title varchar_normal +); ---** TXT +--** ITEM > TRANSCRIPT --- <podcast:txt> -CREATE TABLE txt_tag_base ( +-- <podcast:transcript> +CREATE TABLE item_transcript ( id SERIAL PRIMARY KEY, - verify varchar_normal NOT NULL, - value varchar_long NOT NULL + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + url varchar_url NOT NULL, + type varchar_short NOT NULL, + language varchar_short, + rel VARCHAR(50) CHECK (rel IS NULL OR rel = 'captions') ); -CREATE TABLE channel_txt_tag ( - channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE -) INHERITS (txt_tag_base); +--** ITEM > TXT TAG CREATE TABLE item_txt_tag ( - item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE -) INHERITS (txt_tag_base); + id SERIAL PRIMARY KEY, + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + verify varchar_normal NOT NULL, + value varchar_long NOT NULL +); ---** VALUE TAG +--** ITEM > VALUE TAG --- <podcast:value> -CREATE TABLE value_tag_base ( +CREATE TABLE item_value_tag ( id SERIAL PRIMARY KEY, + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, type varchar_short NOT NULL, method varchar_short NOT NULL, suggested FLOAT ); -CREATE TABLE channel_value_tag ( - channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE -) INHERITS (value_tag_base); - -CREATE TABLE item_value_tag ( - item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE -) INHERITS (value_tag_base); - ---** VALUE TAG > RECEIPIENT +--** ITEM > VALUE TAG > RECEIPIENT -- <podcast:valueRecipient> -CREATE TABLE value_tag_receipient ( +CREATE TABLE item_value_tag_receipient ( id SERIAL PRIMARY KEY, - value_tag_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, + item_value_tag_id INTEGER NOT NULL REFERENCES item_value_tag(id) ON DELETE CASCADE, type varchar_short NOT NULL, address varchar_long NOT NULL, split FLOAT NOT NULL, @@ -643,14 +757,61 @@ CREATE TABLE value_tag_receipient ( fee BOOLEAN DEFAULT FALSE ); ---** VALUE TAG > TIME SPLIT +--** ITEM > VALUE TAG > TIME SPLIT --- <podcast:valueTimeSplit> -CREATE TABLE value_tag_time_split ( +-- <item> -> <podcast:value> -> <podcast:valueTimeSplit> +CREATE TABLE item_value_tag_time_split ( id SERIAL PRIMARY KEY, - value_tag_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, + item_value_tag_id INTEGER NOT NULL REFERENCES item_value_tag(id) ON DELETE CASCADE, start_time INTEGER NOT NULL, duration INTEGER NOT NULL, remote_start_time INTEGER DEFAULT 0, remote_percentage INTEGER DEFAULT 100 ); + +--** ITEM > VALUE TAG > TIME SPLIT > REMOTE ITEM + +CREATE TABLE item_value_tag_time_split_remote_item ( + id SERIAL PRIMARY KEY, + item_value_tag_time_split_id INTEGER NOT NULL REFERENCES item_value_tag_time_split(id) ON DELETE CASCADE, + feed_guid UUID NOT NULL, + feed_url varchar_url, + item_guid varchar_uri, + title varchar_normal +); + +--** ITEM > VALUE TAG > TIME SPLIT > VALUE RECIPEINT + +CREATE TABLE item_value_tag_time_split_receipient ( + id SERIAL PRIMARY KEY, + item_value_tag_time_split_id INTEGER NOT NULL REFERENCES item_value_tag_time_split(id) ON DELETE CASCADE, + type varchar_short NOT NULL, + address varchar_long NOT NULL, + split FLOAT NOT NULL, + name varchar_normal, + custom_key varchar_long, + custom_value varchar_long, + fee BOOLEAN DEFAULT FALSE +); + +--** LIVE ITEM > STATUS + +CREATE TABLE live_item_status ( + id SERIAL PRIMARY KEY, + status TEXT UNIQUE CHECK (status IN ('pending', 'live', 'ended')) +); + +INSERT INTO live_item_status (status) VALUES ('pending'), ('live'), ('ended'); + +--** LIVE ITEM + +-- <podcast:liveItem> +CREATE TABLE live_item ( + id SERIAL PRIMARY KEY, + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + live_item_status_id INTEGER NOT NULL REFERENCES live_item_status(id), + start_time TIMESTAMPTZ NOT NULL, + end_time TIMESTAMPTZ, + chat_web_url varchar_url +); + diff --git a/docs/database/0003_clip.sql b/docs/database/0003_clip.sql index 1c0f6ee..fb907a8 100644 --- a/docs/database/0003_clip.sql +++ b/docs/database/0003_clip.sql @@ -1,4 +1,4 @@ -CREATE TABLE account_clip ( +CREATE TABLE clip ( id SERIAL PRIMARY KEY, id_text short_id_v2 UNIQUE NOT NULL, account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, diff --git a/docs/database/0004_playlist.sql b/docs/database/0004_playlist.sql index b0f07c4..c3ba865 100644 --- a/docs/database/0004_playlist.sql +++ b/docs/database/0004_playlist.sql @@ -7,14 +7,10 @@ CREATE TABLE playlist ( description varchar_long, is_default_favorites BOOLEAN DEFAULT FALSE, is_public BOOLEAN DEFAULT FALSE, - item_count INTEGER DEFAULT 0 + item_count INTEGER DEFAULT 0, + medium_value_id INTEGER NOT NULL REFERENCES medium_value(id) ); -CREATE TABLE playlist_medium ( - playlist_id INTEGER NOT NULL REFERENCES playlist(id) ON DELETE CASCADE, - UNIQUE (playlist_id) -) INHERITS (medium_base); - CREATE TABLE playlist_resource_base ( id SERIAL PRIMARY KEY, playlist_id INTEGER NOT NULL REFERENCES playlist(id) ON DELETE CASCADE, @@ -27,17 +23,50 @@ CREATE TABLE playlist_resource_item ( ) INHERITS (playlist_resource_base); CREATE TABLE playlist_resource_item_add_by_rss ( - item_data jsonb NOT NULL + resource_data jsonb NOT NULL ) INHERITS (playlist_resource_base); -CREATE TABLE playlist_resource_chapter ( - chapter_id INTEGER NOT NULL REFERENCES item_chapter(id) ON DELETE CASCADE +CREATE TABLE playlist_resource_item_chapter ( + item_chapter_id INTEGER NOT NULL REFERENCES item_chapter(id) ON DELETE CASCADE ) INHERITS (playlist_resource_base); -CREATE TABLE playlist_resource_account_clip ( - account_clip_id INTEGER NOT NULL REFERENCES account_clip(id) ON DELETE CASCADE +CREATE TABLE playlist_resource_clip ( + clip_id INTEGER NOT NULL REFERENCES clip(id) ON DELETE CASCADE ) INHERITS (playlist_resource_base); -CREATE TABLE playlist_resource_soundbite ( +CREATE TABLE playlist_resource_item_soundbite ( soundbite_id INTEGER NOT NULL REFERENCES item_soundbite(id) ON DELETE CASCADE ) INHERITS (playlist_resource_base); + +CREATE OR REPLACE FUNCTION delete_playlist_resource_base() +RETURNS TRIGGER AS $$ +BEGIN + DELETE FROM playlist_resource_base WHERE id = OLD.id; + RETURN OLD; +END; +$$ LANGUAGE plpgsql; + +CREATE TRIGGER delete_playlist_resource_base_trigger_item +BEFORE DELETE ON playlist_resource_item +FOR EACH ROW +EXECUTE FUNCTION delete_playlist_resource_base(); + +CREATE TRIGGER delete_playlist_resource_base_trigger_item_add_by_rss +BEFORE DELETE ON playlist_resource_item_add_by_rss +FOR EACH ROW +EXECUTE FUNCTION delete_playlist_resource_base(); + +CREATE TRIGGER delete_playlist_resource_base_trigger_item_chapter +BEFORE DELETE ON playlist_resource_item_chapter +FOR EACH ROW +EXECUTE FUNCTION delete_playlist_resource_base(); + +CREATE TRIGGER delete_playlist_resource_base_trigger_clip +BEFORE DELETE ON playlist_resource_clip +FOR EACH ROW +EXECUTE FUNCTION delete_playlist_resource_base(); + +CREATE TRIGGER delete_playlist_resource_base_trigger_item_soundbite +BEFORE DELETE ON playlist_resource_item_soundbite +FOR EACH ROW +EXECUTE FUNCTION delete_playlist_resource_base(); diff --git a/docs/database/0005_queue_resource.sql b/docs/database/0005_queue_resource.sql index 7fca37c..5f069e4 100644 --- a/docs/database/0005_queue_resource.sql +++ b/docs/database/0005_queue_resource.sql @@ -14,7 +14,7 @@ CREATE TABLE queue_resource_item ( ) INHERITS (queue_resource_base); CREATE TABLE queue_resource_item_add_by_rss ( - item_data jsonb NOT NULL, + resource_data jsonb NOT NULL, UNIQUE (account_id) ) INHERITS (queue_resource_base); @@ -23,8 +23,8 @@ CREATE TABLE queue_resource_item_chapter ( UNIQUE (account_id) ) INHERITS (queue_resource_base); -CREATE TABLE queue_resource_account_clip ( - account_clip_id INTEGER NOT NULL REFERENCES account_clip(id) ON DELETE CASCADE, +CREATE TABLE queue_resource_clip ( + clip_id INTEGER NOT NULL REFERENCES clip(id) ON DELETE CASCADE, UNIQUE (account_id) ) INHERITS (queue_resource_base); @@ -32,3 +32,36 @@ CREATE TABLE queue_resource_item_soundbite ( soundbite_id INTEGER NOT NULL REFERENCES item_soundbite(id) ON DELETE CASCADE, UNIQUE (account_id) ) INHERITS (queue_resource_base); + +CREATE OR REPLACE FUNCTION delete_queue_resource_base() +RETURNS TRIGGER AS $$ +BEGIN + DELETE FROM queue_resource_base WHERE id = OLD.id; + RETURN OLD; +END; +$$ LANGUAGE plpgsql; + +CREATE TRIGGER delete_queue_resource_base_trigger_item +BEFORE DELETE ON queue_resource_item +FOR EACH ROW +EXECUTE FUNCTION delete_queue_resource_base(); + +CREATE TRIGGER delete_queue_resource_base_trigger_item_add_by_rss +BEFORE DELETE ON queue_resource_item_add_by_rss +FOR EACH ROW +EXECUTE FUNCTION delete_queue_resource_base(); + +CREATE TRIGGER delete_queue_resource_base_trigger_item_chapter +BEFORE DELETE ON queue_resource_item_chapter +FOR EACH ROW +EXECUTE FUNCTION delete_queue_resource_base(); + +CREATE TRIGGER delete_queue_resource_base_trigger_clip +BEFORE DELETE ON queue_resource_clip +FOR EACH ROW +EXECUTE FUNCTION delete_queue_resource_base(); + +CREATE TRIGGER delete_queue_resource_base_trigger_item_soundbite +BEFORE DELETE ON queue_resource_item_soundbite +FOR EACH ROW +EXECUTE FUNCTION delete_queue_resource_base(); From 53e9244246bec0320cf083e1911a397fc06e5596 Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Sun, 18 Aug 2024 15:06:04 -0500 Subject: [PATCH 28/73] Add account_following tables --- .../0006_account_following_tables.sql | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 docs/database/0006_account_following_tables.sql diff --git a/docs/database/0006_account_following_tables.sql b/docs/database/0006_account_following_tables.sql new file mode 100644 index 0000000..d4d1f7a --- /dev/null +++ b/docs/database/0006_account_following_tables.sql @@ -0,0 +1,25 @@ +CREATE TABLE account_following_account ( + account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, + following_account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, + PRIMARY KEY (account_id, following_account_id) +); + +CREATE TABLE account_following_channel ( + account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, + channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, + PRIMARY KEY (account_id, channel_id) +); + +CREATE TABLE account_following_playlist ( + account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, + playlist_id INTEGER NOT NULL REFERENCES playlist(id) ON DELETE CASCADE, + PRIMARY KEY (account_id, playlist_id) +); + +CREATE TABLE account_following_add_by_rss_channel ( + account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, + feed_url varchar_url NOT NULL, + PRIMARY KEY (account_id, feed_url), + title varchar_normal, + image_url varchar_url +); From 9c5b2d5e59e138d8c35a4af3d3238ec7e349ffa8 Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Sun, 18 Aug 2024 15:25:29 -0500 Subject: [PATCH 29/73] Add notes and cleanup 0001 migration --- .../0001_init_podcasting_20_database.sql | 147 ++++++++++-------- 1 file changed, 86 insertions(+), 61 deletions(-) diff --git a/docs/database/0001_init_podcasting_20_database.sql b/docs/database/0001_init_podcasting_20_database.sql index 99b7af0..55ffbe3 100644 --- a/docs/database/0001_init_podcasting_20_database.sql +++ b/docs/database/0001_init_podcasting_20_database.sql @@ -12,29 +12,24 @@ PODCASTING 2.0 DATABASE SCHEMA - The `podcast_index_id` ensures that our database only contains feed data that is available in the Podcast Index API. -- The columns that are within top-level tables, like channel, are intended to be the most essential information, - and information that is useful for identifying what the channel corresponds with if you are viewing the database - in a tool like pgAdmin. Example: title makes it easy to see which id corresponds with a podcast you are looking for, - and description and author can help identify different podcasts with the same title. - */ -----------** DICTIONARY REFERENCE TABLES **---------- ---** --** These tables need to be instantiated before the tables that reference them, ---** --** and they will only have a specified set of values, like an enum. +----------** GLOBAL REFERENCE TABLES **---------- +-- These tables are referenced across many tables, and must be created first. --** CATEGORY -- Allowed category values align with the standard categories and subcategories -- supported by Apple iTunes through the <itunes:category> tag. +-- CREATE TABLE category ( id SERIAL PRIMARY KEY, node_text varchar_normal NOT NULL, -- <itunes:category> display_name varchar_normal NOT NULL, -- our own display name for the category - slug varchar_normal NOT NULL + slug varchar_normal NOT NULL -- our own slug for the category ); ---** MEDIUM VALUE (referenced by many tables) +--** MEDIUM VALUE -- <podcast:medium> CREATE TABLE medium_value ( @@ -78,25 +73,24 @@ CREATE TABLE feed ( id SERIAL PRIMARY KEY, url varchar_url UNIQUE NOT NULL, - -- 0 to 5, 0 will only be parsed when PI API reports an update, - -- higher parsing_priority will be parsed more frequently on a schedule. - parsing_priority INTEGER DEFAULT 0, - last_http_status INTEGER, - last_crawl_time server_time, - last_good_http_status_time server_time, - last_parse_time server_time, - last_update_time server_time, - crawl_errors INTEGER DEFAULT 0, - parse_errors INTEGER DEFAULT 0, - + -- feed flag feed_flag_status_id INTEGER NOT NULL REFERENCES feed_flag_status(id), + -- internal + -- Used to prevent another thread from parsing the same feed. -- Set to current time at beginning of parsing, and NULL at end of parsing. -- This is to prevent multiple threads from parsing the same feed. -- If is_parsing is over X minutes old, assume last parsing failed and proceed to parse. is_parsing server_time, + + -- 0 will only be parsed when PI API reports an update. + -- higher parsing_priority will be parsed more frequently on a schedule. + parsing_priority INTEGER DEFAULT 0 CHECK (parsing_priority BETWEEN 0 AND 5), + + -- the run-time environment container id container_id VARCHAR(12), + created_at server_time_with_default, updated_at server_time_with_default ); @@ -106,6 +100,18 @@ BEFORE UPDATE ON feed FOR EACH ROW EXECUTE FUNCTION set_updated_at_field(); +CREATE TABLE feed_log ( + id SERIAL PRIMARY KEY, + feed_id INTEGER NOT NULL REFERENCES feed(id) ON DELETE CASCADE, + last_http_status INTEGER, + last_crawl_time server_time, + last_good_http_status_time server_time, + last_parse_time server_time, + last_update_time server_time, + crawl_errors INTEGER DEFAULT 0, + parse_errors INTEGER DEFAULT 0 +); + --** CHANNEL -- <channel> @@ -148,7 +154,7 @@ INSERT INTO channel_itunes_type (itunes_type) VALUES ('episodic'), ('serial'); --** CHANNEL > ABOUT --- various channel data from multiple tags +-- various <channel> child data from multiple tags CREATE TABLE channel_about ( id SERIAL PRIMARY KEY, channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, @@ -170,7 +176,7 @@ CREATE TABLE channel_category ( --** CHANNEL > CHAT --- <podcast:chat> +-- <channel> -> <podcast:chat> CREATE TABLE channel_chat ( id SERIAL PRIMARY KEY, channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, @@ -182,7 +188,7 @@ CREATE TABLE channel_chat ( --** CHANNEL > DESCRIPTION --- <description> AND possibly other tags that contain a description. +-- <channel> -> <description> AND possibly other tags that contain a description CREATE TABLE channel_description ( id SERIAL PRIMARY KEY, channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, @@ -192,7 +198,7 @@ CREATE TABLE channel_description ( --** CHANNEL > FUNDING --- <podcast:funding> +-- <channel> -> <podcast:funding> CREATE TABLE channel_funding ( id SERIAL PRIMARY KEY, channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, @@ -202,7 +208,7 @@ CREATE TABLE channel_funding ( --** CHANNEL > IMAGE --- <podcast:image> AND all other image tags in the rss feed +-- <channel> -> <podcast:image> AND all other image tags in the rss feed CREATE TABLE channel_image ( id SERIAL PRIMARY KEY, channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, @@ -227,7 +233,7 @@ CREATE TABLE channel_internal_settings ( --** CHANNEL > LICENSE --- <podcast:license> +-- <channel> -> <podcast:license> CREATE TABLE channel_license ( id SERIAL PRIMARY KEY, channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, @@ -238,7 +244,7 @@ CREATE TABLE channel_license ( --** CHANNEL > LOCATION --- <podcast:location> +-- <channel> -> <podcast:location> CREATE TABLE channel_location ( id SERIAL PRIMARY KEY, channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, @@ -252,7 +258,7 @@ CREATE TABLE channel_location ( --** CHANNEL > PERSON --- <podcast:person> +-- <channel> -> <podcast:person> CREATE TABLE channel_person ( id SERIAL PRIMARY KEY, channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, @@ -265,7 +271,7 @@ CREATE TABLE channel_person ( --** CHANNEL > PODROLL --- <podcast:podroll> +-- <channel> -> <podcast:podroll> CREATE TABLE channel_podroll ( id SERIAL PRIMARY KEY, channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE @@ -273,7 +279,7 @@ CREATE TABLE channel_podroll ( --** CHANNEL > PODROLL > REMOTE ITEM --- <podcast:podroll> --> <podcast:remoteItem> +-- <channel> -> <podcast:podroll> --> <podcast:remoteItem> CREATE TABLE channel_podroll_remote_item ( id SERIAL PRIMARY KEY, channel_podroll_id INTEGER NOT NULL REFERENCES channel_podroll(id) ON DELETE CASCADE, @@ -307,9 +313,10 @@ CREATE TABLE channel_publisher_remote_item ( --** CHANNEL > REMOTE ITEM ---** <channel> -> <podcast:remoteItem> ---** Remote items at the channel level are only used when the <podcast:medium> for the channel ---** is set to 'mixed' or another list medium like 'podcastL'. +-- Remote items at the channel level are only used when the <podcast:medium> for the channel +-- is set to 'mixed' or another list medium like 'podcastL'. + +-- <channel> -> <podcast:remoteItem> CREATE TABLE channel_remote_item ( id SERIAL PRIMARY KEY, channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, @@ -340,6 +347,7 @@ CREATE TABLE channel_season ( --** CHANNEL > SOCIAL INTERACT +-- <channel> -> <podcast:socialInteract> CREATE TABLE channel_social_interact ( id SERIAL PRIMARY KEY, channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, @@ -352,7 +360,7 @@ CREATE TABLE channel_social_interact ( --** CHANNEL > TRAILER --- <podcast:trailer> +-- <channel> -> <podcast:trailer> CREATE TABLE channel_trailer ( id SERIAL PRIMARY KEY, channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, @@ -366,6 +374,7 @@ CREATE TABLE channel_trailer ( --** CHANNEL > TXT TAG +-- <channel> -> <podcast:txt> CREATE TABLE channel_txt_tag ( id SERIAL PRIMARY KEY, channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, @@ -375,7 +384,7 @@ CREATE TABLE channel_txt_tag ( --** CHANNEL > VALUE TAG --- <podcast:value> +-- <channel> -> <podcast:value> CREATE TABLE channel_value_tag ( id SERIAL PRIMARY KEY, channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, @@ -386,7 +395,7 @@ CREATE TABLE channel_value_tag ( --** CHANNEL > VALUE TAG > RECEIPIENT --- <podcast:valueRecipient> +-- <channel> -> <podcast:value> -> <podcast:valueRecipient> CREATE TABLE channel_value_tag_receipient ( id SERIAL PRIMARY KEY, channel_value_tag_id INTEGER NOT NULL REFERENCES channel_value_tag(id) ON DELETE CASCADE, @@ -401,7 +410,7 @@ CREATE TABLE channel_value_tag_receipient ( --** CHANNEL > VALUE TAG > TIME SPLIT --- <podcast:valueTimeSplit> +-- <channel> -> <podcast:valueTimeSplit> CREATE TABLE channel_value_tag_time_split ( id SERIAL PRIMARY KEY, channel_value_tag_id INTEGER NOT NULL REFERENCES channel_value_tag(id) ON DELETE CASCADE, @@ -411,8 +420,9 @@ CREATE TABLE channel_value_tag_time_split ( remote_percentage INTEGER DEFAULT 100 ); ---** ITEM > VALUE TAG > TIME SPLIT > REMOTE ITEM +--** CHANNEL > VALUE TAG > TIME SPLIT > REMOTE ITEM +-- <channel> -> <podcast:value> -> <podcast:valueTimeSplit> -> <podcast:remoteItem> CREATE TABLE channel_value_tag_time_split_remote_item ( id SERIAL PRIMARY KEY, channel_value_tag_time_split_id INTEGER NOT NULL REFERENCES channel_value_tag_time_split(id) ON DELETE CASCADE, @@ -422,8 +432,9 @@ CREATE TABLE channel_value_tag_time_split_remote_item ( title varchar_normal ); ---** ITEM > VALUE TAG > TIME SPLIT > VALUE RECIPEINT +--** CHANNEL > VALUE TAG > TIME SPLIT > VALUE RECIPEINT +-- <channel> -> <podcast:value> -> <podcast:valueTimeSplit> -> <podcast:valueRecipient> CREATE TABLE channel_value_tag_time_split_receipient ( id SERIAL PRIMARY KEY, channel_value_tag_time_split_id INTEGER NOT NULL REFERENCES channel_value_tag_time_split(id) ON DELETE CASCADE, @@ -437,9 +448,10 @@ CREATE TABLE channel_value_tag_time_split_receipient ( ); --** ITEM ---** Technically the item table could be named channel_item, but it seems easier to understand as item. --- <item> +-- Technically the item table could be named channel_item, but it seems easier to understand as item. + +-- <channel> -> <item> CREATE TABLE item ( id SERIAL PRIMARY KEY, id_text short_id_v2 UNIQUE NOT NULL, @@ -459,7 +471,7 @@ CREATE UNIQUE INDEX item_slug ON item(slug) WHERE slug IS NOT NULL; --** ITEM > ABOUT > ITUNES TYPE --- <itunes:episodeType> +-- <item> -> <itunes:episodeType> CREATE TABLE item_itunes_episode_type ( id SERIAL PRIMARY KEY, itunes_episode_type TEXT UNIQUE CHECK (itunes_episode_type IN ('full', 'trailer', 'bonus')) @@ -475,12 +487,12 @@ CREATE TABLE item_about ( duration INTEGER, -- <itunes:duration> explicit BOOLEAN, -- <itunes:explicit> website_link_url varchar_url, -- <link> - item_itunes_episode_type_id INTEGER REFERENCES item_itunes_episode_type(id) + item_itunes_episode_type_id INTEGER REFERENCES item_itunes_episode_type(id) -- <itunes:episodeType> ); --** ITEM > CONTENT LINK --- <podcast:contentLink> +-- <item> -> <podcast:contentLink> CREATE TABLE content_link ( id SERIAL PRIMARY KEY, item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, @@ -490,7 +502,7 @@ CREATE TABLE content_link ( --** ITEM > CHAPTERS --- <podcast:chapters> +-- <item> -> <podcast:chapters> CREATE TABLE item_chapters ( id SERIAL PRIMARY KEY, item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, @@ -505,7 +517,7 @@ CREATE TABLE item_chapters ( parse_errors INTEGER DEFAULT 0 ); --- corresponds with jsonChapters.md example file +-- -- <item> -> <podcast:chapters> -> chapter items correspond with jsonChapters.md example file CREATE TABLE item_chapter ( id SERIAL PRIMARY KEY, text_id short_id_v2 UNIQUE NOT NULL, @@ -524,7 +536,7 @@ CREATE TABLE item_chapter ( --** ITEM > CHAPTER > IMAGE --- <podcast:image> AND all other image tags in the rss feed +-- <item> -> <podcast:chapters> -> chapter items correspond with jsonChapters.md example file CREATE TABLE item_chapter_image ( id SERIAL PRIMARY KEY, item_chapter_id INTEGER NOT NULL REFERENCES item_chapter(id) ON DELETE CASCADE, @@ -539,6 +551,7 @@ CREATE TABLE item_chapter_image ( --** ITEM > CHAPTER > LOCATION +-- <item> -> <podcast:chapters> -> chapter items correspond with jsonChapters.md example file CREATE TABLE item_chapter_location ( id SERIAL PRIMARY KEY, item_chapter_id INTEGER NOT NULL REFERENCES item_chapter(id) ON DELETE CASCADE, @@ -552,7 +565,7 @@ CREATE TABLE item_chapter_location ( --** ITEM > CHAT --- <podcast:chat> +-- <item> -> <podcast:chat> CREATE TABLE item_chat ( id SERIAL PRIMARY KEY, item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, @@ -564,7 +577,7 @@ CREATE TABLE item_chat ( --** ITEM > DESCRIPTION --- <description> AND possibly other tags that contain a description. +-- <item> -> <description> AND possibly other tags that contain a description CREATE TABLE item_description ( id SERIAL PRIMARY KEY, item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, @@ -574,8 +587,9 @@ CREATE TABLE item_description ( --** ITEM > ENCLOSURE (AKA ALTERNATE ENCLOSURE) --- <podcast:alternateEnclosure> -- NOTE: the older <enclosure> tag style is integrated into the item_enclosure table. + +-- <item> -> <podcast:alternateEnclosure> AND <item> -> <enclosure> CREATE TABLE item_enclosure ( id SERIAL PRIMARY KEY, item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, @@ -590,6 +604,7 @@ CREATE TABLE item_enclosure ( item_enclosure_default BOOLEAN DEFAULT FALSE ); +-- <item> -> <podcast:alternateEnclosure> -> <podcast:source> CREATE TABLE item_enclosure_source ( id SERIAL PRIMARY KEY, item_enclosure_id INTEGER NOT NULL REFERENCES item_enclosure(id) ON DELETE CASCADE, @@ -597,6 +612,7 @@ CREATE TABLE item_enclosure_source ( content_type varchar_short ); +-- <item> -> <podcast:alternateEnclosure> -> <podcast:integrity> CREATE TABLE item_enclosure_integrity ( id SERIAL PRIMARY KEY, item_enclosure_id INTEGER NOT NULL REFERENCES item_enclosure_source(id) ON DELETE CASCADE, @@ -606,7 +622,7 @@ CREATE TABLE item_enclosure_integrity ( --** ITEM > FUNDING --- <podcast:funding> +-- <item> -> <podcast:funding> CREATE TABLE item_funding ( id SERIAL PRIMARY KEY, item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, @@ -616,7 +632,7 @@ CREATE TABLE item_funding ( --** ITEM > IMAGE --- <podcast:image> AND all other image tags in the rss feed +-- <item> -> <podcast:image> AND all other image tags in the rss feed CREATE TABLE item_image ( id SERIAL PRIMARY KEY, item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, @@ -631,7 +647,7 @@ CREATE TABLE item_image ( --** ITEM > LICENSE --- <podcast:license> +-- <item> -> <podcast:license> CREATE TABLE item_license ( id SERIAL PRIMARY KEY, item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, @@ -642,6 +658,7 @@ CREATE TABLE item_license ( --** ITEM > LOCATION +-- <item> -> <podcast:location> CREATE TABLE item_location ( id SERIAL PRIMARY KEY, item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, @@ -655,7 +672,7 @@ CREATE TABLE item_location ( --** ITEM > PERSON --- <podcast:person> +-- <item> -> <podcast:person> CREATE TABLE item_person ( id SERIAL PRIMARY KEY, channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, @@ -668,7 +685,7 @@ CREATE TABLE item_person ( --** ITEM > SEASON --- <podcast:season> +-- <item> -> <podcast:season> CREATE TABLE item_season ( id SERIAL PRIMARY KEY, channel_season_id INTEGER NOT NULL REFERENCES channel_season(id) ON DELETE CASCADE, @@ -678,7 +695,7 @@ CREATE TABLE item_season ( --** ITEM > SEASON > EPISODE --- <podcast:episode> +-- <item> -> <podcast:season> -> <podcast:episode> CREATE TABLE item_season_episode ( id SERIAL PRIMARY KEY, item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, @@ -688,6 +705,7 @@ CREATE TABLE item_season_episode ( --** ITEM > SOCIAL INTERACT +-- <item> -> <podcast:socialInteract> CREATE TABLE item_social_interact ( id SERIAL PRIMARY KEY, item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, @@ -700,7 +718,7 @@ CREATE TABLE item_social_interact ( --** ITEM > SOUNDBITE --- <podcast:soundbite> +-- <item> -> <podcast:soundbite> CREATE TABLE item_soundbite ( id SERIAL PRIMARY KEY, id_text short_id_v2 UNIQUE NOT NULL, @@ -713,7 +731,7 @@ CREATE TABLE item_soundbite ( --** ITEM > TRANSCRIPT --- <podcast:transcript> +-- <item> -> <podcast:transcript> CREATE TABLE item_transcript ( id SERIAL PRIMARY KEY, item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, @@ -725,6 +743,7 @@ CREATE TABLE item_transcript ( --** ITEM > TXT TAG +-- <item> -> <podcast:txt> CREATE TABLE item_txt_tag ( id SERIAL PRIMARY KEY, item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, @@ -734,6 +753,7 @@ CREATE TABLE item_txt_tag ( --** ITEM > VALUE TAG +-- <item> -> <podcast:value> CREATE TABLE item_value_tag ( id SERIAL PRIMARY KEY, item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, @@ -744,7 +764,7 @@ CREATE TABLE item_value_tag ( --** ITEM > VALUE TAG > RECEIPIENT --- <podcast:valueRecipient> +-- <item> -> <podcast:value> -> <podcast:valueRecipient> CREATE TABLE item_value_tag_receipient ( id SERIAL PRIMARY KEY, item_value_tag_id INTEGER NOT NULL REFERENCES item_value_tag(id) ON DELETE CASCADE, @@ -771,6 +791,7 @@ CREATE TABLE item_value_tag_time_split ( --** ITEM > VALUE TAG > TIME SPLIT > REMOTE ITEM +-- <item> -> <podcast:value> -> <podcast:valueTimeSplit> -> <podcast:remoteItem> CREATE TABLE item_value_tag_time_split_remote_item ( id SERIAL PRIMARY KEY, item_value_tag_time_split_id INTEGER NOT NULL REFERENCES item_value_tag_time_split(id) ON DELETE CASCADE, @@ -782,6 +803,7 @@ CREATE TABLE item_value_tag_time_split_remote_item ( --** ITEM > VALUE TAG > TIME SPLIT > VALUE RECIPEINT +-- <item> -> <podcast:value> -> <podcast:valueTimeSplit> -> <podcast:valueRecipient> CREATE TABLE item_value_tag_time_split_receipient ( id SERIAL PRIMARY KEY, item_value_tag_time_split_id INTEGER NOT NULL REFERENCES item_value_tag_time_split(id) ON DELETE CASCADE, @@ -805,7 +827,10 @@ INSERT INTO live_item_status (status) VALUES ('pending'), ('live'), ('ended'); --** LIVE ITEM --- <podcast:liveItem> +-- Technically the live_item table could be named channel_live_item, +-- but for consistency with the item table, it is called live_item. + +-- <channel> -> <podcast:liveItem> CREATE TABLE live_item ( id SERIAL PRIMARY KEY, item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, From 22f4a8b54b38db8321ed4071c0df12ddffbf7b11 Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Sun, 18 Aug 2024 15:30:25 -0500 Subject: [PATCH 30/73] Move database sql files into migrations directory --- {docs/database => database/migrations}/0000_init_helpers.sql | 0 .../migrations}/0001_init_podcasting_20_database.sql | 0 {docs/database => database/migrations}/0002_account.sql | 0 {docs/database => database/migrations}/0003_clip.sql | 0 {docs/database => database/migrations}/0004_playlist.sql | 0 {docs/database => database/migrations}/0005_queue_resource.sql | 0 .../migrations}/0006_account_following_tables.sql | 0 7 files changed, 0 insertions(+), 0 deletions(-) rename {docs/database => database/migrations}/0000_init_helpers.sql (100%) rename {docs/database => database/migrations}/0001_init_podcasting_20_database.sql (100%) rename {docs/database => database/migrations}/0002_account.sql (100%) rename {docs/database => database/migrations}/0003_clip.sql (100%) rename {docs/database => database/migrations}/0004_playlist.sql (100%) rename {docs/database => database/migrations}/0005_queue_resource.sql (100%) rename {docs/database => database/migrations}/0006_account_following_tables.sql (100%) diff --git a/docs/database/0000_init_helpers.sql b/database/migrations/0000_init_helpers.sql similarity index 100% rename from docs/database/0000_init_helpers.sql rename to database/migrations/0000_init_helpers.sql diff --git a/docs/database/0001_init_podcasting_20_database.sql b/database/migrations/0001_init_podcasting_20_database.sql similarity index 100% rename from docs/database/0001_init_podcasting_20_database.sql rename to database/migrations/0001_init_podcasting_20_database.sql diff --git a/docs/database/0002_account.sql b/database/migrations/0002_account.sql similarity index 100% rename from docs/database/0002_account.sql rename to database/migrations/0002_account.sql diff --git a/docs/database/0003_clip.sql b/database/migrations/0003_clip.sql similarity index 100% rename from docs/database/0003_clip.sql rename to database/migrations/0003_clip.sql diff --git a/docs/database/0004_playlist.sql b/database/migrations/0004_playlist.sql similarity index 100% rename from docs/database/0004_playlist.sql rename to database/migrations/0004_playlist.sql diff --git a/docs/database/0005_queue_resource.sql b/database/migrations/0005_queue_resource.sql similarity index 100% rename from docs/database/0005_queue_resource.sql rename to database/migrations/0005_queue_resource.sql diff --git a/docs/database/0006_account_following_tables.sql b/database/migrations/0006_account_following_tables.sql similarity index 100% rename from docs/database/0006_account_following_tables.sql rename to database/migrations/0006_account_following_tables.sql From 00fc44394f6dd5cceed27f93745712a9f24667ef Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Sun, 18 Aug 2024 15:39:15 -0500 Subject: [PATCH 31/73] Add combine_all_migrations script --- database/combined/init_database.sql | 1134 ++++++++++++++++++++ database/scripts/combine_all_migrations.sh | 26 + 2 files changed, 1160 insertions(+) create mode 100644 database/combined/init_database.sql create mode 100755 database/scripts/combine_all_migrations.sh diff --git a/database/combined/init_database.sql b/database/combined/init_database.sql new file mode 100644 index 0000000..b0bf99d --- /dev/null +++ b/database/combined/init_database.sql @@ -0,0 +1,1134 @@ +-- 0000 migration + +-- Helpers + +-- In the previous version of the app, short_id was 7-14 characters long. +-- To make migration to v2 easier, we will use a 15 character long short_id, +-- so we can easily distinguish between v1 and v2 short_ids. +CREATE DOMAIN short_id_v2 AS VARCHAR(15); + +CREATE DOMAIN varchar_short AS VARCHAR(50); +CREATE DOMAIN varchar_normal AS VARCHAR(255); +CREATE DOMAIN varchar_long AS VARCHAR(2500); + +CREATE DOMAIN varchar_email AS VARCHAR(255) CHECK (VALUE ~ '^.+@.+\..+$'); +CREATE DOMAIN varchar_fqdn AS VARCHAR(253); +CREATE DOMAIN varchar_guid AS VARCHAR(36); +CREATE DOMAIN varchar_password AS VARCHAR(36); +CREATE DOMAIN varchar_slug AS VARCHAR(100); +CREATE DOMAIN varchar_uri AS VARCHAR(2083); +CREATE DOMAIN varchar_url AS VARCHAR(2083) CHECK (VALUE ~ '^https?://|^http?://'); + +CREATE DOMAIN server_time AS BIGINT; +CREATE DOMAIN server_time_with_default AS BIGINT DEFAULT EXTRACT(EPOCH FROM NOW()); + +CREATE DOMAIN media_player_time AS NUMERIC(10, 2); +CREATE DOMAIN list_position AS NUMERIC(22, 21); +CREATE DOMAIN numeric_20_11 AS NUMERIC(20, 11); + +-- Function to set created_at and updated_at +CREATE OR REPLACE FUNCTION set_updated_at_field() +RETURNS TRIGGER AS $$ +BEGIN + NEW.updated_at := EXTRACT(EPOCH FROM NOW()); + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +-- 0001 migration + +/* + +PODCASTING 2.0 DATABASE SCHEMA + +- The `id` column is a SERIAL column that is used as the primary key for every table. + +- The `id_text` column is only intended for tables where the data is available as urls. + For example, https://podverse.fm/podcast/abc123def456, the `id_text` column would be `abc123def456`. + +- The `slug` column is not required, but functions as an alternative for `id_text`. + For example, https://podverse.fm/podcast/podcasting-20 would have a `slug` column with the value `podcasting-20`. + +- The `podcast_index_id` ensures that our database only contains feed data that is available in the Podcast Index API. + +*/ + +----------** GLOBAL REFERENCE TABLES **---------- +-- These tables are referenced across many tables, and must be created first. + +--** CATEGORY + +-- Allowed category values align with the standard categories and subcategories +-- supported by Apple iTunes through the <itunes:category> tag. +-- +CREATE TABLE category ( + id SERIAL PRIMARY KEY, + node_text varchar_normal NOT NULL, -- <itunes:category> + display_name varchar_normal NOT NULL, -- our own display name for the category + slug varchar_normal NOT NULL -- our own slug for the category +); + +--** MEDIUM VALUE + +-- <podcast:medium> +CREATE TABLE medium_value ( + id SERIAL PRIMARY KEY, + value TEXT UNIQUE CHECK (VALUE IN ( + 'publisher', + 'podcast', 'music', 'video', 'film', 'audiobook', 'newsletter', 'blog', 'publisher', 'course', + 'mixed', 'podcastL', 'musicL', 'videoL', 'filmL', 'audiobookL', 'newsletterL', 'blogL', 'publisherL', 'courseL' + )) +); + +INSERT INTO medium_value (value) VALUES + ('publisher'), + ('podcast'), ('music'), ('video'), ('film'), ('audiobook'), ('newsletter'), ('blog'), ('course'), + ('mixed'), ('podcastL'), ('musicL'), ('videoL'), ('filmL'), ('audiobookL'), ('newsletterL'), ('blogL'), ('publisherL'), ('courseL') +; + +----------** TABLES **---------- + +--** FEED > FLAG STATUS + +-- used internally for identifying and handling spam and other special flag statuses. +CREATE TABLE feed_flag_status ( + id SERIAL PRIMARY KEY, + status TEXT UNIQUE CHECK (status IN ('none', 'spam', 'takedown', 'other', 'always-allow')), + created_at server_time_with_default, + updated_at server_time_with_default +); + +CREATE TRIGGER set_updated_at_feed_flag_status +BEFORE UPDATE ON feed_flag_status +FOR EACH ROW +EXECUTE FUNCTION set_updated_at_field(); + +INSERT INTO feed_flag_status (status) VALUES ('none'), ('spam'), ('takedown'), ('other'), ('always-allow'); + +--** FEED + +-- The top-level table for storing feed data, and internal parsing data. +CREATE TABLE feed ( + id SERIAL PRIMARY KEY, + url varchar_url UNIQUE NOT NULL, + + -- feed flag + feed_flag_status_id INTEGER NOT NULL REFERENCES feed_flag_status(id), + + -- internal + + -- Used to prevent another thread from parsing the same feed. + -- Set to current time at beginning of parsing, and NULL at end of parsing. + -- This is to prevent multiple threads from parsing the same feed. + -- If is_parsing is over X minutes old, assume last parsing failed and proceed to parse. + is_parsing server_time, + + -- 0 will only be parsed when PI API reports an update. + -- higher parsing_priority will be parsed more frequently on a schedule. + parsing_priority INTEGER DEFAULT 0 CHECK (parsing_priority BETWEEN 0 AND 5), + + -- the run-time environment container id + container_id VARCHAR(12), + + created_at server_time_with_default, + updated_at server_time_with_default +); + +CREATE TRIGGER set_updated_at_feed +BEFORE UPDATE ON feed +FOR EACH ROW +EXECUTE FUNCTION set_updated_at_field(); + +CREATE TABLE feed_log ( + id SERIAL PRIMARY KEY, + feed_id INTEGER NOT NULL REFERENCES feed(id) ON DELETE CASCADE, + last_http_status INTEGER, + last_crawl_time server_time, + last_good_http_status_time server_time, + last_parse_time server_time, + last_update_time server_time, + crawl_errors INTEGER DEFAULT 0, + parse_errors INTEGER DEFAULT 0 +); + +--** CHANNEL + +-- <channel> +CREATE TABLE channel ( + id SERIAL PRIMARY KEY, + id_text short_id_v2 UNIQUE NOT NULL, + slug varchar_slug, + feed_id INTEGER NOT NULL REFERENCES feed(id) ON DELETE CASCADE, + podcast_index_id INTEGER UNIQUE NOT NULL, + podcast_guid UUID UNIQUE, -- <podcast:guid> + title varchar_normal, + sortable_title varchar_short, -- all lowercase, ignores articles at beginning of title + medium_value_id INTEGER REFERENCES medium_value(id), + + -- TODO: should we hash the last parsed feed, so we can compare it to the hash of + -- a feed before completely parsing it, to check if it has changed before continuing? + + -- channels that have a PI value tag require special handling to request value_tag data + -- from the Podcast Index API. + has_podcast_index_value_tags BOOLEAN DEFAULT FALSE, + + -- hidden items are no longer available in the rss feed, but are still in the database. + hidden BOOLEAN DEFAULT FALSE, + -- markedForDeletion items are no longer available in the rss feed, and may be able to be deleted. + marked_for_deletion BOOLEAN DEFAULT FALSE +); + +CREATE UNIQUE INDEX channel_podcast_guid_unique ON channel(podcast_guid) WHERE podcast_guid IS NOT NULL; +CREATE UNIQUE INDEX channel_slug ON channel(slug) WHERE slug IS NOT NULL; + +--** CHANNEL > ABOUT > ITUNES TYPE + +-- <channel> -> <itunes:type> +CREATE TABLE channel_itunes_type ( + id SERIAL PRIMARY KEY, + itunes_type TEXT UNIQUE CHECK (itunes_type IN ('episodic', 'serial')) +); + +INSERT INTO channel_itunes_type (itunes_type) VALUES ('episodic'), ('serial'); + +--** CHANNEL > ABOUT + +-- various <channel> child data from multiple tags +CREATE TABLE channel_about ( + id SERIAL PRIMARY KEY, + channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, + author varchar_normal, -- <itunes:author> and <author> + episode_count INTEGER, -- aggregated count for convenience + explicit BOOLEAN, -- <itunes:explicit> + itunes_type_id INTEGER REFERENCES channel_itunes_type(id), + language varchar_short NOT NULL, -- <language> + website_link_url varchar_url -- <link> +); + +--** CHANNEL > CATEGORY + +CREATE TABLE channel_category ( + id SERIAL PRIMARY KEY, + channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, + parent_id INTEGER REFERENCES channel_category(id) ON DELETE CASCADE +); + +--** CHANNEL > CHAT + +-- <channel> -> <podcast:chat> +CREATE TABLE channel_chat ( + id SERIAL PRIMARY KEY, + channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, + server varchar_fqdn NOT NULL, + protocol varchar_short, + account_id varchar_normal, + space varchar_normal +); + +--** CHANNEL > DESCRIPTION + +-- <channel> -> <description> AND possibly other tags that contain a description +CREATE TABLE channel_description ( + id SERIAL PRIMARY KEY, + channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, + UNIQUE (channel_id), + value varchar_long NOT NULL +); + +--** CHANNEL > FUNDING + +-- <channel> -> <podcast:funding> +CREATE TABLE channel_funding ( + id SERIAL PRIMARY KEY, + channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, + url varchar_url NOT NULL, + title varchar_normal +); + +--** CHANNEL > IMAGE + +-- <channel> -> <podcast:image> AND all other image tags in the rss feed +CREATE TABLE channel_image ( + id SERIAL PRIMARY KEY, + channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, + url varchar_url NOT NULL, + image_width_size INTEGER, -- <podcast:image> must have a width specified, but older image tags will not, so allow null. + + -- If true, then the image is hosted by us in a service like S3. + -- When is_resized images are deleted, the corresponding image in S3 + -- should also be deleted. + is_resized BOOLEAN DEFAULT FALSE +); + +--** CHANNEL > INTERNAL SETTINGS + +CREATE TABLE channel_internal_settings ( + id SERIAL PRIMARY KEY, + channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, + -- needed to approve which web domains can override the player with query params. + -- this prevents malicious parties from misrepresenting the podcast contents on another website. + embed_approved_media_url_paths TEXT +); + +--** CHANNEL > LICENSE + +-- <channel> -> <podcast:license> +CREATE TABLE channel_license ( + id SERIAL PRIMARY KEY, + channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, + UNIQUE (channel_id), + type varchar_normal NOT NULL, + url varchar_url NOT NULL +); + +--** CHANNEL > LOCATION + +-- <channel> -> <podcast:location> +CREATE TABLE channel_location ( + id SERIAL PRIMARY KEY, + channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, + geo varchar_normal, + osm varchar_normal, + CHECK ( + (geo IS NOT NULL AND osm IS NULL) OR + (geo IS NULL AND osm IS NOT NULL) + ) +); + +--** CHANNEL > PERSON + +-- <channel> -> <podcast:person> +CREATE TABLE channel_person ( + id SERIAL PRIMARY KEY, + channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, + name varchar_normal, + role varchar_normal, + person_group varchar_normal DEFAULT 'cast', -- group is a reserved keyword in sql + img varchar_url, + href varchar_url +); + +--** CHANNEL > PODROLL + +-- <channel> -> <podcast:podroll> +CREATE TABLE channel_podroll ( + id SERIAL PRIMARY KEY, + channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE +); + +--** CHANNEL > PODROLL > REMOTE ITEM + +-- <channel> -> <podcast:podroll> --> <podcast:remoteItem> +CREATE TABLE channel_podroll_remote_item ( + id SERIAL PRIMARY KEY, + channel_podroll_id INTEGER NOT NULL REFERENCES channel_podroll(id) ON DELETE CASCADE, + feed_guid UUID NOT NULL, + feed_url varchar_url, + item_guid varchar_uri, + title varchar_normal, + medium_value_id INTEGER REFERENCES medium_value(id) +); + +--** CHANNEL > PUBLISHER + +-- <channel> -> <podcast:publisher> +CREATE TABLE channel_publisher ( + id SERIAL PRIMARY KEY, + channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE +); + +--** CHANNEL > PUBLISHER > REMOTE ITEM + +-- <channel> -> <podcast:publisher> -> <podcast:remoteItem> +CREATE TABLE channel_publisher_remote_item ( + id SERIAL PRIMARY KEY, + channel_publisher_id INTEGER NOT NULL REFERENCES channel_publisher(id) ON DELETE CASCADE, + feed_guid UUID NOT NULL, + feed_url varchar_url, + item_guid varchar_uri, + title varchar_normal, + medium_value_id INTEGER REFERENCES medium_value(id) +); + +--** CHANNEL > REMOTE ITEM + +-- Remote items at the channel level are only used when the <podcast:medium> for the channel +-- is set to 'mixed' or another list medium like 'podcastL'. + +-- <channel> -> <podcast:remoteItem> +CREATE TABLE channel_remote_item ( + id SERIAL PRIMARY KEY, + channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, + feed_guid UUID NOT NULL, + feed_url varchar_url, + item_guid varchar_uri, + title varchar_normal, + medium_value_id INTEGER REFERENCES medium_value(id) +); + +--** CHANNEL > SEASON + +-- channels with seasons need to be rendered in client apps differently. +-- you can only determine if a channel is in a "season" format is by finding +-- the <itunes:season> tag in an item in that channel. + +-- NOTE: A channel season does not exist in the Podcasting 2.0 spec, +-- but it is useful for organizing seasons at the channel level, +-- and could be in the P2.0 spec someday. + +CREATE TABLE channel_season ( + id SERIAL PRIMARY KEY, + channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, + number INTEGER NOT NULL, + UNIQUE (channel_id, number), + name varchar_normal +); + +--** CHANNEL > SOCIAL INTERACT + +-- <channel> -> <podcast:socialInteract> +CREATE TABLE channel_social_interact ( + id SERIAL PRIMARY KEY, + channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, + protocol varchar_short NOT NULL, + uri varchar_uri NOT NULL, + account_id varchar_normal, + account_url varchar_url, + priority INTEGER +); + +--** CHANNEL > TRAILER + +-- <channel> -> <podcast:trailer> +CREATE TABLE channel_trailer ( + id SERIAL PRIMARY KEY, + channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, + title varchar_normal, + url varchar_url NOT NULL, + pub_date TIMESTAMPTZ NOT NULL, + length INTEGER, + type varchar_short, + season INTEGER +); + +--** CHANNEL > TXT TAG + +-- <channel> -> <podcast:txt> +CREATE TABLE channel_txt_tag ( + id SERIAL PRIMARY KEY, + channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, + verify varchar_normal NOT NULL, + value varchar_long NOT NULL +); + +--** CHANNEL > VALUE TAG + +-- <channel> -> <podcast:value> +CREATE TABLE channel_value_tag ( + id SERIAL PRIMARY KEY, + channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, + type varchar_short NOT NULL, + method varchar_short NOT NULL, + suggested FLOAT +); + +--** CHANNEL > VALUE TAG > RECEIPIENT + +-- <channel> -> <podcast:value> -> <podcast:valueRecipient> +CREATE TABLE channel_value_tag_receipient ( + id SERIAL PRIMARY KEY, + channel_value_tag_id INTEGER NOT NULL REFERENCES channel_value_tag(id) ON DELETE CASCADE, + type varchar_short NOT NULL, + address varchar_long NOT NULL, + split FLOAT NOT NULL, + name varchar_normal, + custom_key varchar_long, + custom_value varchar_long, + fee BOOLEAN DEFAULT FALSE +); + +--** CHANNEL > VALUE TAG > TIME SPLIT + +-- <channel> -> <podcast:valueTimeSplit> +CREATE TABLE channel_value_tag_time_split ( + id SERIAL PRIMARY KEY, + channel_value_tag_id INTEGER NOT NULL REFERENCES channel_value_tag(id) ON DELETE CASCADE, + start_time INTEGER NOT NULL, + duration INTEGER NOT NULL, + remote_start_time INTEGER DEFAULT 0, + remote_percentage INTEGER DEFAULT 100 +); + +--** CHANNEL > VALUE TAG > TIME SPLIT > REMOTE ITEM + +-- <channel> -> <podcast:value> -> <podcast:valueTimeSplit> -> <podcast:remoteItem> +CREATE TABLE channel_value_tag_time_split_remote_item ( + id SERIAL PRIMARY KEY, + channel_value_tag_time_split_id INTEGER NOT NULL REFERENCES channel_value_tag_time_split(id) ON DELETE CASCADE, + feed_guid UUID NOT NULL, + feed_url varchar_url, + item_guid varchar_uri, + title varchar_normal +); + +--** CHANNEL > VALUE TAG > TIME SPLIT > VALUE RECIPEINT + +-- <channel> -> <podcast:value> -> <podcast:valueTimeSplit> -> <podcast:valueRecipient> +CREATE TABLE channel_value_tag_time_split_receipient ( + id SERIAL PRIMARY KEY, + channel_value_tag_time_split_id INTEGER NOT NULL REFERENCES channel_value_tag_time_split(id) ON DELETE CASCADE, + type varchar_short NOT NULL, + address varchar_long NOT NULL, + split FLOAT NOT NULL, + name varchar_normal, + custom_key varchar_long, + custom_value varchar_long, + fee BOOLEAN DEFAULT FALSE +); + +--** ITEM + +-- Technically the item table could be named channel_item, but it seems easier to understand as item. + +-- <channel> -> <item> +CREATE TABLE item ( + id SERIAL PRIMARY KEY, + id_text short_id_v2 UNIQUE NOT NULL, + slug varchar_slug, + channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, + guid varchar_uri, -- <guid> + pub_date TIMESTAMPTZ, -- <pubDate> + title varchar_normal, -- <title> + + -- hidden items are no longer available in the rss feed, but are still in the database. + hidden BOOLEAN DEFAULT FALSE, + -- markedForDeletion items are no longer available in the rss feed, and may be able to be deleted. + marked_for_deletion BOOLEAN DEFAULT FALSE +); + +CREATE UNIQUE INDEX item_slug ON item(slug) WHERE slug IS NOT NULL; + +--** ITEM > ABOUT > ITUNES TYPE + +-- <item> -> <itunes:episodeType> +CREATE TABLE item_itunes_episode_type ( + id SERIAL PRIMARY KEY, + itunes_episode_type TEXT UNIQUE CHECK (itunes_episode_type IN ('full', 'trailer', 'bonus')) +); + +INSERT INTO item_itunes_episode_type (itunes_episode_type) VALUES ('full'), ('trailer'), ('bonus'); + +--** ITEM > ABOUT + +CREATE TABLE item_about ( + id SERIAL PRIMARY KEY, + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + duration INTEGER, -- <itunes:duration> + explicit BOOLEAN, -- <itunes:explicit> + website_link_url varchar_url, -- <link> + item_itunes_episode_type_id INTEGER REFERENCES item_itunes_episode_type(id) -- <itunes:episodeType> +); + +--** ITEM > CONTENT LINK + +-- <item> -> <podcast:contentLink> +CREATE TABLE content_link ( + id SERIAL PRIMARY KEY, + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + href varchar_url NOT NULL, + title varchar_normal +); + +--** ITEM > CHAPTERS + +-- <item> -> <podcast:chapters> +CREATE TABLE item_chapters ( + id SERIAL PRIMARY KEY, + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + url varchar_url NOT NULL, + type varchar_short NOT NULL, + last_http_status INTEGER, + last_crawl_time server_time, + last_good_http_status_time server_time, + last_parse_time server_time, + last_update_time server_time, + crawl_errors INTEGER DEFAULT 0, + parse_errors INTEGER DEFAULT 0 +); + +-- -- <item> -> <podcast:chapters> -> chapter items correspond with jsonChapters.md example file +CREATE TABLE item_chapter ( + id SERIAL PRIMARY KEY, + text_id short_id_v2 UNIQUE NOT NULL, + item_chapters_file_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + + -- the hash is used for comparison, to determine if new chapters should be inserted + -- after re-parsing an existing chapters file. + hash varchar_guid NOT NULL, + + start_time media_player_time NOT NULL, + end_time media_player_time, + title varchar_normal, + web_url varchar_url, + table_of_contents BOOLEAN DEFAULT TRUE +); + +--** ITEM > CHAPTER > IMAGE + +-- <item> -> <podcast:chapters> -> chapter items correspond with jsonChapters.md example file +CREATE TABLE item_chapter_image ( + id SERIAL PRIMARY KEY, + item_chapter_id INTEGER NOT NULL REFERENCES item_chapter(id) ON DELETE CASCADE, + url varchar_url NOT NULL, + image_width_size INTEGER, -- <podcast:image> must have a width specified, but older image tags will not, so allow null. + + -- If true, then the image is hosted by us in a service like S3. + -- When is_resized images are deleted, the corresponding image in S3 + -- should also be deleted. + is_resized BOOLEAN DEFAULT FALSE +); + +--** ITEM > CHAPTER > LOCATION + +-- <item> -> <podcast:chapters> -> chapter items correspond with jsonChapters.md example file +CREATE TABLE item_chapter_location ( + id SERIAL PRIMARY KEY, + item_chapter_id INTEGER NOT NULL REFERENCES item_chapter(id) ON DELETE CASCADE, + geo varchar_normal, + osm varchar_normal, + CHECK ( + (geo IS NOT NULL AND osm IS NULL) OR + (geo IS NULL AND osm IS NOT NULL) + ) +); + +--** ITEM > CHAT + +-- <item> -> <podcast:chat> +CREATE TABLE item_chat ( + id SERIAL PRIMARY KEY, + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + server varchar_fqdn NOT NULL, + protocol varchar_short, + account_id varchar_normal, + space varchar_normal +); + +--** ITEM > DESCRIPTION + +-- <item> -> <description> AND possibly other tags that contain a description +CREATE TABLE item_description ( + id SERIAL PRIMARY KEY, + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + UNIQUE (item_id), + value varchar_long NOT NULL +); + +--** ITEM > ENCLOSURE (AKA ALTERNATE ENCLOSURE) + +-- NOTE: the older <enclosure> tag style is integrated into the item_enclosure table. + +-- <item> -> <podcast:alternateEnclosure> AND <item> -> <enclosure> +CREATE TABLE item_enclosure ( + id SERIAL PRIMARY KEY, + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + type varchar_short NOT NULL, + length INTEGER, + bitrate INTEGER, + height INTEGER, + language varchar_short, + title varchar_short, + rel varchar_short, + codecs varchar_short, + item_enclosure_default BOOLEAN DEFAULT FALSE +); + +-- <item> -> <podcast:alternateEnclosure> -> <podcast:source> +CREATE TABLE item_enclosure_source ( + id SERIAL PRIMARY KEY, + item_enclosure_id INTEGER NOT NULL REFERENCES item_enclosure(id) ON DELETE CASCADE, + uri varchar_uri NOT NULL, + content_type varchar_short +); + +-- <item> -> <podcast:alternateEnclosure> -> <podcast:integrity> +CREATE TABLE item_enclosure_integrity ( + id SERIAL PRIMARY KEY, + item_enclosure_id INTEGER NOT NULL REFERENCES item_enclosure_source(id) ON DELETE CASCADE, + type TEXT NOT NULL CHECK (type IN ('sri', 'pgp-signature')), + value varchar_long NOT NULL +); + +--** ITEM > FUNDING + +-- <item> -> <podcast:funding> +CREATE TABLE item_funding ( + id SERIAL PRIMARY KEY, + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + url varchar_url NOT NULL, + title varchar_normal +); + +--** ITEM > IMAGE + +-- <item> -> <podcast:image> AND all other image tags in the rss feed +CREATE TABLE item_image ( + id SERIAL PRIMARY KEY, + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + url varchar_url NOT NULL, + image_width_size INTEGER, -- <podcast:image> must have a width specified, but older image tags will not, so allow null. + + -- If true, then the image is hosted by us in a service like S3. + -- When is_resized images are deleted, the corresponding image in S3 + -- should also be deleted. + is_resized BOOLEAN DEFAULT FALSE +); + +--** ITEM > LICENSE + +-- <item> -> <podcast:license> +CREATE TABLE item_license ( + id SERIAL PRIMARY KEY, + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + UNIQUE (item_id), + type varchar_normal NOT NULL, + url varchar_url NOT NULL +); + +--** ITEM > LOCATION + +-- <item> -> <podcast:location> +CREATE TABLE item_location ( + id SERIAL PRIMARY KEY, + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + geo varchar_normal, + osm varchar_normal, + CHECK ( + (geo IS NOT NULL AND osm IS NULL) OR + (geo IS NULL AND osm IS NOT NULL) + ) +); + +--** ITEM > PERSON + +-- <item> -> <podcast:person> +CREATE TABLE item_person ( + id SERIAL PRIMARY KEY, + channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, + name varchar_normal, + role varchar_normal, + person_group varchar_normal DEFAULT 'cast', -- group is a reserved keyword in sql + img varchar_url, + href varchar_url +); + +--** ITEM > SEASON + +-- <item> -> <podcast:season> +CREATE TABLE item_season ( + id SERIAL PRIMARY KEY, + channel_season_id INTEGER NOT NULL REFERENCES channel_season(id) ON DELETE CASCADE, + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + title varchar_normal +); + +--** ITEM > SEASON > EPISODE + +-- <item> -> <podcast:season> -> <podcast:episode> +CREATE TABLE item_season_episode ( + id SERIAL PRIMARY KEY, + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + display varchar_short, + episode_number FLOAT NOT NULL +); + +--** ITEM > SOCIAL INTERACT + +-- <item> -> <podcast:socialInteract> +CREATE TABLE item_social_interact ( + id SERIAL PRIMARY KEY, + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + protocol varchar_short NOT NULL, + uri varchar_uri NOT NULL, + account_id varchar_normal, + account_url varchar_url, + priority INTEGER +); + +--** ITEM > SOUNDBITE + +-- <item> -> <podcast:soundbite> +CREATE TABLE item_soundbite ( + id SERIAL PRIMARY KEY, + id_text short_id_v2 UNIQUE NOT NULL, + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + url varchar_url NOT NULL, + start_time INTEGER NOT NULL, + duration INTEGER NOT NULL, + title varchar_normal +); + +--** ITEM > TRANSCRIPT + +-- <item> -> <podcast:transcript> +CREATE TABLE item_transcript ( + id SERIAL PRIMARY KEY, + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + url varchar_url NOT NULL, + type varchar_short NOT NULL, + language varchar_short, + rel VARCHAR(50) CHECK (rel IS NULL OR rel = 'captions') +); + +--** ITEM > TXT TAG + +-- <item> -> <podcast:txt> +CREATE TABLE item_txt_tag ( + id SERIAL PRIMARY KEY, + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + verify varchar_normal NOT NULL, + value varchar_long NOT NULL +); + +--** ITEM > VALUE TAG + +-- <item> -> <podcast:value> +CREATE TABLE item_value_tag ( + id SERIAL PRIMARY KEY, + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + type varchar_short NOT NULL, + method varchar_short NOT NULL, + suggested FLOAT +); + +--** ITEM > VALUE TAG > RECEIPIENT + +-- <item> -> <podcast:value> -> <podcast:valueRecipient> +CREATE TABLE item_value_tag_receipient ( + id SERIAL PRIMARY KEY, + item_value_tag_id INTEGER NOT NULL REFERENCES item_value_tag(id) ON DELETE CASCADE, + type varchar_short NOT NULL, + address varchar_long NOT NULL, + split FLOAT NOT NULL, + name varchar_normal, + custom_key varchar_long, + custom_value varchar_long, + fee BOOLEAN DEFAULT FALSE +); + +--** ITEM > VALUE TAG > TIME SPLIT + +-- <item> -> <podcast:value> -> <podcast:valueTimeSplit> +CREATE TABLE item_value_tag_time_split ( + id SERIAL PRIMARY KEY, + item_value_tag_id INTEGER NOT NULL REFERENCES item_value_tag(id) ON DELETE CASCADE, + start_time INTEGER NOT NULL, + duration INTEGER NOT NULL, + remote_start_time INTEGER DEFAULT 0, + remote_percentage INTEGER DEFAULT 100 +); + +--** ITEM > VALUE TAG > TIME SPLIT > REMOTE ITEM + +-- <item> -> <podcast:value> -> <podcast:valueTimeSplit> -> <podcast:remoteItem> +CREATE TABLE item_value_tag_time_split_remote_item ( + id SERIAL PRIMARY KEY, + item_value_tag_time_split_id INTEGER NOT NULL REFERENCES item_value_tag_time_split(id) ON DELETE CASCADE, + feed_guid UUID NOT NULL, + feed_url varchar_url, + item_guid varchar_uri, + title varchar_normal +); + +--** ITEM > VALUE TAG > TIME SPLIT > VALUE RECIPEINT + +-- <item> -> <podcast:value> -> <podcast:valueTimeSplit> -> <podcast:valueRecipient> +CREATE TABLE item_value_tag_time_split_receipient ( + id SERIAL PRIMARY KEY, + item_value_tag_time_split_id INTEGER NOT NULL REFERENCES item_value_tag_time_split(id) ON DELETE CASCADE, + type varchar_short NOT NULL, + address varchar_long NOT NULL, + split FLOAT NOT NULL, + name varchar_normal, + custom_key varchar_long, + custom_value varchar_long, + fee BOOLEAN DEFAULT FALSE +); + +--** LIVE ITEM > STATUS + +CREATE TABLE live_item_status ( + id SERIAL PRIMARY KEY, + status TEXT UNIQUE CHECK (status IN ('pending', 'live', 'ended')) +); + +INSERT INTO live_item_status (status) VALUES ('pending'), ('live'), ('ended'); + +--** LIVE ITEM + +-- Technically the live_item table could be named channel_live_item, +-- but for consistency with the item table, it is called live_item. + +-- <channel> -> <podcast:liveItem> +CREATE TABLE live_item ( + id SERIAL PRIMARY KEY, + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + live_item_status_id INTEGER NOT NULL REFERENCES live_item_status(id), + start_time TIMESTAMPTZ NOT NULL, + end_time TIMESTAMPTZ, + chat_web_url varchar_url +); + + +-- 0002 migration + +CREATE TABLE sharable_status ( + id SERIAL PRIMARY KEY, + status TEXT UNIQUE CHECK (status IN ('public', 'unlisted', 'private')) +); + +INSERT INTO sharable_status (status) VALUES ('public'), ('unlisted'), ('private'); + +CREATE TABLE account ( + id SERIAL PRIMARY KEY, + id_text short_id_v2 UNIQUE NOT NULL, + verified BOOLEAN DEFAULT FALSE, + sharable_status_id INTEGER NOT NULL REFERENCES sharable_status(id) +); + +CREATE TABLE account_credentials ( + id SERIAL PRIMARY KEY, + account_id integer REFERENCES account(id) ON DELETE CASCADE, + email varchar_email UNIQUE NOT NULL, + password varchar_password NOT NULL +); + +CREATE TABLE account_profile ( + id SERIAL PRIMARY KEY, + account_id integer REFERENCES account(id) ON DELETE CASCADE, + display_name varchar_normal, + bio varchar_long +); + +CREATE TABLE account_reset_password ( + id SERIAL PRIMARY KEY, + account_id integer REFERENCES account(id) ON DELETE CASCADE, + reset_token varchar_guid, + reset_token_expires_at TIMESTAMP +); + +CREATE TABLE account_verification ( + id SERIAL PRIMARY KEY, + account_id integer REFERENCES account(id) ON DELETE CASCADE, + verification_token varchar_guid, + verification_token_expires_at TIMESTAMP +); + +CREATE TABLE account_membership ( + id SERIAL PRIMARY KEY, + tier TEXT UNIQUE CHECK (tier IN ('trial', 'basic')) +); + +INSERT INTO account_membership (tier) VALUES ('trial'), ('basic'); + +CREATE TABLE account_membership_status ( + id SERIAL PRIMARY KEY, + account_id integer REFERENCES account(id) ON DELETE CASCADE, + account_membership_id INTEGER NOT NULL REFERENCES account_membership(id), + membership_expires_at TIMESTAMP +); + +CREATE TABLE account_admin_roles ( + id SERIAL PRIMARY KEY, + account_id integer REFERENCES account(id) ON DELETE CASCADE, + dev_admin BOOLEAN DEFAULT FALSE, + podping_admin BOOLEAN DEFAULT FALSE +); + +-- 0003 migration + +CREATE TABLE clip ( + id SERIAL PRIMARY KEY, + id_text short_id_v2 UNIQUE NOT NULL, + account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + start_time media_player_time NOT NULL, + end_time media_player_time, + title varchar_normal, + description varchar_long, + sharable_status_id INTEGER NOT NULL REFERENCES sharable_status(id) +); + +-- 0004 migration + +CREATE TABLE playlist ( + id SERIAL PRIMARY KEY, + id_text short_id_v2 UNIQUE NOT NULL, + account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, + sharable_status_id INTEGER NOT NULL REFERENCES sharable_status(id), + title varchar_normal, + description varchar_long, + is_default_favorites BOOLEAN DEFAULT FALSE, + is_public BOOLEAN DEFAULT FALSE, + item_count INTEGER DEFAULT 0, + medium_value_id INTEGER NOT NULL REFERENCES medium_value(id) +); + +CREATE TABLE playlist_resource_base ( + id SERIAL PRIMARY KEY, + playlist_id INTEGER NOT NULL REFERENCES playlist(id) ON DELETE CASCADE, + list_position list_position NOT NULL CHECK (list_position != 0 OR list_position = 0::numeric), + UNIQUE (playlist_id, list_position) +); + +CREATE TABLE playlist_resource_item ( + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE +) INHERITS (playlist_resource_base); + +CREATE TABLE playlist_resource_item_add_by_rss ( + resource_data jsonb NOT NULL +) INHERITS (playlist_resource_base); + +CREATE TABLE playlist_resource_item_chapter ( + item_chapter_id INTEGER NOT NULL REFERENCES item_chapter(id) ON DELETE CASCADE +) INHERITS (playlist_resource_base); + +CREATE TABLE playlist_resource_clip ( + clip_id INTEGER NOT NULL REFERENCES clip(id) ON DELETE CASCADE +) INHERITS (playlist_resource_base); + +CREATE TABLE playlist_resource_item_soundbite ( + soundbite_id INTEGER NOT NULL REFERENCES item_soundbite(id) ON DELETE CASCADE +) INHERITS (playlist_resource_base); + +CREATE OR REPLACE FUNCTION delete_playlist_resource_base() +RETURNS TRIGGER AS $$ +BEGIN + DELETE FROM playlist_resource_base WHERE id = OLD.id; + RETURN OLD; +END; +$$ LANGUAGE plpgsql; + +CREATE TRIGGER delete_playlist_resource_base_trigger_item +BEFORE DELETE ON playlist_resource_item +FOR EACH ROW +EXECUTE FUNCTION delete_playlist_resource_base(); + +CREATE TRIGGER delete_playlist_resource_base_trigger_item_add_by_rss +BEFORE DELETE ON playlist_resource_item_add_by_rss +FOR EACH ROW +EXECUTE FUNCTION delete_playlist_resource_base(); + +CREATE TRIGGER delete_playlist_resource_base_trigger_item_chapter +BEFORE DELETE ON playlist_resource_item_chapter +FOR EACH ROW +EXECUTE FUNCTION delete_playlist_resource_base(); + +CREATE TRIGGER delete_playlist_resource_base_trigger_clip +BEFORE DELETE ON playlist_resource_clip +FOR EACH ROW +EXECUTE FUNCTION delete_playlist_resource_base(); + +CREATE TRIGGER delete_playlist_resource_base_trigger_item_soundbite +BEFORE DELETE ON playlist_resource_item_soundbite +FOR EACH ROW +EXECUTE FUNCTION delete_playlist_resource_base(); + +-- 0005 migration + +CREATE TABLE queue_resource_base ( + id SERIAL PRIMARY KEY, + account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, + list_position list_position NOT NULL CHECK (list_position != 0 OR list_position = 0::numeric), + UNIQUE (account_id, list_position), + playback_position media_player_time NOT NULL DEFAULT 0, + media_file_duration FLOAT NOT NULL DEFAULT 0, + completed BOOLEAN NOT NULL DEFAULT FALSE +); + +CREATE TABLE queue_resource_item ( + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + UNIQUE (account_id) +) INHERITS (queue_resource_base); + +CREATE TABLE queue_resource_item_add_by_rss ( + resource_data jsonb NOT NULL, + UNIQUE (account_id) +) INHERITS (queue_resource_base); + +CREATE TABLE queue_resource_item_chapter ( + item_chapter_id INTEGER NOT NULL REFERENCES item_chapter(id) ON DELETE CASCADE, + UNIQUE (account_id) +) INHERITS (queue_resource_base); + +CREATE TABLE queue_resource_clip ( + clip_id INTEGER NOT NULL REFERENCES clip(id) ON DELETE CASCADE, + UNIQUE (account_id) +) INHERITS (queue_resource_base); + +CREATE TABLE queue_resource_item_soundbite ( + soundbite_id INTEGER NOT NULL REFERENCES item_soundbite(id) ON DELETE CASCADE, + UNIQUE (account_id) +) INHERITS (queue_resource_base); + +CREATE OR REPLACE FUNCTION delete_queue_resource_base() +RETURNS TRIGGER AS $$ +BEGIN + DELETE FROM queue_resource_base WHERE id = OLD.id; + RETURN OLD; +END; +$$ LANGUAGE plpgsql; + +CREATE TRIGGER delete_queue_resource_base_trigger_item +BEFORE DELETE ON queue_resource_item +FOR EACH ROW +EXECUTE FUNCTION delete_queue_resource_base(); + +CREATE TRIGGER delete_queue_resource_base_trigger_item_add_by_rss +BEFORE DELETE ON queue_resource_item_add_by_rss +FOR EACH ROW +EXECUTE FUNCTION delete_queue_resource_base(); + +CREATE TRIGGER delete_queue_resource_base_trigger_item_chapter +BEFORE DELETE ON queue_resource_item_chapter +FOR EACH ROW +EXECUTE FUNCTION delete_queue_resource_base(); + +CREATE TRIGGER delete_queue_resource_base_trigger_clip +BEFORE DELETE ON queue_resource_clip +FOR EACH ROW +EXECUTE FUNCTION delete_queue_resource_base(); + +CREATE TRIGGER delete_queue_resource_base_trigger_item_soundbite +BEFORE DELETE ON queue_resource_item_soundbite +FOR EACH ROW +EXECUTE FUNCTION delete_queue_resource_base(); + +-- 0006 migration + +CREATE TABLE account_following_account ( + account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, + following_account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, + PRIMARY KEY (account_id, following_account_id) +); + +CREATE TABLE account_following_channel ( + account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, + channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, + PRIMARY KEY (account_id, channel_id) +); + +CREATE TABLE account_following_playlist ( + account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, + playlist_id INTEGER NOT NULL REFERENCES playlist(id) ON DELETE CASCADE, + PRIMARY KEY (account_id, playlist_id) +); + +CREATE TABLE account_following_add_by_rss_channel ( + account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, + feed_url varchar_url NOT NULL, + PRIMARY KEY (account_id, feed_url), + title varchar_normal, + image_url varchar_url +); + diff --git a/database/scripts/combine_all_migrations.sh b/database/scripts/combine_all_migrations.sh new file mode 100755 index 0000000..d53732a --- /dev/null +++ b/database/scripts/combine_all_migrations.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +# Get the directory of the script +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +# Define the source and destination directories based on the script's location +SOURCE_DIR="$SCRIPT_DIR/../migrations" +DEST_DIR="$SCRIPT_DIR/../combined" +DEST_FILE="$DEST_DIR/init_database.sql" + +# Create the destination directory if it does not exist +mkdir -p "$DEST_DIR" + +# Create or clear the destination file +> "$DEST_FILE" + +# Iterate over all .sql files in the source directory +for file in "$SOURCE_DIR"/*.sql; +do + # Append the contents of each .sql file to the destination file + cat "$file" >> "$DEST_FILE" + # Add a newline for separation + echo "" >> "$DEST_FILE" +done + +echo "All .sql files have been combined into $DEST_FILE" From f8d42a66165a1cac315e6f2c33f918bedd0897d4 Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Sun, 18 Aug 2024 15:39:29 -0500 Subject: [PATCH 32/73] Add headers to migration files --- database/migrations/0000_init_helpers.sql | 2 ++ database/migrations/0001_init_podcasting_20_database.sql | 2 ++ database/migrations/0002_account.sql | 2 ++ database/migrations/0003_clip.sql | 2 ++ database/migrations/0004_playlist.sql | 2 ++ database/migrations/0005_queue_resource.sql | 2 ++ database/migrations/0006_account_following_tables.sql | 2 ++ 7 files changed, 14 insertions(+) diff --git a/database/migrations/0000_init_helpers.sql b/database/migrations/0000_init_helpers.sql index 7a946ff..61fba6d 100644 --- a/database/migrations/0000_init_helpers.sql +++ b/database/migrations/0000_init_helpers.sql @@ -1,3 +1,5 @@ +-- 0000 migration + -- Helpers -- In the previous version of the app, short_id was 7-14 characters long. diff --git a/database/migrations/0001_init_podcasting_20_database.sql b/database/migrations/0001_init_podcasting_20_database.sql index 55ffbe3..1d53a8b 100644 --- a/database/migrations/0001_init_podcasting_20_database.sql +++ b/database/migrations/0001_init_podcasting_20_database.sql @@ -1,3 +1,5 @@ +-- 0001 migration + /* PODCASTING 2.0 DATABASE SCHEMA diff --git a/database/migrations/0002_account.sql b/database/migrations/0002_account.sql index c4c317c..c6d417d 100644 --- a/database/migrations/0002_account.sql +++ b/database/migrations/0002_account.sql @@ -1,3 +1,5 @@ +-- 0002 migration + CREATE TABLE sharable_status ( id SERIAL PRIMARY KEY, status TEXT UNIQUE CHECK (status IN ('public', 'unlisted', 'private')) diff --git a/database/migrations/0003_clip.sql b/database/migrations/0003_clip.sql index fb907a8..0b6c135 100644 --- a/database/migrations/0003_clip.sql +++ b/database/migrations/0003_clip.sql @@ -1,3 +1,5 @@ +-- 0003 migration + CREATE TABLE clip ( id SERIAL PRIMARY KEY, id_text short_id_v2 UNIQUE NOT NULL, diff --git a/database/migrations/0004_playlist.sql b/database/migrations/0004_playlist.sql index c3ba865..3254307 100644 --- a/database/migrations/0004_playlist.sql +++ b/database/migrations/0004_playlist.sql @@ -1,3 +1,5 @@ +-- 0004 migration + CREATE TABLE playlist ( id SERIAL PRIMARY KEY, id_text short_id_v2 UNIQUE NOT NULL, diff --git a/database/migrations/0005_queue_resource.sql b/database/migrations/0005_queue_resource.sql index 5f069e4..dfd75aa 100644 --- a/database/migrations/0005_queue_resource.sql +++ b/database/migrations/0005_queue_resource.sql @@ -1,3 +1,5 @@ +-- 0005 migration + CREATE TABLE queue_resource_base ( id SERIAL PRIMARY KEY, account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, diff --git a/database/migrations/0006_account_following_tables.sql b/database/migrations/0006_account_following_tables.sql index d4d1f7a..27f4a3f 100644 --- a/database/migrations/0006_account_following_tables.sql +++ b/database/migrations/0006_account_following_tables.sql @@ -1,3 +1,5 @@ +-- 0006 migration + CREATE TABLE account_following_account ( account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, following_account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, From 128ac6d1924ec673e33f0446635f14598de847f2 Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Sun, 18 Aug 2024 16:20:47 -0500 Subject: [PATCH 33/73] Add notification tables including up_device and fcm_device --- database/combined/init_database.sql | 26 ++++++++++++++++++++++ database/migrations/0007_notifications.sql | 25 +++++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 database/migrations/0007_notifications.sql diff --git a/database/combined/init_database.sql b/database/combined/init_database.sql index b0bf99d..d130914 100644 --- a/database/combined/init_database.sql +++ b/database/combined/init_database.sql @@ -1132,3 +1132,29 @@ CREATE TABLE account_following_add_by_rss_channel ( image_url varchar_url ); +-- 0007 + +CREATE TABLE account_notification ( + channel_id INTEGER NOT NULL, + account_id INTEGER NOT NULL, + PRIMARY KEY (channel_id, account_id), + CONSTRAINT fk_channel FOREIGN KEY (channel_id) REFERENCES channel(id) ON DELETE CASCADE, + CONSTRAINT fk_account FOREIGN KEY (account_id) REFERENCES account(id) ON DELETE CASCADE +); + +CREATE TABLE account_up_device ( + account_id INTEGER NOT NULL, + up_endpoint varchar_url PRIMARY KEY, + up_public_key varchar_long NOT NULL, + up_auth_key varchar_long NOT NULL, + CONSTRAINT fk_account FOREIGN KEY (account_id) REFERENCES account(id) ON DELETE CASCADE +); + +CREATE DOMAIN varchar_fcm_token AS VARCHAR(255); + +CREATE TABLE account_fcm_device ( + fcm_token varchar_fcm_token PRIMARY KEY, + account_id INT NOT NULL, + CONSTRAINT fk_account FOREIGN KEY (account_id) REFERENCES account(id) ON DELETE CASCADE +); + diff --git a/database/migrations/0007_notifications.sql b/database/migrations/0007_notifications.sql new file mode 100644 index 0000000..a1a65d7 --- /dev/null +++ b/database/migrations/0007_notifications.sql @@ -0,0 +1,25 @@ +-- 0007 + +CREATE TABLE account_notification ( + channel_id INTEGER NOT NULL, + account_id INTEGER NOT NULL, + PRIMARY KEY (channel_id, account_id), + CONSTRAINT fk_channel FOREIGN KEY (channel_id) REFERENCES channel(id) ON DELETE CASCADE, + CONSTRAINT fk_account FOREIGN KEY (account_id) REFERENCES account(id) ON DELETE CASCADE +); + +CREATE TABLE account_up_device ( + account_id INTEGER NOT NULL, + up_endpoint varchar_url PRIMARY KEY, + up_public_key varchar_long NOT NULL, + up_auth_key varchar_long NOT NULL, + CONSTRAINT fk_account FOREIGN KEY (account_id) REFERENCES account(id) ON DELETE CASCADE +); + +CREATE DOMAIN varchar_fcm_token AS VARCHAR(255); + +CREATE TABLE account_fcm_device ( + fcm_token varchar_fcm_token PRIMARY KEY, + account_id INT NOT NULL, + CONSTRAINT fk_account FOREIGN KEY (account_id) REFERENCES account(id) ON DELETE CASCADE +); From 93375b9351d72cd28cf2e5da760fc7d35bb0a6c6 Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Sun, 18 Aug 2024 16:51:34 -0500 Subject: [PATCH 34/73] Add paypal, apple, and google purchase tables --- .../0008_purchases_paypal_apple_google.sql | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 database/migrations/0008_purchases_paypal_apple_google.sql diff --git a/database/migrations/0008_purchases_paypal_apple_google.sql b/database/migrations/0008_purchases_paypal_apple_google.sql new file mode 100644 index 0000000..5421070 --- /dev/null +++ b/database/migrations/0008_purchases_paypal_apple_google.sql @@ -0,0 +1,49 @@ +-- 0008 + +CREATE TABLE account_paypal_order ( + account_id INT NOT NULL, + CONSTRAINT fk_account FOREIGN KEY (account_id) REFERENCES account(id) ON DELETE CASCADE, + payment_id VARCHAR PRIMARY KEY, + state VARCHAR +); + +CREATE TABLE account_app_store_purchase ( + account_id INT NOT NULL, + CONSTRAINT fk_account FOREIGN KEY (account_id) REFERENCES account(id) ON DELETE CASCADE, + transaction_id VARCHAR PRIMARY KEY, + cancellation_date VARCHAR, + cancellation_date_ms VARCHAR, + cancellation_date_pst VARCHAR, + cancellation_reason VARCHAR, + expires_date VARCHAR, + expires_date_ms VARCHAR, + expires_date_pst VARCHAR, + is_in_intro_offer_period BOOLEAN, + is_trial_period BOOLEAN, + original_purchase_date VARCHAR, + original_purchase_date_ms VARCHAR, + original_purchase_date_pst VARCHAR, + original_transaction_id VARCHAR, + product_id VARCHAR, + promotional_offer_id VARCHAR, + purchase_date VARCHAR, + purchase_date_ms VARCHAR, + purchase_date_pst VARCHAR, + quantity INT, + web_order_line_item_id VARCHAR +); + +CREATE TABLE account_google_play_purchase ( + account_id INT NOT NULL, + CONSTRAINT fk_account FOREIGN KEY (account_id) REFERENCES account(id) ON DELETE CASCADE, + transaction_id VARCHAR PRIMARY KEY, + acknowledgement_state INT NULL, + consumption_state INT NULL, + developer_payload VARCHAR NULL, + kind VARCHAR NULL, + product_id VARCHAR NOT NULL, + purchase_time_millis VARCHAR NULL, + purchase_state INT NULL, + purchase_token VARCHAR UNIQUE NOT NULL +); + From 5c641ec13a95a2054f2007366343a4bd45f3ca84 Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Sun, 18 Aug 2024 16:51:45 -0500 Subject: [PATCH 35/73] Add account_claim_token table --- database/migrations/0009_account_claim_token.sql | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 database/migrations/0009_account_claim_token.sql diff --git a/database/migrations/0009_account_claim_token.sql b/database/migrations/0009_account_claim_token.sql new file mode 100644 index 0000000..3c1cf26 --- /dev/null +++ b/database/migrations/0009_account_claim_token.sql @@ -0,0 +1,7 @@ +-- 0009 + +CREATE TABLE account_claim_token ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + claimed BOOLEAN DEFAULT FALSE, + years_to_add INT DEFAULT 1 +); From 338c9ca29d177822b310277a46889a16d7a69b1e Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Sun, 18 Aug 2024 16:52:19 -0500 Subject: [PATCH 36/73] Update init_database.sql --- database/combined/init_database.sql | 58 +++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/database/combined/init_database.sql b/database/combined/init_database.sql index d130914..8308958 100644 --- a/database/combined/init_database.sql +++ b/database/combined/init_database.sql @@ -1158,3 +1158,61 @@ CREATE TABLE account_fcm_device ( CONSTRAINT fk_account FOREIGN KEY (account_id) REFERENCES account(id) ON DELETE CASCADE ); +-- 0008 + +CREATE TABLE account_paypal_order ( + account_id INT NOT NULL, + CONSTRAINT fk_account FOREIGN KEY (account_id) REFERENCES account(id) ON DELETE CASCADE, + payment_id VARCHAR PRIMARY KEY, + state VARCHAR +); + +CREATE TABLE account_app_store_purchase ( + account_id INT NOT NULL, + CONSTRAINT fk_account FOREIGN KEY (account_id) REFERENCES account(id) ON DELETE CASCADE, + transaction_id VARCHAR PRIMARY KEY, + cancellation_date VARCHAR, + cancellation_date_ms VARCHAR, + cancellation_date_pst VARCHAR, + cancellation_reason VARCHAR, + expires_date VARCHAR, + expires_date_ms VARCHAR, + expires_date_pst VARCHAR, + is_in_intro_offer_period BOOLEAN, + is_trial_period BOOLEAN, + original_purchase_date VARCHAR, + original_purchase_date_ms VARCHAR, + original_purchase_date_pst VARCHAR, + original_transaction_id VARCHAR, + product_id VARCHAR, + promotional_offer_id VARCHAR, + purchase_date VARCHAR, + purchase_date_ms VARCHAR, + purchase_date_pst VARCHAR, + quantity INT, + web_order_line_item_id VARCHAR +); + +CREATE TABLE account_google_play_purchase ( + account_id INT NOT NULL, + CONSTRAINT fk_account FOREIGN KEY (account_id) REFERENCES account(id) ON DELETE CASCADE, + transaction_id VARCHAR PRIMARY KEY, + acknowledgement_state INT NULL, + consumption_state INT NULL, + developer_payload VARCHAR NULL, + kind VARCHAR NULL, + product_id VARCHAR NOT NULL, + purchase_time_millis VARCHAR NULL, + purchase_state INT NULL, + purchase_token VARCHAR UNIQUE NOT NULL +); + + +-- 0009 + +CREATE TABLE account_claim_token ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + claimed BOOLEAN DEFAULT FALSE, + years_to_add INT DEFAULT 1 +); + From a5df4c144fc7de2718512815574b1698b5bd67d0 Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Mon, 19 Aug 2024 16:32:00 -0500 Subject: [PATCH 37/73] Continue updating initial database migrations --- database/combined/init_database.sql | 87 ++++++++++--------- .../0001_init_podcasting_20_database.sql | 36 ++++---- ...0005_queue_resource.sql => 0005_queue.sql} | 21 +++-- database/migrations/0007_notifications.sql | 16 ++-- .../0008_purchases_paypal_apple_google.sql | 9 +- .../migrations/0009_account_claim_token.sql | 7 -- .../0009_membership_claim_token.sql | 8 ++ 7 files changed, 93 insertions(+), 91 deletions(-) rename database/migrations/{0005_queue_resource.sql => 0005_queue.sql} (84%) delete mode 100644 database/migrations/0009_account_claim_token.sql create mode 100644 database/migrations/0009_membership_claim_token.sql diff --git a/database/combined/init_database.sql b/database/combined/init_database.sql index 8308958..a6aca8e 100644 --- a/database/combined/init_database.sql +++ b/database/combined/init_database.sql @@ -529,16 +529,6 @@ CREATE TABLE item_about ( item_itunes_episode_type_id INTEGER REFERENCES item_itunes_episode_type(id) -- <itunes:episodeType> ); ---** ITEM > CONTENT LINK - --- <item> -> <podcast:contentLink> -CREATE TABLE content_link ( - id SERIAL PRIMARY KEY, - item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, - href varchar_url NOT NULL, - title varchar_normal -); - --** ITEM > CHAPTERS -- <item> -> <podcast:chapters> @@ -614,6 +604,16 @@ CREATE TABLE item_chat ( space varchar_normal ); +--** ITEM > CONTENT LINK + +-- <item> -> <podcast:contentLink> +CREATE TABLE item_content_link ( + id SERIAL PRIMARY KEY, + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + href varchar_url NOT NULL, + title varchar_normal +); + --** ITEM > DESCRIPTION -- <item> -> <description> AND possibly other tags that contain a description @@ -643,14 +643,6 @@ CREATE TABLE item_enclosure ( item_enclosure_default BOOLEAN DEFAULT FALSE ); --- <item> -> <podcast:alternateEnclosure> -> <podcast:source> -CREATE TABLE item_enclosure_source ( - id SERIAL PRIMARY KEY, - item_enclosure_id INTEGER NOT NULL REFERENCES item_enclosure(id) ON DELETE CASCADE, - uri varchar_uri NOT NULL, - content_type varchar_short -); - -- <item> -> <podcast:alternateEnclosure> -> <podcast:integrity> CREATE TABLE item_enclosure_integrity ( id SERIAL PRIMARY KEY, @@ -659,6 +651,14 @@ CREATE TABLE item_enclosure_integrity ( value varchar_long NOT NULL ); +-- <item> -> <podcast:alternateEnclosure> -> <podcast:source> +CREATE TABLE item_enclosure_source ( + id SERIAL PRIMARY KEY, + item_enclosure_id INTEGER NOT NULL REFERENCES item_enclosure(id) ON DELETE CASCADE, + uri varchar_uri NOT NULL, + content_type varchar_short +); + --** ITEM > FUNDING -- <item> -> <podcast:funding> @@ -1036,11 +1036,18 @@ EXECUTE FUNCTION delete_playlist_resource_base(); -- 0005 migration -CREATE TABLE queue_resource_base ( +CREATE TABLE queue ( id SERIAL PRIMARY KEY, account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, + medium_value_id INTEGER NOT NULL REFERENCES medium_value(id), + UNIQUE (account_id, medium_value_id) +); + +CREATE TABLE queue_resource_base ( + id SERIAL PRIMARY KEY, + queue_id INTEGER NOT NULL REFERENCES queue(id) ON DELETE CASCADE, + UNIQUE (queue_id, list_position), list_position list_position NOT NULL CHECK (list_position != 0 OR list_position = 0::numeric), - UNIQUE (account_id, list_position), playback_position media_player_time NOT NULL DEFAULT 0, media_file_duration FLOAT NOT NULL DEFAULT 0, completed BOOLEAN NOT NULL DEFAULT FALSE @@ -1048,27 +1055,27 @@ CREATE TABLE queue_resource_base ( CREATE TABLE queue_resource_item ( item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, - UNIQUE (account_id) + UNIQUE (queue_id) ) INHERITS (queue_resource_base); CREATE TABLE queue_resource_item_add_by_rss ( resource_data jsonb NOT NULL, - UNIQUE (account_id) + UNIQUE (queue_id) ) INHERITS (queue_resource_base); CREATE TABLE queue_resource_item_chapter ( item_chapter_id INTEGER NOT NULL REFERENCES item_chapter(id) ON DELETE CASCADE, - UNIQUE (account_id) + UNIQUE (queue_id) ) INHERITS (queue_resource_base); CREATE TABLE queue_resource_clip ( clip_id INTEGER NOT NULL REFERENCES clip(id) ON DELETE CASCADE, - UNIQUE (account_id) + UNIQUE (queue_id) ) INHERITS (queue_resource_base); CREATE TABLE queue_resource_item_soundbite ( soundbite_id INTEGER NOT NULL REFERENCES item_soundbite(id) ON DELETE CASCADE, - UNIQUE (account_id) + UNIQUE (queue_id) ) INHERITS (queue_resource_base); CREATE OR REPLACE FUNCTION delete_queue_resource_base() @@ -1135,41 +1142,35 @@ CREATE TABLE account_following_add_by_rss_channel ( -- 0007 CREATE TABLE account_notification ( - channel_id INTEGER NOT NULL, - account_id INTEGER NOT NULL, - PRIMARY KEY (channel_id, account_id), - CONSTRAINT fk_channel FOREIGN KEY (channel_id) REFERENCES channel(id) ON DELETE CASCADE, - CONSTRAINT fk_account FOREIGN KEY (account_id) REFERENCES account(id) ON DELETE CASCADE + channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, + account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, + PRIMARY KEY (channel_id, account_id) ); CREATE TABLE account_up_device ( - account_id INTEGER NOT NULL, + account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, up_endpoint varchar_url PRIMARY KEY, up_public_key varchar_long NOT NULL, - up_auth_key varchar_long NOT NULL, - CONSTRAINT fk_account FOREIGN KEY (account_id) REFERENCES account(id) ON DELETE CASCADE + up_auth_key varchar_long NOT NULL ); CREATE DOMAIN varchar_fcm_token AS VARCHAR(255); CREATE TABLE account_fcm_device ( fcm_token varchar_fcm_token PRIMARY KEY, - account_id INT NOT NULL, - CONSTRAINT fk_account FOREIGN KEY (account_id) REFERENCES account(id) ON DELETE CASCADE + account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE ); -- 0008 CREATE TABLE account_paypal_order ( - account_id INT NOT NULL, - CONSTRAINT fk_account FOREIGN KEY (account_id) REFERENCES account(id) ON DELETE CASCADE, + account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, payment_id VARCHAR PRIMARY KEY, state VARCHAR ); CREATE TABLE account_app_store_purchase ( - account_id INT NOT NULL, - CONSTRAINT fk_account FOREIGN KEY (account_id) REFERENCES account(id) ON DELETE CASCADE, + account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, transaction_id VARCHAR PRIMARY KEY, cancellation_date VARCHAR, cancellation_date_ms VARCHAR, @@ -1194,8 +1195,7 @@ CREATE TABLE account_app_store_purchase ( ); CREATE TABLE account_google_play_purchase ( - account_id INT NOT NULL, - CONSTRAINT fk_account FOREIGN KEY (account_id) REFERENCES account(id) ON DELETE CASCADE, + account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, transaction_id VARCHAR PRIMARY KEY, acknowledgement_state INT NULL, consumption_state INT NULL, @@ -1210,9 +1210,10 @@ CREATE TABLE account_google_play_purchase ( -- 0009 -CREATE TABLE account_claim_token ( +CREATE TABLE membership_claim_token ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), claimed BOOLEAN DEFAULT FALSE, - years_to_add INT DEFAULT 1 + years_to_add INT DEFAULT 1, + account_membership_id INT REFERENCES account_membership(id) ON DELETE CASCADE ); diff --git a/database/migrations/0001_init_podcasting_20_database.sql b/database/migrations/0001_init_podcasting_20_database.sql index 1d53a8b..3a40013 100644 --- a/database/migrations/0001_init_podcasting_20_database.sql +++ b/database/migrations/0001_init_podcasting_20_database.sql @@ -492,16 +492,6 @@ CREATE TABLE item_about ( item_itunes_episode_type_id INTEGER REFERENCES item_itunes_episode_type(id) -- <itunes:episodeType> ); ---** ITEM > CONTENT LINK - --- <item> -> <podcast:contentLink> -CREATE TABLE content_link ( - id SERIAL PRIMARY KEY, - item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, - href varchar_url NOT NULL, - title varchar_normal -); - --** ITEM > CHAPTERS -- <item> -> <podcast:chapters> @@ -577,6 +567,16 @@ CREATE TABLE item_chat ( space varchar_normal ); +--** ITEM > CONTENT LINK + +-- <item> -> <podcast:contentLink> +CREATE TABLE item_content_link ( + id SERIAL PRIMARY KEY, + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + href varchar_url NOT NULL, + title varchar_normal +); + --** ITEM > DESCRIPTION -- <item> -> <description> AND possibly other tags that contain a description @@ -606,14 +606,6 @@ CREATE TABLE item_enclosure ( item_enclosure_default BOOLEAN DEFAULT FALSE ); --- <item> -> <podcast:alternateEnclosure> -> <podcast:source> -CREATE TABLE item_enclosure_source ( - id SERIAL PRIMARY KEY, - item_enclosure_id INTEGER NOT NULL REFERENCES item_enclosure(id) ON DELETE CASCADE, - uri varchar_uri NOT NULL, - content_type varchar_short -); - -- <item> -> <podcast:alternateEnclosure> -> <podcast:integrity> CREATE TABLE item_enclosure_integrity ( id SERIAL PRIMARY KEY, @@ -622,6 +614,14 @@ CREATE TABLE item_enclosure_integrity ( value varchar_long NOT NULL ); +-- <item> -> <podcast:alternateEnclosure> -> <podcast:source> +CREATE TABLE item_enclosure_source ( + id SERIAL PRIMARY KEY, + item_enclosure_id INTEGER NOT NULL REFERENCES item_enclosure(id) ON DELETE CASCADE, + uri varchar_uri NOT NULL, + content_type varchar_short +); + --** ITEM > FUNDING -- <item> -> <podcast:funding> diff --git a/database/migrations/0005_queue_resource.sql b/database/migrations/0005_queue.sql similarity index 84% rename from database/migrations/0005_queue_resource.sql rename to database/migrations/0005_queue.sql index dfd75aa..c313e3c 100644 --- a/database/migrations/0005_queue_resource.sql +++ b/database/migrations/0005_queue.sql @@ -1,10 +1,17 @@ -- 0005 migration -CREATE TABLE queue_resource_base ( +CREATE TABLE queue ( id SERIAL PRIMARY KEY, account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, + medium_value_id INTEGER NOT NULL REFERENCES medium_value(id), + UNIQUE (account_id, medium_value_id) +); + +CREATE TABLE queue_resource_base ( + id SERIAL PRIMARY KEY, + queue_id INTEGER NOT NULL REFERENCES queue(id) ON DELETE CASCADE, + UNIQUE (queue_id, list_position), list_position list_position NOT NULL CHECK (list_position != 0 OR list_position = 0::numeric), - UNIQUE (account_id, list_position), playback_position media_player_time NOT NULL DEFAULT 0, media_file_duration FLOAT NOT NULL DEFAULT 0, completed BOOLEAN NOT NULL DEFAULT FALSE @@ -12,27 +19,27 @@ CREATE TABLE queue_resource_base ( CREATE TABLE queue_resource_item ( item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, - UNIQUE (account_id) + UNIQUE (queue_id) ) INHERITS (queue_resource_base); CREATE TABLE queue_resource_item_add_by_rss ( resource_data jsonb NOT NULL, - UNIQUE (account_id) + UNIQUE (queue_id) ) INHERITS (queue_resource_base); CREATE TABLE queue_resource_item_chapter ( item_chapter_id INTEGER NOT NULL REFERENCES item_chapter(id) ON DELETE CASCADE, - UNIQUE (account_id) + UNIQUE (queue_id) ) INHERITS (queue_resource_base); CREATE TABLE queue_resource_clip ( clip_id INTEGER NOT NULL REFERENCES clip(id) ON DELETE CASCADE, - UNIQUE (account_id) + UNIQUE (queue_id) ) INHERITS (queue_resource_base); CREATE TABLE queue_resource_item_soundbite ( soundbite_id INTEGER NOT NULL REFERENCES item_soundbite(id) ON DELETE CASCADE, - UNIQUE (account_id) + UNIQUE (queue_id) ) INHERITS (queue_resource_base); CREATE OR REPLACE FUNCTION delete_queue_resource_base() diff --git a/database/migrations/0007_notifications.sql b/database/migrations/0007_notifications.sql index a1a65d7..3870db7 100644 --- a/database/migrations/0007_notifications.sql +++ b/database/migrations/0007_notifications.sql @@ -1,25 +1,21 @@ -- 0007 CREATE TABLE account_notification ( - channel_id INTEGER NOT NULL, - account_id INTEGER NOT NULL, - PRIMARY KEY (channel_id, account_id), - CONSTRAINT fk_channel FOREIGN KEY (channel_id) REFERENCES channel(id) ON DELETE CASCADE, - CONSTRAINT fk_account FOREIGN KEY (account_id) REFERENCES account(id) ON DELETE CASCADE + channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, + account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, + PRIMARY KEY (channel_id, account_id) ); CREATE TABLE account_up_device ( - account_id INTEGER NOT NULL, + account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, up_endpoint varchar_url PRIMARY KEY, up_public_key varchar_long NOT NULL, - up_auth_key varchar_long NOT NULL, - CONSTRAINT fk_account FOREIGN KEY (account_id) REFERENCES account(id) ON DELETE CASCADE + up_auth_key varchar_long NOT NULL ); CREATE DOMAIN varchar_fcm_token AS VARCHAR(255); CREATE TABLE account_fcm_device ( fcm_token varchar_fcm_token PRIMARY KEY, - account_id INT NOT NULL, - CONSTRAINT fk_account FOREIGN KEY (account_id) REFERENCES account(id) ON DELETE CASCADE + account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE ); diff --git a/database/migrations/0008_purchases_paypal_apple_google.sql b/database/migrations/0008_purchases_paypal_apple_google.sql index 5421070..a9119f6 100644 --- a/database/migrations/0008_purchases_paypal_apple_google.sql +++ b/database/migrations/0008_purchases_paypal_apple_google.sql @@ -1,15 +1,13 @@ -- 0008 CREATE TABLE account_paypal_order ( - account_id INT NOT NULL, - CONSTRAINT fk_account FOREIGN KEY (account_id) REFERENCES account(id) ON DELETE CASCADE, + account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, payment_id VARCHAR PRIMARY KEY, state VARCHAR ); CREATE TABLE account_app_store_purchase ( - account_id INT NOT NULL, - CONSTRAINT fk_account FOREIGN KEY (account_id) REFERENCES account(id) ON DELETE CASCADE, + account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, transaction_id VARCHAR PRIMARY KEY, cancellation_date VARCHAR, cancellation_date_ms VARCHAR, @@ -34,8 +32,7 @@ CREATE TABLE account_app_store_purchase ( ); CREATE TABLE account_google_play_purchase ( - account_id INT NOT NULL, - CONSTRAINT fk_account FOREIGN KEY (account_id) REFERENCES account(id) ON DELETE CASCADE, + account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, transaction_id VARCHAR PRIMARY KEY, acknowledgement_state INT NULL, consumption_state INT NULL, diff --git a/database/migrations/0009_account_claim_token.sql b/database/migrations/0009_account_claim_token.sql deleted file mode 100644 index 3c1cf26..0000000 --- a/database/migrations/0009_account_claim_token.sql +++ /dev/null @@ -1,7 +0,0 @@ --- 0009 - -CREATE TABLE account_claim_token ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - claimed BOOLEAN DEFAULT FALSE, - years_to_add INT DEFAULT 1 -); diff --git a/database/migrations/0009_membership_claim_token.sql b/database/migrations/0009_membership_claim_token.sql new file mode 100644 index 0000000..bdc62ae --- /dev/null +++ b/database/migrations/0009_membership_claim_token.sql @@ -0,0 +1,8 @@ +-- 0009 + +CREATE TABLE membership_claim_token ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + claimed BOOLEAN DEFAULT FALSE, + years_to_add INT DEFAULT 1, + account_membership_id INT REFERENCES account_membership(id) ON DELETE CASCADE +); From a8559466a146dd41432add1163593c01fd597e6d Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Wed, 21 Aug 2024 18:09:24 -0500 Subject: [PATCH 38/73] Remove bigint timestamp columns --- database/combined/init_database.sql | 24 +++++++++---------- database/migrations/0000_init_helpers.sql | 8 +++---- .../0001_init_podcasting_20_database.sql | 16 ++++++------- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/database/combined/init_database.sql b/database/combined/init_database.sql index a6aca8e..ff3db4f 100644 --- a/database/combined/init_database.sql +++ b/database/combined/init_database.sql @@ -19,18 +19,18 @@ CREATE DOMAIN varchar_slug AS VARCHAR(100); CREATE DOMAIN varchar_uri AS VARCHAR(2083); CREATE DOMAIN varchar_url AS VARCHAR(2083) CHECK (VALUE ~ '^https?://|^http?://'); -CREATE DOMAIN server_time AS BIGINT; -CREATE DOMAIN server_time_with_default AS BIGINT DEFAULT EXTRACT(EPOCH FROM NOW()); +CREATE DOMAIN server_time AS TIMESTAMP; +CREATE DOMAIN server_time_with_default AS TIMESTAMP DEFAULT NOW(); CREATE DOMAIN media_player_time AS NUMERIC(10, 2); CREATE DOMAIN list_position AS NUMERIC(22, 21); CREATE DOMAIN numeric_20_11 AS NUMERIC(20, 11); --- Function to set created_at and updated_at +-- Function to set updated_at CREATE OR REPLACE FUNCTION set_updated_at_field() RETURNS TRIGGER AS $$ BEGIN - NEW.updated_at := EXTRACT(EPOCH FROM NOW()); + NEW.updated_at := NOW(); RETURN NEW; END; $$ LANGUAGE plpgsql; @@ -643,14 +643,6 @@ CREATE TABLE item_enclosure ( item_enclosure_default BOOLEAN DEFAULT FALSE ); --- <item> -> <podcast:alternateEnclosure> -> <podcast:integrity> -CREATE TABLE item_enclosure_integrity ( - id SERIAL PRIMARY KEY, - item_enclosure_id INTEGER NOT NULL REFERENCES item_enclosure_source(id) ON DELETE CASCADE, - type TEXT NOT NULL CHECK (type IN ('sri', 'pgp-signature')), - value varchar_long NOT NULL -); - -- <item> -> <podcast:alternateEnclosure> -> <podcast:source> CREATE TABLE item_enclosure_source ( id SERIAL PRIMARY KEY, @@ -659,6 +651,14 @@ CREATE TABLE item_enclosure_source ( content_type varchar_short ); +-- <item> -> <podcast:alternateEnclosure> -> <podcast:integrity> +CREATE TABLE item_enclosure_integrity ( + id SERIAL PRIMARY KEY, + item_enclosure_id INTEGER NOT NULL REFERENCES item_enclosure_source(id) ON DELETE CASCADE, + type TEXT NOT NULL CHECK (type IN ('sri', 'pgp-signature')), + value varchar_long NOT NULL +); + --** ITEM > FUNDING -- <item> -> <podcast:funding> diff --git a/database/migrations/0000_init_helpers.sql b/database/migrations/0000_init_helpers.sql index 61fba6d..d6ba36b 100644 --- a/database/migrations/0000_init_helpers.sql +++ b/database/migrations/0000_init_helpers.sql @@ -19,18 +19,18 @@ CREATE DOMAIN varchar_slug AS VARCHAR(100); CREATE DOMAIN varchar_uri AS VARCHAR(2083); CREATE DOMAIN varchar_url AS VARCHAR(2083) CHECK (VALUE ~ '^https?://|^http?://'); -CREATE DOMAIN server_time AS BIGINT; -CREATE DOMAIN server_time_with_default AS BIGINT DEFAULT EXTRACT(EPOCH FROM NOW()); +CREATE DOMAIN server_time AS TIMESTAMP; +CREATE DOMAIN server_time_with_default AS TIMESTAMP DEFAULT NOW(); CREATE DOMAIN media_player_time AS NUMERIC(10, 2); CREATE DOMAIN list_position AS NUMERIC(22, 21); CREATE DOMAIN numeric_20_11 AS NUMERIC(20, 11); --- Function to set created_at and updated_at +-- Function to set updated_at CREATE OR REPLACE FUNCTION set_updated_at_field() RETURNS TRIGGER AS $$ BEGIN - NEW.updated_at := EXTRACT(EPOCH FROM NOW()); + NEW.updated_at := NOW(); RETURN NEW; END; $$ LANGUAGE plpgsql; diff --git a/database/migrations/0001_init_podcasting_20_database.sql b/database/migrations/0001_init_podcasting_20_database.sql index 3a40013..fac8600 100644 --- a/database/migrations/0001_init_podcasting_20_database.sql +++ b/database/migrations/0001_init_podcasting_20_database.sql @@ -606,14 +606,6 @@ CREATE TABLE item_enclosure ( item_enclosure_default BOOLEAN DEFAULT FALSE ); --- <item> -> <podcast:alternateEnclosure> -> <podcast:integrity> -CREATE TABLE item_enclosure_integrity ( - id SERIAL PRIMARY KEY, - item_enclosure_id INTEGER NOT NULL REFERENCES item_enclosure_source(id) ON DELETE CASCADE, - type TEXT NOT NULL CHECK (type IN ('sri', 'pgp-signature')), - value varchar_long NOT NULL -); - -- <item> -> <podcast:alternateEnclosure> -> <podcast:source> CREATE TABLE item_enclosure_source ( id SERIAL PRIMARY KEY, @@ -622,6 +614,14 @@ CREATE TABLE item_enclosure_source ( content_type varchar_short ); +-- <item> -> <podcast:alternateEnclosure> -> <podcast:integrity> +CREATE TABLE item_enclosure_integrity ( + id SERIAL PRIMARY KEY, + item_enclosure_id INTEGER NOT NULL REFERENCES item_enclosure_source(id) ON DELETE CASCADE, + type TEXT NOT NULL CHECK (type IN ('sri', 'pgp-signature')), + value varchar_long NOT NULL +); + --** ITEM > FUNDING -- <item> -> <podcast:funding> From 082c7563b43d9b5893378616571383815fc60b27 Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Tue, 27 Aug 2024 14:57:40 -0500 Subject: [PATCH 39/73] Updates to 0001 sql columns --- database/combined/init_database.sql | 32 ++++++++----------- .../0001_init_podcasting_20_database.sql | 32 ++++++++----------- 2 files changed, 26 insertions(+), 38 deletions(-) diff --git a/database/combined/init_database.sql b/database/combined/init_database.sql index ff3db4f..082fa1f 100644 --- a/database/combined/init_database.sql +++ b/database/combined/init_database.sql @@ -201,7 +201,7 @@ CREATE TABLE channel_about ( episode_count INTEGER, -- aggregated count for convenience explicit BOOLEAN, -- <itunes:explicit> itunes_type_id INTEGER REFERENCES channel_itunes_type(id), - language varchar_short NOT NULL, -- <language> + language varchar_short, -- <language> website_link_url varchar_url -- <link> ); @@ -277,8 +277,8 @@ CREATE TABLE channel_license ( id SERIAL PRIMARY KEY, channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, UNIQUE (channel_id), - type varchar_normal NOT NULL, - url varchar_url NOT NULL + identifier varchar_normal NOT NULL, + url varchar_url ); --** CHANNEL > LOCATION @@ -289,10 +289,8 @@ CREATE TABLE channel_location ( channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, geo varchar_normal, osm varchar_normal, - CHECK ( - (geo IS NOT NULL AND osm IS NULL) OR - (geo IS NULL AND osm IS NOT NULL) - ) + CHECK (geo IS NOT NULL OR osm IS NOT NULL), + name varchar_normal ); --** CHANNEL > PERSON @@ -301,7 +299,7 @@ CREATE TABLE channel_location ( CREATE TABLE channel_person ( id SERIAL PRIMARY KEY, channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, - name varchar_normal, + name varchar_normal NOT NULL, role varchar_normal, person_group varchar_normal DEFAULT 'cast', -- group is a reserved keyword in sql img varchar_url, @@ -586,10 +584,8 @@ CREATE TABLE item_chapter_location ( item_chapter_id INTEGER NOT NULL REFERENCES item_chapter(id) ON DELETE CASCADE, geo varchar_normal, osm varchar_normal, - CHECK ( - (geo IS NOT NULL AND osm IS NULL) OR - (geo IS NULL AND osm IS NOT NULL) - ) + CHECK (geo IS NOT NULL OR osm IS NOT NULL), + name varchar_normal ); --** ITEM > CHAT @@ -691,8 +687,8 @@ CREATE TABLE item_license ( id SERIAL PRIMARY KEY, item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, UNIQUE (item_id), - type varchar_normal NOT NULL, - url varchar_url NOT NULL + identifier varchar_normal NOT NULL, + url varchar_url ); --** ITEM > LOCATION @@ -703,10 +699,8 @@ CREATE TABLE item_location ( item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, geo varchar_normal, osm varchar_normal, - CHECK ( - (geo IS NOT NULL AND osm IS NULL) OR - (geo IS NULL AND osm IS NOT NULL) - ) + CHECK (geo IS NOT NULL OR osm IS NOT NULL), + name varchar_normal ); --** ITEM > PERSON @@ -715,7 +709,7 @@ CREATE TABLE item_location ( CREATE TABLE item_person ( id SERIAL PRIMARY KEY, channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, - name varchar_normal, + name varchar_normal NOT NULL, role varchar_normal, person_group varchar_normal DEFAULT 'cast', -- group is a reserved keyword in sql img varchar_url, diff --git a/database/migrations/0001_init_podcasting_20_database.sql b/database/migrations/0001_init_podcasting_20_database.sql index fac8600..3d43ce0 100644 --- a/database/migrations/0001_init_podcasting_20_database.sql +++ b/database/migrations/0001_init_podcasting_20_database.sql @@ -164,7 +164,7 @@ CREATE TABLE channel_about ( episode_count INTEGER, -- aggregated count for convenience explicit BOOLEAN, -- <itunes:explicit> itunes_type_id INTEGER REFERENCES channel_itunes_type(id), - language varchar_short NOT NULL, -- <language> + language varchar_short, -- <language> website_link_url varchar_url -- <link> ); @@ -240,8 +240,8 @@ CREATE TABLE channel_license ( id SERIAL PRIMARY KEY, channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, UNIQUE (channel_id), - type varchar_normal NOT NULL, - url varchar_url NOT NULL + identifier varchar_normal NOT NULL, + url varchar_url ); --** CHANNEL > LOCATION @@ -252,10 +252,8 @@ CREATE TABLE channel_location ( channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, geo varchar_normal, osm varchar_normal, - CHECK ( - (geo IS NOT NULL AND osm IS NULL) OR - (geo IS NULL AND osm IS NOT NULL) - ) + CHECK (geo IS NOT NULL OR osm IS NOT NULL), + name varchar_normal ); --** CHANNEL > PERSON @@ -264,7 +262,7 @@ CREATE TABLE channel_location ( CREATE TABLE channel_person ( id SERIAL PRIMARY KEY, channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, - name varchar_normal, + name varchar_normal NOT NULL, role varchar_normal, person_group varchar_normal DEFAULT 'cast', -- group is a reserved keyword in sql img varchar_url, @@ -549,10 +547,8 @@ CREATE TABLE item_chapter_location ( item_chapter_id INTEGER NOT NULL REFERENCES item_chapter(id) ON DELETE CASCADE, geo varchar_normal, osm varchar_normal, - CHECK ( - (geo IS NOT NULL AND osm IS NULL) OR - (geo IS NULL AND osm IS NOT NULL) - ) + CHECK (geo IS NOT NULL OR osm IS NOT NULL), + name varchar_normal ); --** ITEM > CHAT @@ -654,8 +650,8 @@ CREATE TABLE item_license ( id SERIAL PRIMARY KEY, item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, UNIQUE (item_id), - type varchar_normal NOT NULL, - url varchar_url NOT NULL + identifier varchar_normal NOT NULL, + url varchar_url ); --** ITEM > LOCATION @@ -666,10 +662,8 @@ CREATE TABLE item_location ( item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, geo varchar_normal, osm varchar_normal, - CHECK ( - (geo IS NOT NULL AND osm IS NULL) OR - (geo IS NULL AND osm IS NOT NULL) - ) + CHECK (geo IS NOT NULL OR osm IS NOT NULL), + name varchar_normal ); --** ITEM > PERSON @@ -678,7 +672,7 @@ CREATE TABLE item_location ( CREATE TABLE item_person ( id SERIAL PRIMARY KEY, channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, - name varchar_normal, + name varchar_normal NOT NULL, role varchar_normal, person_group varchar_normal DEFAULT 'cast', -- group is a reserved keyword in sql img varchar_url, From 165198cb7034716b3b24aba1d1fbf5deb30cb1cf Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Tue, 27 Aug 2024 15:09:37 -0500 Subject: [PATCH 40/73] Update 0001 channel columns --- database/combined/init_database.sql | 4 ++-- database/migrations/0001_init_podcasting_20_database.sql | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/database/combined/init_database.sql b/database/combined/init_database.sql index 082fa1f..3c49805 100644 --- a/database/combined/init_database.sql +++ b/database/combined/init_database.sql @@ -161,8 +161,8 @@ CREATE TABLE channel ( feed_id INTEGER NOT NULL REFERENCES feed(id) ON DELETE CASCADE, podcast_index_id INTEGER UNIQUE NOT NULL, podcast_guid UUID UNIQUE, -- <podcast:guid> - title varchar_normal, - sortable_title varchar_short, -- all lowercase, ignores articles at beginning of title + title varchar_normal NOT NULL, + sortable_title varchar_short NOT NULL, -- all lowercase, ignores articles at beginning of title medium_value_id INTEGER REFERENCES medium_value(id), -- TODO: should we hash the last parsed feed, so we can compare it to the hash of diff --git a/database/migrations/0001_init_podcasting_20_database.sql b/database/migrations/0001_init_podcasting_20_database.sql index 3d43ce0..289741a 100644 --- a/database/migrations/0001_init_podcasting_20_database.sql +++ b/database/migrations/0001_init_podcasting_20_database.sql @@ -124,8 +124,8 @@ CREATE TABLE channel ( feed_id INTEGER NOT NULL REFERENCES feed(id) ON DELETE CASCADE, podcast_index_id INTEGER UNIQUE NOT NULL, podcast_guid UUID UNIQUE, -- <podcast:guid> - title varchar_normal, - sortable_title varchar_short, -- all lowercase, ignores articles at beginning of title + title varchar_normal NOT NULL, + sortable_title varchar_short NOT NULL, -- all lowercase, ignores articles at beginning of title medium_value_id INTEGER REFERENCES medium_value(id), -- TODO: should we hash the last parsed feed, so we can compare it to the hash of From f12102121ed0dbf7d4743b5754267ae88fc1ca02 Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Tue, 27 Aug 2024 15:32:32 -0500 Subject: [PATCH 41/73] Make channel title optional --- database/combined/init_database.sql | 4 ++-- database/migrations/0001_init_podcasting_20_database.sql | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/database/combined/init_database.sql b/database/combined/init_database.sql index 3c49805..082fa1f 100644 --- a/database/combined/init_database.sql +++ b/database/combined/init_database.sql @@ -161,8 +161,8 @@ CREATE TABLE channel ( feed_id INTEGER NOT NULL REFERENCES feed(id) ON DELETE CASCADE, podcast_index_id INTEGER UNIQUE NOT NULL, podcast_guid UUID UNIQUE, -- <podcast:guid> - title varchar_normal NOT NULL, - sortable_title varchar_short NOT NULL, -- all lowercase, ignores articles at beginning of title + title varchar_normal, + sortable_title varchar_short, -- all lowercase, ignores articles at beginning of title medium_value_id INTEGER REFERENCES medium_value(id), -- TODO: should we hash the last parsed feed, so we can compare it to the hash of diff --git a/database/migrations/0001_init_podcasting_20_database.sql b/database/migrations/0001_init_podcasting_20_database.sql index 289741a..3d43ce0 100644 --- a/database/migrations/0001_init_podcasting_20_database.sql +++ b/database/migrations/0001_init_podcasting_20_database.sql @@ -124,8 +124,8 @@ CREATE TABLE channel ( feed_id INTEGER NOT NULL REFERENCES feed(id) ON DELETE CASCADE, podcast_index_id INTEGER UNIQUE NOT NULL, podcast_guid UUID UNIQUE, -- <podcast:guid> - title varchar_normal NOT NULL, - sortable_title varchar_short NOT NULL, -- all lowercase, ignores articles at beginning of title + title varchar_normal, + sortable_title varchar_short, -- all lowercase, ignores articles at beginning of title medium_value_id INTEGER REFERENCES medium_value(id), -- TODO: should we hash the last parsed feed, so we can compare it to the hash of From 474df58938668dbbc603212b7753ddef0e3677d1 Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Thu, 29 Aug 2024 00:54:01 -0500 Subject: [PATCH 42/73] Update txt table names and columns --- database/combined/init_database.sql | 17 +++++++++-------- .../0001_init_podcasting_20_database.sql | 17 +++++++++-------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/database/combined/init_database.sql b/database/combined/init_database.sql index 082fa1f..91d3d74 100644 --- a/database/combined/init_database.sql +++ b/database/combined/init_database.sql @@ -401,21 +401,22 @@ CREATE TABLE channel_social_interact ( CREATE TABLE channel_trailer ( id SERIAL PRIMARY KEY, channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, - title varchar_normal, url varchar_url NOT NULL, - pub_date TIMESTAMPTZ NOT NULL, + title varchar_normal, + pubdate TIMESTAMPTZ NOT NULL, length INTEGER, type varchar_short, - season INTEGER + season INTEGER, + UNIQUE (channel_id, url) ); --** CHANNEL > TXT TAG -- <channel> -> <podcast:txt> -CREATE TABLE channel_txt_tag ( +CREATE TABLE channel_txt ( id SERIAL PRIMARY KEY, channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, - verify varchar_normal NOT NULL, + purpose varchar_normal, value varchar_long NOT NULL ); @@ -495,7 +496,7 @@ CREATE TABLE item ( slug varchar_slug, channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, guid varchar_uri, -- <guid> - pub_date TIMESTAMPTZ, -- <pubDate> + pubdate TIMESTAMPTZ, -- <pubDate> title varchar_normal, -- <title> -- hidden items are no longer available in the rss feed, but are still in the database. @@ -777,10 +778,10 @@ CREATE TABLE item_transcript ( --** ITEM > TXT TAG -- <item> -> <podcast:txt> -CREATE TABLE item_txt_tag ( +CREATE TABLE item_txt ( id SERIAL PRIMARY KEY, item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, - verify varchar_normal NOT NULL, + purpose varchar_normal, value varchar_long NOT NULL ); diff --git a/database/migrations/0001_init_podcasting_20_database.sql b/database/migrations/0001_init_podcasting_20_database.sql index 3d43ce0..ea0692a 100644 --- a/database/migrations/0001_init_podcasting_20_database.sql +++ b/database/migrations/0001_init_podcasting_20_database.sql @@ -364,21 +364,22 @@ CREATE TABLE channel_social_interact ( CREATE TABLE channel_trailer ( id SERIAL PRIMARY KEY, channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, - title varchar_normal, url varchar_url NOT NULL, - pub_date TIMESTAMPTZ NOT NULL, + title varchar_normal, + pubdate TIMESTAMPTZ NOT NULL, length INTEGER, type varchar_short, - season INTEGER + season INTEGER, + UNIQUE (channel_id, url) ); --** CHANNEL > TXT TAG -- <channel> -> <podcast:txt> -CREATE TABLE channel_txt_tag ( +CREATE TABLE channel_txt ( id SERIAL PRIMARY KEY, channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, - verify varchar_normal NOT NULL, + purpose varchar_normal, value varchar_long NOT NULL ); @@ -458,7 +459,7 @@ CREATE TABLE item ( slug varchar_slug, channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, guid varchar_uri, -- <guid> - pub_date TIMESTAMPTZ, -- <pubDate> + pubdate TIMESTAMPTZ, -- <pubDate> title varchar_normal, -- <title> -- hidden items are no longer available in the rss feed, but are still in the database. @@ -740,10 +741,10 @@ CREATE TABLE item_transcript ( --** ITEM > TXT TAG -- <item> -> <podcast:txt> -CREATE TABLE item_txt_tag ( +CREATE TABLE item_txt ( id SERIAL PRIMARY KEY, item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, - verify varchar_normal NOT NULL, + purpose varchar_normal, value varchar_long NOT NULL ); From 3c615e3052b835b65274ab560018edb72ce1ded6 Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Thu, 29 Aug 2024 01:28:45 -0500 Subject: [PATCH 43/73] Change value_tag to value --- database/combined/init_database.sql | 64 +++++++++---------- .../0001_init_podcasting_20_database.sql | 64 +++++++++---------- 2 files changed, 64 insertions(+), 64 deletions(-) diff --git a/database/combined/init_database.sql b/database/combined/init_database.sql index 91d3d74..31b6445 100644 --- a/database/combined/init_database.sql +++ b/database/combined/init_database.sql @@ -168,9 +168,9 @@ CREATE TABLE channel ( -- TODO: should we hash the last parsed feed, so we can compare it to the hash of -- a feed before completely parsing it, to check if it has changed before continuing? - -- channels that have a PI value tag require special handling to request value_tag data + -- channels that have a PI value tag require special handling to request value data -- from the Podcast Index API. - has_podcast_index_value_tags BOOLEAN DEFAULT FALSE, + has_podcast_index_value BOOLEAN DEFAULT FALSE, -- hidden items are no longer available in the rss feed, but are still in the database. hidden BOOLEAN DEFAULT FALSE, @@ -410,7 +410,7 @@ CREATE TABLE channel_trailer ( UNIQUE (channel_id, url) ); ---** CHANNEL > TXT TAG +--** CHANNEL > TXT -- <channel> -> <podcast:txt> CREATE TABLE channel_txt ( @@ -420,10 +420,10 @@ CREATE TABLE channel_txt ( value varchar_long NOT NULL ); ---** CHANNEL > VALUE TAG +--** CHANNEL > VALUE -- <channel> -> <podcast:value> -CREATE TABLE channel_value_tag ( +CREATE TABLE channel_value ( id SERIAL PRIMARY KEY, channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, type varchar_short NOT NULL, @@ -431,12 +431,12 @@ CREATE TABLE channel_value_tag ( suggested FLOAT ); ---** CHANNEL > VALUE TAG > RECEIPIENT +--** CHANNEL > VALUE > RECEIPIENT -- <channel> -> <podcast:value> -> <podcast:valueRecipient> -CREATE TABLE channel_value_tag_receipient ( +CREATE TABLE channel_value_receipient ( id SERIAL PRIMARY KEY, - channel_value_tag_id INTEGER NOT NULL REFERENCES channel_value_tag(id) ON DELETE CASCADE, + channel_value_id INTEGER NOT NULL REFERENCES channel_value(id) ON DELETE CASCADE, type varchar_short NOT NULL, address varchar_long NOT NULL, split FLOAT NOT NULL, @@ -446,36 +446,36 @@ CREATE TABLE channel_value_tag_receipient ( fee BOOLEAN DEFAULT FALSE ); ---** CHANNEL > VALUE TAG > TIME SPLIT +--** CHANNEL > VALUE > TIME SPLIT -- <channel> -> <podcast:valueTimeSplit> -CREATE TABLE channel_value_tag_time_split ( +CREATE TABLE channel_value_time_split ( id SERIAL PRIMARY KEY, - channel_value_tag_id INTEGER NOT NULL REFERENCES channel_value_tag(id) ON DELETE CASCADE, + channel_value_id INTEGER NOT NULL REFERENCES channel_value(id) ON DELETE CASCADE, start_time INTEGER NOT NULL, duration INTEGER NOT NULL, remote_start_time INTEGER DEFAULT 0, remote_percentage INTEGER DEFAULT 100 ); ---** CHANNEL > VALUE TAG > TIME SPLIT > REMOTE ITEM +--** CHANNEL > VALUE > TIME SPLIT > REMOTE ITEM -- <channel> -> <podcast:value> -> <podcast:valueTimeSplit> -> <podcast:remoteItem> -CREATE TABLE channel_value_tag_time_split_remote_item ( +CREATE TABLE channel_value_time_split_remote_item ( id SERIAL PRIMARY KEY, - channel_value_tag_time_split_id INTEGER NOT NULL REFERENCES channel_value_tag_time_split(id) ON DELETE CASCADE, + channel_value_time_split_id INTEGER NOT NULL REFERENCES channel_value_time_split(id) ON DELETE CASCADE, feed_guid UUID NOT NULL, feed_url varchar_url, item_guid varchar_uri, title varchar_normal ); ---** CHANNEL > VALUE TAG > TIME SPLIT > VALUE RECIPEINT +--** CHANNEL > VALUE > TIME SPLIT > VALUE RECIPEINT -- <channel> -> <podcast:value> -> <podcast:valueTimeSplit> -> <podcast:valueRecipient> -CREATE TABLE channel_value_tag_time_split_receipient ( +CREATE TABLE channel_value_time_split_receipient ( id SERIAL PRIMARY KEY, - channel_value_tag_time_split_id INTEGER NOT NULL REFERENCES channel_value_tag_time_split(id) ON DELETE CASCADE, + channel_value_time_split_id INTEGER NOT NULL REFERENCES channel_value_time_split(id) ON DELETE CASCADE, type varchar_short NOT NULL, address varchar_long NOT NULL, split FLOAT NOT NULL, @@ -775,7 +775,7 @@ CREATE TABLE item_transcript ( rel VARCHAR(50) CHECK (rel IS NULL OR rel = 'captions') ); ---** ITEM > TXT TAG +--** ITEM > TXT -- <item> -> <podcast:txt> CREATE TABLE item_txt ( @@ -785,10 +785,10 @@ CREATE TABLE item_txt ( value varchar_long NOT NULL ); ---** ITEM > VALUE TAG +--** ITEM > VALUE -- <item> -> <podcast:value> -CREATE TABLE item_value_tag ( +CREATE TABLE item_value ( id SERIAL PRIMARY KEY, item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, type varchar_short NOT NULL, @@ -796,12 +796,12 @@ CREATE TABLE item_value_tag ( suggested FLOAT ); ---** ITEM > VALUE TAG > RECEIPIENT +--** ITEM > VALUE > RECEIPIENT -- <item> -> <podcast:value> -> <podcast:valueRecipient> -CREATE TABLE item_value_tag_receipient ( +CREATE TABLE item_value_receipient ( id SERIAL PRIMARY KEY, - item_value_tag_id INTEGER NOT NULL REFERENCES item_value_tag(id) ON DELETE CASCADE, + item_value_id INTEGER NOT NULL REFERENCES item_value(id) ON DELETE CASCADE, type varchar_short NOT NULL, address varchar_long NOT NULL, split FLOAT NOT NULL, @@ -811,36 +811,36 @@ CREATE TABLE item_value_tag_receipient ( fee BOOLEAN DEFAULT FALSE ); ---** ITEM > VALUE TAG > TIME SPLIT +--** ITEM > VALUE > TIME SPLIT -- <item> -> <podcast:value> -> <podcast:valueTimeSplit> -CREATE TABLE item_value_tag_time_split ( +CREATE TABLE item_value_time_split ( id SERIAL PRIMARY KEY, - item_value_tag_id INTEGER NOT NULL REFERENCES item_value_tag(id) ON DELETE CASCADE, + item_value_id INTEGER NOT NULL REFERENCES item_value(id) ON DELETE CASCADE, start_time INTEGER NOT NULL, duration INTEGER NOT NULL, remote_start_time INTEGER DEFAULT 0, remote_percentage INTEGER DEFAULT 100 ); ---** ITEM > VALUE TAG > TIME SPLIT > REMOTE ITEM +--** ITEM > VALUE > TIME SPLIT > REMOTE ITEM -- <item> -> <podcast:value> -> <podcast:valueTimeSplit> -> <podcast:remoteItem> -CREATE TABLE item_value_tag_time_split_remote_item ( +CREATE TABLE item_value_time_split_remote_item ( id SERIAL PRIMARY KEY, - item_value_tag_time_split_id INTEGER NOT NULL REFERENCES item_value_tag_time_split(id) ON DELETE CASCADE, + item_value_time_split_id INTEGER NOT NULL REFERENCES item_value_time_split(id) ON DELETE CASCADE, feed_guid UUID NOT NULL, feed_url varchar_url, item_guid varchar_uri, title varchar_normal ); ---** ITEM > VALUE TAG > TIME SPLIT > VALUE RECIPEINT +--** ITEM > VALUE > TIME SPLIT > VALUE RECIPEINT -- <item> -> <podcast:value> -> <podcast:valueTimeSplit> -> <podcast:valueRecipient> -CREATE TABLE item_value_tag_time_split_receipient ( +CREATE TABLE item_value_time_split_receipient ( id SERIAL PRIMARY KEY, - item_value_tag_time_split_id INTEGER NOT NULL REFERENCES item_value_tag_time_split(id) ON DELETE CASCADE, + item_value_time_split_id INTEGER NOT NULL REFERENCES item_value_time_split(id) ON DELETE CASCADE, type varchar_short NOT NULL, address varchar_long NOT NULL, split FLOAT NOT NULL, diff --git a/database/migrations/0001_init_podcasting_20_database.sql b/database/migrations/0001_init_podcasting_20_database.sql index ea0692a..29c3ad3 100644 --- a/database/migrations/0001_init_podcasting_20_database.sql +++ b/database/migrations/0001_init_podcasting_20_database.sql @@ -131,9 +131,9 @@ CREATE TABLE channel ( -- TODO: should we hash the last parsed feed, so we can compare it to the hash of -- a feed before completely parsing it, to check if it has changed before continuing? - -- channels that have a PI value tag require special handling to request value_tag data + -- channels that have a PI value tag require special handling to request value data -- from the Podcast Index API. - has_podcast_index_value_tags BOOLEAN DEFAULT FALSE, + has_podcast_index_value BOOLEAN DEFAULT FALSE, -- hidden items are no longer available in the rss feed, but are still in the database. hidden BOOLEAN DEFAULT FALSE, @@ -373,7 +373,7 @@ CREATE TABLE channel_trailer ( UNIQUE (channel_id, url) ); ---** CHANNEL > TXT TAG +--** CHANNEL > TXT -- <channel> -> <podcast:txt> CREATE TABLE channel_txt ( @@ -383,10 +383,10 @@ CREATE TABLE channel_txt ( value varchar_long NOT NULL ); ---** CHANNEL > VALUE TAG +--** CHANNEL > VALUE -- <channel> -> <podcast:value> -CREATE TABLE channel_value_tag ( +CREATE TABLE channel_value ( id SERIAL PRIMARY KEY, channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, type varchar_short NOT NULL, @@ -394,12 +394,12 @@ CREATE TABLE channel_value_tag ( suggested FLOAT ); ---** CHANNEL > VALUE TAG > RECEIPIENT +--** CHANNEL > VALUE > RECEIPIENT -- <channel> -> <podcast:value> -> <podcast:valueRecipient> -CREATE TABLE channel_value_tag_receipient ( +CREATE TABLE channel_value_receipient ( id SERIAL PRIMARY KEY, - channel_value_tag_id INTEGER NOT NULL REFERENCES channel_value_tag(id) ON DELETE CASCADE, + channel_value_id INTEGER NOT NULL REFERENCES channel_value(id) ON DELETE CASCADE, type varchar_short NOT NULL, address varchar_long NOT NULL, split FLOAT NOT NULL, @@ -409,36 +409,36 @@ CREATE TABLE channel_value_tag_receipient ( fee BOOLEAN DEFAULT FALSE ); ---** CHANNEL > VALUE TAG > TIME SPLIT +--** CHANNEL > VALUE > TIME SPLIT -- <channel> -> <podcast:valueTimeSplit> -CREATE TABLE channel_value_tag_time_split ( +CREATE TABLE channel_value_time_split ( id SERIAL PRIMARY KEY, - channel_value_tag_id INTEGER NOT NULL REFERENCES channel_value_tag(id) ON DELETE CASCADE, + channel_value_id INTEGER NOT NULL REFERENCES channel_value(id) ON DELETE CASCADE, start_time INTEGER NOT NULL, duration INTEGER NOT NULL, remote_start_time INTEGER DEFAULT 0, remote_percentage INTEGER DEFAULT 100 ); ---** CHANNEL > VALUE TAG > TIME SPLIT > REMOTE ITEM +--** CHANNEL > VALUE > TIME SPLIT > REMOTE ITEM -- <channel> -> <podcast:value> -> <podcast:valueTimeSplit> -> <podcast:remoteItem> -CREATE TABLE channel_value_tag_time_split_remote_item ( +CREATE TABLE channel_value_time_split_remote_item ( id SERIAL PRIMARY KEY, - channel_value_tag_time_split_id INTEGER NOT NULL REFERENCES channel_value_tag_time_split(id) ON DELETE CASCADE, + channel_value_time_split_id INTEGER NOT NULL REFERENCES channel_value_time_split(id) ON DELETE CASCADE, feed_guid UUID NOT NULL, feed_url varchar_url, item_guid varchar_uri, title varchar_normal ); ---** CHANNEL > VALUE TAG > TIME SPLIT > VALUE RECIPEINT +--** CHANNEL > VALUE > TIME SPLIT > VALUE RECIPEINT -- <channel> -> <podcast:value> -> <podcast:valueTimeSplit> -> <podcast:valueRecipient> -CREATE TABLE channel_value_tag_time_split_receipient ( +CREATE TABLE channel_value_time_split_receipient ( id SERIAL PRIMARY KEY, - channel_value_tag_time_split_id INTEGER NOT NULL REFERENCES channel_value_tag_time_split(id) ON DELETE CASCADE, + channel_value_time_split_id INTEGER NOT NULL REFERENCES channel_value_time_split(id) ON DELETE CASCADE, type varchar_short NOT NULL, address varchar_long NOT NULL, split FLOAT NOT NULL, @@ -738,7 +738,7 @@ CREATE TABLE item_transcript ( rel VARCHAR(50) CHECK (rel IS NULL OR rel = 'captions') ); ---** ITEM > TXT TAG +--** ITEM > TXT -- <item> -> <podcast:txt> CREATE TABLE item_txt ( @@ -748,10 +748,10 @@ CREATE TABLE item_txt ( value varchar_long NOT NULL ); ---** ITEM > VALUE TAG +--** ITEM > VALUE -- <item> -> <podcast:value> -CREATE TABLE item_value_tag ( +CREATE TABLE item_value ( id SERIAL PRIMARY KEY, item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, type varchar_short NOT NULL, @@ -759,12 +759,12 @@ CREATE TABLE item_value_tag ( suggested FLOAT ); ---** ITEM > VALUE TAG > RECEIPIENT +--** ITEM > VALUE > RECEIPIENT -- <item> -> <podcast:value> -> <podcast:valueRecipient> -CREATE TABLE item_value_tag_receipient ( +CREATE TABLE item_value_receipient ( id SERIAL PRIMARY KEY, - item_value_tag_id INTEGER NOT NULL REFERENCES item_value_tag(id) ON DELETE CASCADE, + item_value_id INTEGER NOT NULL REFERENCES item_value(id) ON DELETE CASCADE, type varchar_short NOT NULL, address varchar_long NOT NULL, split FLOAT NOT NULL, @@ -774,36 +774,36 @@ CREATE TABLE item_value_tag_receipient ( fee BOOLEAN DEFAULT FALSE ); ---** ITEM > VALUE TAG > TIME SPLIT +--** ITEM > VALUE > TIME SPLIT -- <item> -> <podcast:value> -> <podcast:valueTimeSplit> -CREATE TABLE item_value_tag_time_split ( +CREATE TABLE item_value_time_split ( id SERIAL PRIMARY KEY, - item_value_tag_id INTEGER NOT NULL REFERENCES item_value_tag(id) ON DELETE CASCADE, + item_value_id INTEGER NOT NULL REFERENCES item_value(id) ON DELETE CASCADE, start_time INTEGER NOT NULL, duration INTEGER NOT NULL, remote_start_time INTEGER DEFAULT 0, remote_percentage INTEGER DEFAULT 100 ); ---** ITEM > VALUE TAG > TIME SPLIT > REMOTE ITEM +--** ITEM > VALUE > TIME SPLIT > REMOTE ITEM -- <item> -> <podcast:value> -> <podcast:valueTimeSplit> -> <podcast:remoteItem> -CREATE TABLE item_value_tag_time_split_remote_item ( +CREATE TABLE item_value_time_split_remote_item ( id SERIAL PRIMARY KEY, - item_value_tag_time_split_id INTEGER NOT NULL REFERENCES item_value_tag_time_split(id) ON DELETE CASCADE, + item_value_time_split_id INTEGER NOT NULL REFERENCES item_value_time_split(id) ON DELETE CASCADE, feed_guid UUID NOT NULL, feed_url varchar_url, item_guid varchar_uri, title varchar_normal ); ---** ITEM > VALUE TAG > TIME SPLIT > VALUE RECIPEINT +--** ITEM > VALUE > TIME SPLIT > VALUE RECIPEINT -- <item> -> <podcast:value> -> <podcast:valueTimeSplit> -> <podcast:valueRecipient> -CREATE TABLE item_value_tag_time_split_receipient ( +CREATE TABLE item_value_time_split_receipient ( id SERIAL PRIMARY KEY, - item_value_tag_time_split_id INTEGER NOT NULL REFERENCES item_value_tag_time_split(id) ON DELETE CASCADE, + item_value_time_split_id INTEGER NOT NULL REFERENCES item_value_time_split(id) ON DELETE CASCADE, type varchar_short NOT NULL, address varchar_long NOT NULL, split FLOAT NOT NULL, From 4761e3265f5f899d555701c87e9e9a5b644e4235 Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Thu, 29 Aug 2024 15:43:23 -0500 Subject: [PATCH 44/73] Remove unnecessary channel_value_time_split tables --- database/combined/init_database.sql | 39 ------------------- .../0001_init_podcasting_20_database.sql | 39 ------------------- 2 files changed, 78 deletions(-) diff --git a/database/combined/init_database.sql b/database/combined/init_database.sql index 31b6445..eae4415 100644 --- a/database/combined/init_database.sql +++ b/database/combined/init_database.sql @@ -446,45 +446,6 @@ CREATE TABLE channel_value_receipient ( fee BOOLEAN DEFAULT FALSE ); ---** CHANNEL > VALUE > TIME SPLIT - --- <channel> -> <podcast:valueTimeSplit> -CREATE TABLE channel_value_time_split ( - id SERIAL PRIMARY KEY, - channel_value_id INTEGER NOT NULL REFERENCES channel_value(id) ON DELETE CASCADE, - start_time INTEGER NOT NULL, - duration INTEGER NOT NULL, - remote_start_time INTEGER DEFAULT 0, - remote_percentage INTEGER DEFAULT 100 -); - ---** CHANNEL > VALUE > TIME SPLIT > REMOTE ITEM - --- <channel> -> <podcast:value> -> <podcast:valueTimeSplit> -> <podcast:remoteItem> -CREATE TABLE channel_value_time_split_remote_item ( - id SERIAL PRIMARY KEY, - channel_value_time_split_id INTEGER NOT NULL REFERENCES channel_value_time_split(id) ON DELETE CASCADE, - feed_guid UUID NOT NULL, - feed_url varchar_url, - item_guid varchar_uri, - title varchar_normal -); - ---** CHANNEL > VALUE > TIME SPLIT > VALUE RECIPEINT - --- <channel> -> <podcast:value> -> <podcast:valueTimeSplit> -> <podcast:valueRecipient> -CREATE TABLE channel_value_time_split_receipient ( - id SERIAL PRIMARY KEY, - channel_value_time_split_id INTEGER NOT NULL REFERENCES channel_value_time_split(id) ON DELETE CASCADE, - type varchar_short NOT NULL, - address varchar_long NOT NULL, - split FLOAT NOT NULL, - name varchar_normal, - custom_key varchar_long, - custom_value varchar_long, - fee BOOLEAN DEFAULT FALSE -); - --** ITEM -- Technically the item table could be named channel_item, but it seems easier to understand as item. diff --git a/database/migrations/0001_init_podcasting_20_database.sql b/database/migrations/0001_init_podcasting_20_database.sql index 29c3ad3..7fa7879 100644 --- a/database/migrations/0001_init_podcasting_20_database.sql +++ b/database/migrations/0001_init_podcasting_20_database.sql @@ -409,45 +409,6 @@ CREATE TABLE channel_value_receipient ( fee BOOLEAN DEFAULT FALSE ); ---** CHANNEL > VALUE > TIME SPLIT - --- <channel> -> <podcast:valueTimeSplit> -CREATE TABLE channel_value_time_split ( - id SERIAL PRIMARY KEY, - channel_value_id INTEGER NOT NULL REFERENCES channel_value(id) ON DELETE CASCADE, - start_time INTEGER NOT NULL, - duration INTEGER NOT NULL, - remote_start_time INTEGER DEFAULT 0, - remote_percentage INTEGER DEFAULT 100 -); - ---** CHANNEL > VALUE > TIME SPLIT > REMOTE ITEM - --- <channel> -> <podcast:value> -> <podcast:valueTimeSplit> -> <podcast:remoteItem> -CREATE TABLE channel_value_time_split_remote_item ( - id SERIAL PRIMARY KEY, - channel_value_time_split_id INTEGER NOT NULL REFERENCES channel_value_time_split(id) ON DELETE CASCADE, - feed_guid UUID NOT NULL, - feed_url varchar_url, - item_guid varchar_uri, - title varchar_normal -); - ---** CHANNEL > VALUE > TIME SPLIT > VALUE RECIPEINT - --- <channel> -> <podcast:value> -> <podcast:valueTimeSplit> -> <podcast:valueRecipient> -CREATE TABLE channel_value_time_split_receipient ( - id SERIAL PRIMARY KEY, - channel_value_time_split_id INTEGER NOT NULL REFERENCES channel_value_time_split(id) ON DELETE CASCADE, - type varchar_short NOT NULL, - address varchar_long NOT NULL, - split FLOAT NOT NULL, - name varchar_normal, - custom_key varchar_long, - custom_value varchar_long, - fee BOOLEAN DEFAULT FALSE -); - --** ITEM -- Technically the item table could be named channel_item, but it seems easier to understand as item. From 231435b616b99f7b839d17daa39ac6ff330fbb7f Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Thu, 29 Aug 2024 20:35:55 -0500 Subject: [PATCH 45/73] Change medium_value to medium --- database/migrations/0004_playlist.sql | 2 +- database/migrations/0005_queue.sql | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/database/migrations/0004_playlist.sql b/database/migrations/0004_playlist.sql index 3254307..c223144 100644 --- a/database/migrations/0004_playlist.sql +++ b/database/migrations/0004_playlist.sql @@ -10,7 +10,7 @@ CREATE TABLE playlist ( is_default_favorites BOOLEAN DEFAULT FALSE, is_public BOOLEAN DEFAULT FALSE, item_count INTEGER DEFAULT 0, - medium_value_id INTEGER NOT NULL REFERENCES medium_value(id) + medium_id INTEGER NOT NULL REFERENCES medium(id) ); CREATE TABLE playlist_resource_base ( diff --git a/database/migrations/0005_queue.sql b/database/migrations/0005_queue.sql index c313e3c..c423f32 100644 --- a/database/migrations/0005_queue.sql +++ b/database/migrations/0005_queue.sql @@ -3,8 +3,8 @@ CREATE TABLE queue ( id SERIAL PRIMARY KEY, account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, - medium_value_id INTEGER NOT NULL REFERENCES medium_value(id), - UNIQUE (account_id, medium_value_id) + medium_id INTEGER NOT NULL REFERENCES medium(id), + UNIQUE (account_id, medium_id) ); CREATE TABLE queue_resource_base ( From 3252aec216621c6bbe166325f9d9cd7b5bc0fc41 Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Thu, 29 Aug 2024 20:36:20 -0500 Subject: [PATCH 46/73] Change medium_value to medium; add guid_enclosure_url to item --- database/combined/init_database.sql | 19 ++++++++++--------- .../0001_init_podcasting_20_database.sql | 13 +++++++------ 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/database/combined/init_database.sql b/database/combined/init_database.sql index eae4415..2804158 100644 --- a/database/combined/init_database.sql +++ b/database/combined/init_database.sql @@ -71,7 +71,7 @@ CREATE TABLE category ( --** MEDIUM VALUE -- <podcast:medium> -CREATE TABLE medium_value ( +CREATE TABLE medium ( id SERIAL PRIMARY KEY, value TEXT UNIQUE CHECK (VALUE IN ( 'publisher', @@ -80,7 +80,7 @@ CREATE TABLE medium_value ( )) ); -INSERT INTO medium_value (value) VALUES +INSERT INTO medium (value) VALUES ('publisher'), ('podcast'), ('music'), ('video'), ('film'), ('audiobook'), ('newsletter'), ('blog'), ('course'), ('mixed'), ('podcastL'), ('musicL'), ('videoL'), ('filmL'), ('audiobookL'), ('newsletterL'), ('blogL'), ('publisherL'), ('courseL') @@ -163,7 +163,7 @@ CREATE TABLE channel ( podcast_guid UUID UNIQUE, -- <podcast:guid> title varchar_normal, sortable_title varchar_short, -- all lowercase, ignores articles at beginning of title - medium_value_id INTEGER REFERENCES medium_value(id), + medium_id INTEGER REFERENCES medium(id), -- TODO: should we hash the last parsed feed, so we can compare it to the hash of -- a feed before completely parsing it, to check if it has changed before continuing? @@ -324,7 +324,7 @@ CREATE TABLE channel_podroll_remote_item ( feed_url varchar_url, item_guid varchar_uri, title varchar_normal, - medium_value_id INTEGER REFERENCES medium_value(id) + medium_id INTEGER REFERENCES medium(id) ); --** CHANNEL > PUBLISHER @@ -345,7 +345,7 @@ CREATE TABLE channel_publisher_remote_item ( feed_url varchar_url, item_guid varchar_uri, title varchar_normal, - medium_value_id INTEGER REFERENCES medium_value(id) + medium_id INTEGER REFERENCES medium(id) ); --** CHANNEL > REMOTE ITEM @@ -361,7 +361,7 @@ CREATE TABLE channel_remote_item ( feed_url varchar_url, item_guid varchar_uri, title varchar_normal, - medium_value_id INTEGER REFERENCES medium_value(id) + medium_id INTEGER REFERENCES medium(id) ); --** CHANNEL > SEASON @@ -457,6 +457,7 @@ CREATE TABLE item ( slug varchar_slug, channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, guid varchar_uri, -- <guid> + guid_enclosure_url varchar_url, -- <guid> enclosure url pubdate TIMESTAMPTZ, -- <pubDate> title varchar_normal, -- <title> @@ -927,7 +928,7 @@ CREATE TABLE playlist ( is_default_favorites BOOLEAN DEFAULT FALSE, is_public BOOLEAN DEFAULT FALSE, item_count INTEGER DEFAULT 0, - medium_value_id INTEGER NOT NULL REFERENCES medium_value(id) + medium_id INTEGER NOT NULL REFERENCES medium(id) ); CREATE TABLE playlist_resource_base ( @@ -995,8 +996,8 @@ EXECUTE FUNCTION delete_playlist_resource_base(); CREATE TABLE queue ( id SERIAL PRIMARY KEY, account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, - medium_value_id INTEGER NOT NULL REFERENCES medium_value(id), - UNIQUE (account_id, medium_value_id) + medium_id INTEGER NOT NULL REFERENCES medium(id), + UNIQUE (account_id, medium_id) ); CREATE TABLE queue_resource_base ( diff --git a/database/migrations/0001_init_podcasting_20_database.sql b/database/migrations/0001_init_podcasting_20_database.sql index 7fa7879..11bd52f 100644 --- a/database/migrations/0001_init_podcasting_20_database.sql +++ b/database/migrations/0001_init_podcasting_20_database.sql @@ -34,7 +34,7 @@ CREATE TABLE category ( --** MEDIUM VALUE -- <podcast:medium> -CREATE TABLE medium_value ( +CREATE TABLE medium ( id SERIAL PRIMARY KEY, value TEXT UNIQUE CHECK (VALUE IN ( 'publisher', @@ -43,7 +43,7 @@ CREATE TABLE medium_value ( )) ); -INSERT INTO medium_value (value) VALUES +INSERT INTO medium (value) VALUES ('publisher'), ('podcast'), ('music'), ('video'), ('film'), ('audiobook'), ('newsletter'), ('blog'), ('course'), ('mixed'), ('podcastL'), ('musicL'), ('videoL'), ('filmL'), ('audiobookL'), ('newsletterL'), ('blogL'), ('publisherL'), ('courseL') @@ -126,7 +126,7 @@ CREATE TABLE channel ( podcast_guid UUID UNIQUE, -- <podcast:guid> title varchar_normal, sortable_title varchar_short, -- all lowercase, ignores articles at beginning of title - medium_value_id INTEGER REFERENCES medium_value(id), + medium_id INTEGER REFERENCES medium(id), -- TODO: should we hash the last parsed feed, so we can compare it to the hash of -- a feed before completely parsing it, to check if it has changed before continuing? @@ -287,7 +287,7 @@ CREATE TABLE channel_podroll_remote_item ( feed_url varchar_url, item_guid varchar_uri, title varchar_normal, - medium_value_id INTEGER REFERENCES medium_value(id) + medium_id INTEGER REFERENCES medium(id) ); --** CHANNEL > PUBLISHER @@ -308,7 +308,7 @@ CREATE TABLE channel_publisher_remote_item ( feed_url varchar_url, item_guid varchar_uri, title varchar_normal, - medium_value_id INTEGER REFERENCES medium_value(id) + medium_id INTEGER REFERENCES medium(id) ); --** CHANNEL > REMOTE ITEM @@ -324,7 +324,7 @@ CREATE TABLE channel_remote_item ( feed_url varchar_url, item_guid varchar_uri, title varchar_normal, - medium_value_id INTEGER REFERENCES medium_value(id) + medium_id INTEGER REFERENCES medium(id) ); --** CHANNEL > SEASON @@ -420,6 +420,7 @@ CREATE TABLE item ( slug varchar_slug, channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, guid varchar_uri, -- <guid> + guid_enclosure_url varchar_url, -- <guid> enclosure url pubdate TIMESTAMPTZ, -- <pubDate> title varchar_normal, -- <title> From 4e8887f0c42d747a508e600b4dab4a15b98a49ec Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Thu, 29 Aug 2024 20:42:26 -0500 Subject: [PATCH 47/73] Update comment --- database/combined/init_database.sql | 2 +- database/migrations/0001_init_podcasting_20_database.sql | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/database/combined/init_database.sql b/database/combined/init_database.sql index 2804158..71417cc 100644 --- a/database/combined/init_database.sql +++ b/database/combined/init_database.sql @@ -457,7 +457,7 @@ CREATE TABLE item ( slug varchar_slug, channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, guid varchar_uri, -- <guid> - guid_enclosure_url varchar_url, -- <guid> enclosure url + guid_enclosure_url varchar_url NOT NULL, -- enclosure url pubdate TIMESTAMPTZ, -- <pubDate> title varchar_normal, -- <title> diff --git a/database/migrations/0001_init_podcasting_20_database.sql b/database/migrations/0001_init_podcasting_20_database.sql index 11bd52f..962e46a 100644 --- a/database/migrations/0001_init_podcasting_20_database.sql +++ b/database/migrations/0001_init_podcasting_20_database.sql @@ -420,7 +420,7 @@ CREATE TABLE item ( slug varchar_slug, channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, guid varchar_uri, -- <guid> - guid_enclosure_url varchar_url, -- <guid> enclosure url + guid_enclosure_url varchar_url NOT NULL, -- enclosure url pubdate TIMESTAMPTZ, -- <pubDate> title varchar_normal, -- <title> From 1ba48d3998bf3a028909d961cbd45140ef41f513 Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Thu, 29 Aug 2024 22:15:36 -0500 Subject: [PATCH 48/73] Add item_chapters_feed_log --- database/combined/init_database.sql | 22 +++++++++++++++++-- .../0001_init_podcasting_20_database.sql | 22 +++++++++++++++++-- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/database/combined/init_database.sql b/database/combined/init_database.sql index 71417cc..7941dde 100644 --- a/database/combined/init_database.sql +++ b/database/combined/init_database.sql @@ -493,7 +493,7 @@ CREATE TABLE item_about ( --** ITEM > CHAPTERS -- <item> -> <podcast:chapters> -CREATE TABLE item_chapters ( +CREATE TABLE item_chapters_feed ( id SERIAL PRIMARY KEY, item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, url varchar_url NOT NULL, @@ -507,11 +507,29 @@ CREATE TABLE item_chapters ( parse_errors INTEGER DEFAULT 0 ); +--** ITEM > CHAPTERS > LOG + +-- <item> -> <podcast:chapters> -> parsing logs + +CREATE TABLE item_chapters_feed_log ( + id SERIAL PRIMARY KEY, + item_chapters_feed_id INTEGER NOT NULL REFERENCES item_chapters_feed(id) ON DELETE CASCADE, + last_http_status INTEGER, + last_crawl_time server_time, + last_good_http_status_time server_time, + last_parse_time server_time, + last_update_time server_time, + crawl_errors INTEGER DEFAULT 0, + parse_errors INTEGER DEFAULT 0 +); + +--** ITEM > CHAPTERS > CHAPTER + -- -- <item> -> <podcast:chapters> -> chapter items correspond with jsonChapters.md example file CREATE TABLE item_chapter ( id SERIAL PRIMARY KEY, text_id short_id_v2 UNIQUE NOT NULL, - item_chapters_file_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + item_chapters_feed_id INTEGER NOT NULL REFERENCES item_chapters_feed(id) ON DELETE CASCADE, -- the hash is used for comparison, to determine if new chapters should be inserted -- after re-parsing an existing chapters file. diff --git a/database/migrations/0001_init_podcasting_20_database.sql b/database/migrations/0001_init_podcasting_20_database.sql index 962e46a..4fcc433 100644 --- a/database/migrations/0001_init_podcasting_20_database.sql +++ b/database/migrations/0001_init_podcasting_20_database.sql @@ -456,7 +456,7 @@ CREATE TABLE item_about ( --** ITEM > CHAPTERS -- <item> -> <podcast:chapters> -CREATE TABLE item_chapters ( +CREATE TABLE item_chapters_feed ( id SERIAL PRIMARY KEY, item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, url varchar_url NOT NULL, @@ -470,11 +470,29 @@ CREATE TABLE item_chapters ( parse_errors INTEGER DEFAULT 0 ); +--** ITEM > CHAPTERS > LOG + +-- <item> -> <podcast:chapters> -> parsing logs + +CREATE TABLE item_chapters_feed_log ( + id SERIAL PRIMARY KEY, + item_chapters_feed_id INTEGER NOT NULL REFERENCES item_chapters_feed(id) ON DELETE CASCADE, + last_http_status INTEGER, + last_crawl_time server_time, + last_good_http_status_time server_time, + last_parse_time server_time, + last_update_time server_time, + crawl_errors INTEGER DEFAULT 0, + parse_errors INTEGER DEFAULT 0 +); + +--** ITEM > CHAPTERS > CHAPTER + -- -- <item> -> <podcast:chapters> -> chapter items correspond with jsonChapters.md example file CREATE TABLE item_chapter ( id SERIAL PRIMARY KEY, text_id short_id_v2 UNIQUE NOT NULL, - item_chapters_file_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + item_chapters_feed_id INTEGER NOT NULL REFERENCES item_chapters_feed(id) ON DELETE CASCADE, -- the hash is used for comparison, to determine if new chapters should be inserted -- after re-parsing an existing chapters file. From e105f5c8b5365205a0ab02e3c7b543f21b56cb89 Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Thu, 29 Aug 2024 22:25:59 -0500 Subject: [PATCH 49/73] Remove unused item_chapters_feed log columns --- database/combined/init_database.sql | 9 +-------- database/migrations/0001_init_podcasting_20_database.sql | 9 +-------- 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/database/combined/init_database.sql b/database/combined/init_database.sql index 7941dde..782a7df 100644 --- a/database/combined/init_database.sql +++ b/database/combined/init_database.sql @@ -497,14 +497,7 @@ CREATE TABLE item_chapters_feed ( id SERIAL PRIMARY KEY, item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, url varchar_url NOT NULL, - type varchar_short NOT NULL, - last_http_status INTEGER, - last_crawl_time server_time, - last_good_http_status_time server_time, - last_parse_time server_time, - last_update_time server_time, - crawl_errors INTEGER DEFAULT 0, - parse_errors INTEGER DEFAULT 0 + type varchar_short NOT NULL ); --** ITEM > CHAPTERS > LOG diff --git a/database/migrations/0001_init_podcasting_20_database.sql b/database/migrations/0001_init_podcasting_20_database.sql index 4fcc433..269c3dc 100644 --- a/database/migrations/0001_init_podcasting_20_database.sql +++ b/database/migrations/0001_init_podcasting_20_database.sql @@ -460,14 +460,7 @@ CREATE TABLE item_chapters_feed ( id SERIAL PRIMARY KEY, item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, url varchar_url NOT NULL, - type varchar_short NOT NULL, - last_http_status INTEGER, - last_crawl_time server_time, - last_good_http_status_time server_time, - last_parse_time server_time, - last_update_time server_time, - crawl_errors INTEGER DEFAULT 0, - parse_errors INTEGER DEFAULT 0 + type varchar_short NOT NULL ); --** ITEM > CHAPTERS > LOG From 9b293ed3f54386200e0ad95419521ba958fe5963 Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Fri, 30 Aug 2024 01:24:20 -0500 Subject: [PATCH 50/73] Add missing column to item_Person and item_season_episode --- database/combined/init_database.sql | 3 ++- database/migrations/0001_init_podcasting_20_database.sql | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/database/combined/init_database.sql b/database/combined/init_database.sql index 782a7df..90dabef 100644 --- a/database/combined/init_database.sql +++ b/database/combined/init_database.sql @@ -682,7 +682,7 @@ CREATE TABLE item_location ( -- <item> -> <podcast:person> CREATE TABLE item_person ( id SERIAL PRIMARY KEY, - channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, name varchar_normal NOT NULL, role varchar_normal, person_group varchar_normal DEFAULT 'cast', -- group is a reserved keyword in sql @@ -705,6 +705,7 @@ CREATE TABLE item_season ( -- <item> -> <podcast:season> -> <podcast:episode> CREATE TABLE item_season_episode ( id SERIAL PRIMARY KEY, + channel_season_id INTEGER NOT NULL REFERENCES channel_season(id) ON DELETE CASCADE, item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, display varchar_short, episode_number FLOAT NOT NULL diff --git a/database/migrations/0001_init_podcasting_20_database.sql b/database/migrations/0001_init_podcasting_20_database.sql index 269c3dc..7e44b16 100644 --- a/database/migrations/0001_init_podcasting_20_database.sql +++ b/database/migrations/0001_init_podcasting_20_database.sql @@ -645,7 +645,7 @@ CREATE TABLE item_location ( -- <item> -> <podcast:person> CREATE TABLE item_person ( id SERIAL PRIMARY KEY, - channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, name varchar_normal NOT NULL, role varchar_normal, person_group varchar_normal DEFAULT 'cast', -- group is a reserved keyword in sql @@ -668,6 +668,7 @@ CREATE TABLE item_season ( -- <item> -> <podcast:season> -> <podcast:episode> CREATE TABLE item_season_episode ( id SERIAL PRIMARY KEY, + channel_season_id INTEGER NOT NULL REFERENCES channel_season(id) ON DELETE CASCADE, item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, display varchar_short, episode_number FLOAT NOT NULL From 23af605d93cc685e61bec9a2e447d03d34ce816d Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Fri, 30 Aug 2024 01:42:13 -0500 Subject: [PATCH 51/73] Remove url column from item_soundbite --- database/combined/init_database.sql | 1 - database/migrations/0001_init_podcasting_20_database.sql | 1 - 2 files changed, 2 deletions(-) diff --git a/database/combined/init_database.sql b/database/combined/init_database.sql index 90dabef..5a9fe0e 100644 --- a/database/combined/init_database.sql +++ b/database/combined/init_database.sql @@ -731,7 +731,6 @@ CREATE TABLE item_soundbite ( id SERIAL PRIMARY KEY, id_text short_id_v2 UNIQUE NOT NULL, item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, - url varchar_url NOT NULL, start_time INTEGER NOT NULL, duration INTEGER NOT NULL, title varchar_normal diff --git a/database/migrations/0001_init_podcasting_20_database.sql b/database/migrations/0001_init_podcasting_20_database.sql index 7e44b16..888a01b 100644 --- a/database/migrations/0001_init_podcasting_20_database.sql +++ b/database/migrations/0001_init_podcasting_20_database.sql @@ -694,7 +694,6 @@ CREATE TABLE item_soundbite ( id SERIAL PRIMARY KEY, id_text short_id_v2 UNIQUE NOT NULL, item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, - url varchar_url NOT NULL, start_time INTEGER NOT NULL, duration INTEGER NOT NULL, title varchar_normal From 571438a347d0df4dde8faf5aa430c97e552ee8ca Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Fri, 30 Aug 2024 14:43:49 -0500 Subject: [PATCH 52/73] Use numeric instead of integer for player times --- database/combined/init_database.sql | 16 ++++++++-------- .../0001_init_podcasting_20_database.sql | 14 +++++++------- database/migrations/0005_queue.sql | 2 +- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/database/combined/init_database.sql b/database/combined/init_database.sql index 5a9fe0e..ce5fea6 100644 --- a/database/combined/init_database.sql +++ b/database/combined/init_database.sql @@ -484,7 +484,7 @@ INSERT INTO item_itunes_episode_type (itunes_episode_type) VALUES ('full'), ('tr CREATE TABLE item_about ( id SERIAL PRIMARY KEY, item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, - duration INTEGER, -- <itunes:duration> + duration media_player_time, -- <itunes:duration> explicit BOOLEAN, -- <itunes:explicit> website_link_url varchar_url, -- <link> item_itunes_episode_type_id INTEGER REFERENCES item_itunes_episode_type(id) -- <itunes:episodeType> @@ -731,8 +731,8 @@ CREATE TABLE item_soundbite ( id SERIAL PRIMARY KEY, id_text short_id_v2 UNIQUE NOT NULL, item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, - start_time INTEGER NOT NULL, - duration INTEGER NOT NULL, + start_time media_player_time NOT NULL, + duration media_player_time NOT NULL, title varchar_normal ); @@ -790,10 +790,10 @@ CREATE TABLE item_value_receipient ( CREATE TABLE item_value_time_split ( id SERIAL PRIMARY KEY, item_value_id INTEGER NOT NULL REFERENCES item_value(id) ON DELETE CASCADE, - start_time INTEGER NOT NULL, - duration INTEGER NOT NULL, - remote_start_time INTEGER DEFAULT 0, - remote_percentage INTEGER DEFAULT 100 + start_time media_player_time NOT NULL, + duration media_player_time NOT NULL, + remote_start_time media_player_time DEFAULT 0, + remote_percentage media_player_time DEFAULT 100 ); --** ITEM > VALUE > TIME SPLIT > REMOTE ITEM @@ -1017,7 +1017,7 @@ CREATE TABLE queue_resource_base ( UNIQUE (queue_id, list_position), list_position list_position NOT NULL CHECK (list_position != 0 OR list_position = 0::numeric), playback_position media_player_time NOT NULL DEFAULT 0, - media_file_duration FLOAT NOT NULL DEFAULT 0, + media_file_duration media_player_time NOT NULL DEFAULT 0, completed BOOLEAN NOT NULL DEFAULT FALSE ); diff --git a/database/migrations/0001_init_podcasting_20_database.sql b/database/migrations/0001_init_podcasting_20_database.sql index 888a01b..2e35d68 100644 --- a/database/migrations/0001_init_podcasting_20_database.sql +++ b/database/migrations/0001_init_podcasting_20_database.sql @@ -447,7 +447,7 @@ INSERT INTO item_itunes_episode_type (itunes_episode_type) VALUES ('full'), ('tr CREATE TABLE item_about ( id SERIAL PRIMARY KEY, item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, - duration INTEGER, -- <itunes:duration> + duration media_player_time, -- <itunes:duration> explicit BOOLEAN, -- <itunes:explicit> website_link_url varchar_url, -- <link> item_itunes_episode_type_id INTEGER REFERENCES item_itunes_episode_type(id) -- <itunes:episodeType> @@ -694,8 +694,8 @@ CREATE TABLE item_soundbite ( id SERIAL PRIMARY KEY, id_text short_id_v2 UNIQUE NOT NULL, item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, - start_time INTEGER NOT NULL, - duration INTEGER NOT NULL, + start_time media_player_time NOT NULL, + duration media_player_time NOT NULL, title varchar_normal ); @@ -753,10 +753,10 @@ CREATE TABLE item_value_receipient ( CREATE TABLE item_value_time_split ( id SERIAL PRIMARY KEY, item_value_id INTEGER NOT NULL REFERENCES item_value(id) ON DELETE CASCADE, - start_time INTEGER NOT NULL, - duration INTEGER NOT NULL, - remote_start_time INTEGER DEFAULT 0, - remote_percentage INTEGER DEFAULT 100 + start_time media_player_time NOT NULL, + duration media_player_time NOT NULL, + remote_start_time media_player_time DEFAULT 0, + remote_percentage media_player_time DEFAULT 100 ); --** ITEM > VALUE > TIME SPLIT > REMOTE ITEM diff --git a/database/migrations/0005_queue.sql b/database/migrations/0005_queue.sql index c423f32..55279fd 100644 --- a/database/migrations/0005_queue.sql +++ b/database/migrations/0005_queue.sql @@ -13,7 +13,7 @@ CREATE TABLE queue_resource_base ( UNIQUE (queue_id, list_position), list_position list_position NOT NULL CHECK (list_position != 0 OR list_position = 0::numeric), playback_position media_player_time NOT NULL DEFAULT 0, - media_file_duration FLOAT NOT NULL DEFAULT 0, + media_file_duration media_player_time NOT NULL DEFAULT 0, completed BOOLEAN NOT NULL DEFAULT FALSE ); From c44189699c641809f65d7d35472812428080031b Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Fri, 30 Aug 2024 23:09:15 -0500 Subject: [PATCH 53/73] Fix typos in "recipient" spelling --- database/combined/init_database.sql | 8 ++++---- database/migrations/0001_init_podcasting_20_database.sql | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/database/combined/init_database.sql b/database/combined/init_database.sql index ce5fea6..9e821f0 100644 --- a/database/combined/init_database.sql +++ b/database/combined/init_database.sql @@ -406,7 +406,7 @@ CREATE TABLE channel_trailer ( pubdate TIMESTAMPTZ NOT NULL, length INTEGER, type varchar_short, - season INTEGER, + channel_season_id INTEGER REFERENCES channel_season(id), UNIQUE (channel_id, url) ); @@ -434,7 +434,7 @@ CREATE TABLE channel_value ( --** CHANNEL > VALUE > RECEIPIENT -- <channel> -> <podcast:value> -> <podcast:valueRecipient> -CREATE TABLE channel_value_receipient ( +CREATE TABLE channel_value_recipient ( id SERIAL PRIMARY KEY, channel_value_id INTEGER NOT NULL REFERENCES channel_value(id) ON DELETE CASCADE, type varchar_short NOT NULL, @@ -772,7 +772,7 @@ CREATE TABLE item_value ( --** ITEM > VALUE > RECEIPIENT -- <item> -> <podcast:value> -> <podcast:valueRecipient> -CREATE TABLE item_value_receipient ( +CREATE TABLE item_value_recipient ( id SERIAL PRIMARY KEY, item_value_id INTEGER NOT NULL REFERENCES item_value(id) ON DELETE CASCADE, type varchar_short NOT NULL, @@ -811,7 +811,7 @@ CREATE TABLE item_value_time_split_remote_item ( --** ITEM > VALUE > TIME SPLIT > VALUE RECIPEINT -- <item> -> <podcast:value> -> <podcast:valueTimeSplit> -> <podcast:valueRecipient> -CREATE TABLE item_value_time_split_receipient ( +CREATE TABLE item_value_time_split_recipient ( id SERIAL PRIMARY KEY, item_value_time_split_id INTEGER NOT NULL REFERENCES item_value_time_split(id) ON DELETE CASCADE, type varchar_short NOT NULL, diff --git a/database/migrations/0001_init_podcasting_20_database.sql b/database/migrations/0001_init_podcasting_20_database.sql index 2e35d68..3f4d926 100644 --- a/database/migrations/0001_init_podcasting_20_database.sql +++ b/database/migrations/0001_init_podcasting_20_database.sql @@ -369,7 +369,7 @@ CREATE TABLE channel_trailer ( pubdate TIMESTAMPTZ NOT NULL, length INTEGER, type varchar_short, - season INTEGER, + channel_season_id INTEGER REFERENCES channel_season(id), UNIQUE (channel_id, url) ); @@ -397,7 +397,7 @@ CREATE TABLE channel_value ( --** CHANNEL > VALUE > RECEIPIENT -- <channel> -> <podcast:value> -> <podcast:valueRecipient> -CREATE TABLE channel_value_receipient ( +CREATE TABLE channel_value_recipient ( id SERIAL PRIMARY KEY, channel_value_id INTEGER NOT NULL REFERENCES channel_value(id) ON DELETE CASCADE, type varchar_short NOT NULL, @@ -735,7 +735,7 @@ CREATE TABLE item_value ( --** ITEM > VALUE > RECEIPIENT -- <item> -> <podcast:value> -> <podcast:valueRecipient> -CREATE TABLE item_value_receipient ( +CREATE TABLE item_value_recipient ( id SERIAL PRIMARY KEY, item_value_id INTEGER NOT NULL REFERENCES item_value(id) ON DELETE CASCADE, type varchar_short NOT NULL, @@ -774,7 +774,7 @@ CREATE TABLE item_value_time_split_remote_item ( --** ITEM > VALUE > TIME SPLIT > VALUE RECIPEINT -- <item> -> <podcast:value> -> <podcast:valueTimeSplit> -> <podcast:valueRecipient> -CREATE TABLE item_value_time_split_receipient ( +CREATE TABLE item_value_time_split_recipient ( id SERIAL PRIMARY KEY, item_value_time_split_id INTEGER NOT NULL REFERENCES item_value_time_split(id) ON DELETE CASCADE, type varchar_short NOT NULL, From 8915aa891558163adb32c48d3237d00725732036 Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Fri, 30 Aug 2024 23:30:41 -0500 Subject: [PATCH 54/73] Update item_season_episode table --- database/combined/init_database.sql | 3 +-- database/migrations/0001_init_podcasting_20_database.sql | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/database/combined/init_database.sql b/database/combined/init_database.sql index 9e821f0..dd98a71 100644 --- a/database/combined/init_database.sql +++ b/database/combined/init_database.sql @@ -705,10 +705,9 @@ CREATE TABLE item_season ( -- <item> -> <podcast:season> -> <podcast:episode> CREATE TABLE item_season_episode ( id SERIAL PRIMARY KEY, - channel_season_id INTEGER NOT NULL REFERENCES channel_season(id) ON DELETE CASCADE, item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, display varchar_short, - episode_number FLOAT NOT NULL + number FLOAT NOT NULL ); --** ITEM > SOCIAL INTERACT diff --git a/database/migrations/0001_init_podcasting_20_database.sql b/database/migrations/0001_init_podcasting_20_database.sql index 3f4d926..a34fa51 100644 --- a/database/migrations/0001_init_podcasting_20_database.sql +++ b/database/migrations/0001_init_podcasting_20_database.sql @@ -668,10 +668,9 @@ CREATE TABLE item_season ( -- <item> -> <podcast:season> -> <podcast:episode> CREATE TABLE item_season_episode ( id SERIAL PRIMARY KEY, - channel_season_id INTEGER NOT NULL REFERENCES channel_season(id) ON DELETE CASCADE, item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, display varchar_short, - episode_number FLOAT NOT NULL + number FLOAT NOT NULL ); --** ITEM > SOCIAL INTERACT From dae2c6603f827cc62f4699b7a4c3f18a2dba5b2a Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Sat, 31 Aug 2024 16:42:52 -0500 Subject: [PATCH 55/73] Make protocol column required in chat tables --- database/combined/init_database.sql | 4 ++-- database/migrations/0001_init_podcasting_20_database.sql | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/database/combined/init_database.sql b/database/combined/init_database.sql index dd98a71..9362369 100644 --- a/database/combined/init_database.sql +++ b/database/combined/init_database.sql @@ -220,7 +220,7 @@ CREATE TABLE channel_chat ( id SERIAL PRIMARY KEY, channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, server varchar_fqdn NOT NULL, - protocol varchar_short, + protocol varchar_short NOT NULL, account_id varchar_normal, space varchar_normal ); @@ -569,7 +569,7 @@ CREATE TABLE item_chat ( id SERIAL PRIMARY KEY, item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, server varchar_fqdn NOT NULL, - protocol varchar_short, + protocol varchar_short NOT NULL, account_id varchar_normal, space varchar_normal ); diff --git a/database/migrations/0001_init_podcasting_20_database.sql b/database/migrations/0001_init_podcasting_20_database.sql index a34fa51..d9abda1 100644 --- a/database/migrations/0001_init_podcasting_20_database.sql +++ b/database/migrations/0001_init_podcasting_20_database.sql @@ -183,7 +183,7 @@ CREATE TABLE channel_chat ( id SERIAL PRIMARY KEY, channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, server varchar_fqdn NOT NULL, - protocol varchar_short, + protocol varchar_short NOT NULL, account_id varchar_normal, space varchar_normal ); @@ -532,7 +532,7 @@ CREATE TABLE item_chat ( id SERIAL PRIMARY KEY, item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, server varchar_fqdn NOT NULL, - protocol varchar_short, + protocol varchar_short NOT NULL, account_id varchar_normal, space varchar_normal ); From e5f05bf093961a6c1408122fdc122a3599c34fa5 Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Sat, 31 Aug 2024 19:54:07 -0500 Subject: [PATCH 56/73] Add last_parsed_file_hash column to feed table --- database/combined/init_database.sql | 5 +++++ database/migrations/0000_init_helpers.sql | 1 + database/migrations/0001_init_podcasting_20_database.sql | 4 ++++ 3 files changed, 10 insertions(+) diff --git a/database/combined/init_database.sql b/database/combined/init_database.sql index 9362369..d93092b 100644 --- a/database/combined/init_database.sql +++ b/database/combined/init_database.sql @@ -14,6 +14,7 @@ CREATE DOMAIN varchar_long AS VARCHAR(2500); CREATE DOMAIN varchar_email AS VARCHAR(255) CHECK (VALUE ~ '^.+@.+\..+$'); CREATE DOMAIN varchar_fqdn AS VARCHAR(253); CREATE DOMAIN varchar_guid AS VARCHAR(36); +CREATE DOMAIN varchar_md5 AS VARCHAR(32); CREATE DOMAIN varchar_password AS VARCHAR(36); CREATE DOMAIN varchar_slug AS VARCHAR(100); CREATE DOMAIN varchar_uri AS VARCHAR(2083); @@ -127,6 +128,10 @@ CREATE TABLE feed ( -- higher parsing_priority will be parsed more frequently on a schedule. parsing_priority INTEGER DEFAULT 0 CHECK (parsing_priority BETWEEN 0 AND 5), + -- the hash of the last parsed feed file. + -- used for comparison to determine if full re-parsing is needed. + last_parsed_file_hash varchar_md5, + -- the run-time environment container id container_id VARCHAR(12), diff --git a/database/migrations/0000_init_helpers.sql b/database/migrations/0000_init_helpers.sql index d6ba36b..167c585 100644 --- a/database/migrations/0000_init_helpers.sql +++ b/database/migrations/0000_init_helpers.sql @@ -14,6 +14,7 @@ CREATE DOMAIN varchar_long AS VARCHAR(2500); CREATE DOMAIN varchar_email AS VARCHAR(255) CHECK (VALUE ~ '^.+@.+\..+$'); CREATE DOMAIN varchar_fqdn AS VARCHAR(253); CREATE DOMAIN varchar_guid AS VARCHAR(36); +CREATE DOMAIN varchar_md5 AS VARCHAR(32); CREATE DOMAIN varchar_password AS VARCHAR(36); CREATE DOMAIN varchar_slug AS VARCHAR(100); CREATE DOMAIN varchar_uri AS VARCHAR(2083); diff --git a/database/migrations/0001_init_podcasting_20_database.sql b/database/migrations/0001_init_podcasting_20_database.sql index d9abda1..f245d8d 100644 --- a/database/migrations/0001_init_podcasting_20_database.sql +++ b/database/migrations/0001_init_podcasting_20_database.sql @@ -90,6 +90,10 @@ CREATE TABLE feed ( -- higher parsing_priority will be parsed more frequently on a schedule. parsing_priority INTEGER DEFAULT 0 CHECK (parsing_priority BETWEEN 0 AND 5), + -- the hash of the last parsed feed file. + -- used for comparison to determine if full re-parsing is needed. + last_parsed_file_hash varchar_md5, + -- the run-time environment container id container_id VARCHAR(12), From 336c3bc3bde8b8ec041e0e63f2612155ae7bde2b Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Sat, 31 Aug 2024 22:01:48 -0500 Subject: [PATCH 57/73] Fix item_chapter column name id_text --- database/combined/init_database.sql | 2 +- database/migrations/0001_init_podcasting_20_database.sql | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/database/combined/init_database.sql b/database/combined/init_database.sql index d93092b..fca9649 100644 --- a/database/combined/init_database.sql +++ b/database/combined/init_database.sql @@ -526,7 +526,7 @@ CREATE TABLE item_chapters_feed_log ( -- -- <item> -> <podcast:chapters> -> chapter items correspond with jsonChapters.md example file CREATE TABLE item_chapter ( id SERIAL PRIMARY KEY, - text_id short_id_v2 UNIQUE NOT NULL, + id_text short_id_v2 UNIQUE NOT NULL, item_chapters_feed_id INTEGER NOT NULL REFERENCES item_chapters_feed(id) ON DELETE CASCADE, -- the hash is used for comparison, to determine if new chapters should be inserted diff --git a/database/migrations/0001_init_podcasting_20_database.sql b/database/migrations/0001_init_podcasting_20_database.sql index f245d8d..74d8949 100644 --- a/database/migrations/0001_init_podcasting_20_database.sql +++ b/database/migrations/0001_init_podcasting_20_database.sql @@ -488,7 +488,7 @@ CREATE TABLE item_chapters_feed_log ( -- -- <item> -> <podcast:chapters> -> chapter items correspond with jsonChapters.md example file CREATE TABLE item_chapter ( id SERIAL PRIMARY KEY, - text_id short_id_v2 UNIQUE NOT NULL, + id_text short_id_v2 UNIQUE NOT NULL, item_chapters_feed_id INTEGER NOT NULL REFERENCES item_chapters_feed(id) ON DELETE CASCADE, -- the hash is used for comparison, to determine if new chapters should be inserted From 15bb60614f2680a3773495b518ab28b1dc7b61a6 Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Sat, 31 Aug 2024 22:51:00 -0500 Subject: [PATCH 58/73] Remove item_chapter_image table --- database/combined/init_database.sql | 21 +------------------ .../0001_init_podcasting_20_database.sql | 21 +------------------ 2 files changed, 2 insertions(+), 40 deletions(-) diff --git a/database/combined/init_database.sql b/database/combined/init_database.sql index fca9649..15be8a4 100644 --- a/database/combined/init_database.sql +++ b/database/combined/init_database.sql @@ -528,33 +528,14 @@ CREATE TABLE item_chapter ( id SERIAL PRIMARY KEY, id_text short_id_v2 UNIQUE NOT NULL, item_chapters_feed_id INTEGER NOT NULL REFERENCES item_chapters_feed(id) ON DELETE CASCADE, - - -- the hash is used for comparison, to determine if new chapters should be inserted - -- after re-parsing an existing chapters file. - hash varchar_guid NOT NULL, - start_time media_player_time NOT NULL, end_time media_player_time, title varchar_normal, + img varchar_url, web_url varchar_url, table_of_contents BOOLEAN DEFAULT TRUE ); ---** ITEM > CHAPTER > IMAGE - --- <item> -> <podcast:chapters> -> chapter items correspond with jsonChapters.md example file -CREATE TABLE item_chapter_image ( - id SERIAL PRIMARY KEY, - item_chapter_id INTEGER NOT NULL REFERENCES item_chapter(id) ON DELETE CASCADE, - url varchar_url NOT NULL, - image_width_size INTEGER, -- <podcast:image> must have a width specified, but older image tags will not, so allow null. - - -- If true, then the image is hosted by us in a service like S3. - -- When is_resized images are deleted, the corresponding image in S3 - -- should also be deleted. - is_resized BOOLEAN DEFAULT FALSE -); - --** ITEM > CHAPTER > LOCATION -- <item> -> <podcast:chapters> -> chapter items correspond with jsonChapters.md example file diff --git a/database/migrations/0001_init_podcasting_20_database.sql b/database/migrations/0001_init_podcasting_20_database.sql index 74d8949..3b770e4 100644 --- a/database/migrations/0001_init_podcasting_20_database.sql +++ b/database/migrations/0001_init_podcasting_20_database.sql @@ -490,33 +490,14 @@ CREATE TABLE item_chapter ( id SERIAL PRIMARY KEY, id_text short_id_v2 UNIQUE NOT NULL, item_chapters_feed_id INTEGER NOT NULL REFERENCES item_chapters_feed(id) ON DELETE CASCADE, - - -- the hash is used for comparison, to determine if new chapters should be inserted - -- after re-parsing an existing chapters file. - hash varchar_guid NOT NULL, - start_time media_player_time NOT NULL, end_time media_player_time, title varchar_normal, + img varchar_url, web_url varchar_url, table_of_contents BOOLEAN DEFAULT TRUE ); ---** ITEM > CHAPTER > IMAGE - --- <item> -> <podcast:chapters> -> chapter items correspond with jsonChapters.md example file -CREATE TABLE item_chapter_image ( - id SERIAL PRIMARY KEY, - item_chapter_id INTEGER NOT NULL REFERENCES item_chapter(id) ON DELETE CASCADE, - url varchar_url NOT NULL, - image_width_size INTEGER, -- <podcast:image> must have a width specified, but older image tags will not, so allow null. - - -- If true, then the image is hosted by us in a service like S3. - -- When is_resized images are deleted, the corresponding image in S3 - -- should also be deleted. - is_resized BOOLEAN DEFAULT FALSE -); - --** ITEM > CHAPTER > LOCATION -- <item> -> <podcast:chapters> -> chapter items correspond with jsonChapters.md example file From 868ae77e017aee7763fd77f7331233e6c00f3e39 Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Sun, 1 Sep 2024 01:42:28 -0500 Subject: [PATCH 59/73] Update feed_log --- database/combined/init_database.sql | 8 +------- database/migrations/0001_init_podcasting_20_database.sql | 8 +------- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/database/combined/init_database.sql b/database/combined/init_database.sql index 15be8a4..43a2e26 100644 --- a/database/combined/init_database.sql +++ b/database/combined/init_database.sql @@ -148,11 +148,9 @@ CREATE TABLE feed_log ( id SERIAL PRIMARY KEY, feed_id INTEGER NOT NULL REFERENCES feed(id) ON DELETE CASCADE, last_http_status INTEGER, - last_crawl_time server_time, last_good_http_status_time server_time, last_parse_time server_time, last_update_time server_time, - crawl_errors INTEGER DEFAULT 0, parse_errors INTEGER DEFAULT 0 ); @@ -170,9 +168,6 @@ CREATE TABLE channel ( sortable_title varchar_short, -- all lowercase, ignores articles at beginning of title medium_id INTEGER REFERENCES medium(id), - -- TODO: should we hash the last parsed feed, so we can compare it to the hash of - -- a feed before completely parsing it, to check if it has changed before continuing? - -- channels that have a PI value tag require special handling to request value data -- from the Podcast Index API. has_podcast_index_value BOOLEAN DEFAULT FALSE, @@ -207,6 +202,7 @@ CREATE TABLE channel_about ( explicit BOOLEAN, -- <itunes:explicit> itunes_type_id INTEGER REFERENCES channel_itunes_type(id), language varchar_short, -- <language> + last_pub_date server_time_with_default, -- <pubDate> website_link_url varchar_url -- <link> ); @@ -513,11 +509,9 @@ CREATE TABLE item_chapters_feed_log ( id SERIAL PRIMARY KEY, item_chapters_feed_id INTEGER NOT NULL REFERENCES item_chapters_feed(id) ON DELETE CASCADE, last_http_status INTEGER, - last_crawl_time server_time, last_good_http_status_time server_time, last_parse_time server_time, last_update_time server_time, - crawl_errors INTEGER DEFAULT 0, parse_errors INTEGER DEFAULT 0 ); diff --git a/database/migrations/0001_init_podcasting_20_database.sql b/database/migrations/0001_init_podcasting_20_database.sql index 3b770e4..f2f1b1e 100644 --- a/database/migrations/0001_init_podcasting_20_database.sql +++ b/database/migrations/0001_init_podcasting_20_database.sql @@ -110,11 +110,9 @@ CREATE TABLE feed_log ( id SERIAL PRIMARY KEY, feed_id INTEGER NOT NULL REFERENCES feed(id) ON DELETE CASCADE, last_http_status INTEGER, - last_crawl_time server_time, last_good_http_status_time server_time, last_parse_time server_time, last_update_time server_time, - crawl_errors INTEGER DEFAULT 0, parse_errors INTEGER DEFAULT 0 ); @@ -132,9 +130,6 @@ CREATE TABLE channel ( sortable_title varchar_short, -- all lowercase, ignores articles at beginning of title medium_id INTEGER REFERENCES medium(id), - -- TODO: should we hash the last parsed feed, so we can compare it to the hash of - -- a feed before completely parsing it, to check if it has changed before continuing? - -- channels that have a PI value tag require special handling to request value data -- from the Podcast Index API. has_podcast_index_value BOOLEAN DEFAULT FALSE, @@ -169,6 +164,7 @@ CREATE TABLE channel_about ( explicit BOOLEAN, -- <itunes:explicit> itunes_type_id INTEGER REFERENCES channel_itunes_type(id), language varchar_short, -- <language> + last_pub_date server_time_with_default, -- <pubDate> website_link_url varchar_url -- <link> ); @@ -475,11 +471,9 @@ CREATE TABLE item_chapters_feed_log ( id SERIAL PRIMARY KEY, item_chapters_feed_id INTEGER NOT NULL REFERENCES item_chapters_feed(id) ON DELETE CASCADE, last_http_status INTEGER, - last_crawl_time server_time, last_good_http_status_time server_time, last_parse_time server_time, last_update_time server_time, - crawl_errors INTEGER DEFAULT 0, parse_errors INTEGER DEFAULT 0 ); From 4a30352687aa5129d3c1050571530a6a5b8db570 Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Fri, 6 Sep 2024 00:50:14 -0500 Subject: [PATCH 60/73] Add podverse_queue and podverse_workers to docker compose --- .gitignore | 1 + .vscode/terminals.json.example | 6 ++++ Makefile | 6 ++++ database/combined/init_database.sql | 6 ++-- .../0001_init_podcasting_20_database.sql | 6 ++-- docker-compose/local/docker-compose.yml | 33 +++++++++++++++++++ yarn.lock | 4 +++ 7 files changed, 54 insertions(+), 8 deletions(-) create mode 100644 yarn.lock diff --git a/.gitignore b/.gitignore index 2c4db88..80b09ba 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ truffle.log config/podverse-api-local.env config/podverse-db-local.env config/podverse-web-local.env +config/podverse-workers-local.env config/podverse-db-sandbox.env diff --git a/.vscode/terminals.json.example b/.vscode/terminals.json.example index b17d7a3..9d18418 100644 --- a/.vscode/terminals.json.example +++ b/.vscode/terminals.json.example @@ -37,6 +37,12 @@ "cwd": "~/repos/podverse-parser", "open": true }, + { + "name": "Podverse Queue", + "description": "podverse-queue", + "cwd": "~/repos/podverse-queue", + "open": true + }, { "name": "Podverse RN", "description": "podverse-rn", diff --git a/Makefile b/Makefile index 8f7deca..0449b59 100644 --- a/Makefile +++ b/Makefile @@ -40,6 +40,12 @@ local_nginx_proxy: local_up_db: docker-compose -f docker-compose/local/docker-compose.yml up podverse_db -d +.PHONY: local_up_all +local_up_all: + docker-compose -f docker-compose/local/docker-compose.yml up podverse_db -d + docker-compose -f docker-compose/local/docker-compose.yml up podverse_queue -d + docker-compose -f docker-compose/local/docker-compose.yml up podverse_workers -d + .PHONY: local_down local_down: docker-compose -f docker-compose/local/docker-compose.yml down diff --git a/database/combined/init_database.sql b/database/combined/init_database.sql index 43a2e26..4a55c63 100644 --- a/database/combined/init_database.sql +++ b/database/combined/init_database.sql @@ -149,8 +149,7 @@ CREATE TABLE feed_log ( feed_id INTEGER NOT NULL REFERENCES feed(id) ON DELETE CASCADE, last_http_status INTEGER, last_good_http_status_time server_time, - last_parse_time server_time, - last_update_time server_time, + last_finished_parse_time server_time, parse_errors INTEGER DEFAULT 0 ); @@ -510,8 +509,7 @@ CREATE TABLE item_chapters_feed_log ( item_chapters_feed_id INTEGER NOT NULL REFERENCES item_chapters_feed(id) ON DELETE CASCADE, last_http_status INTEGER, last_good_http_status_time server_time, - last_parse_time server_time, - last_update_time server_time, + last_finished_parse_time server_time, parse_errors INTEGER DEFAULT 0 ); diff --git a/database/migrations/0001_init_podcasting_20_database.sql b/database/migrations/0001_init_podcasting_20_database.sql index f2f1b1e..a0573f5 100644 --- a/database/migrations/0001_init_podcasting_20_database.sql +++ b/database/migrations/0001_init_podcasting_20_database.sql @@ -111,8 +111,7 @@ CREATE TABLE feed_log ( feed_id INTEGER NOT NULL REFERENCES feed(id) ON DELETE CASCADE, last_http_status INTEGER, last_good_http_status_time server_time, - last_parse_time server_time, - last_update_time server_time, + last_finished_parse_time server_time, parse_errors INTEGER DEFAULT 0 ); @@ -472,8 +471,7 @@ CREATE TABLE item_chapters_feed_log ( item_chapters_feed_id INTEGER NOT NULL REFERENCES item_chapters_feed(id) ON DELETE CASCADE, last_http_status INTEGER, last_good_http_status_time server_time, - last_parse_time server_time, - last_update_time server_time, + last_finished_parse_time server_time, parse_errors INTEGER DEFAULT 0 ); diff --git a/docker-compose/local/docker-compose.yml b/docker-compose/local/docker-compose.yml index c4ba2b9..966bf00 100644 --- a/docker-compose/local/docker-compose.yml +++ b/docker-compose/local/docker-compose.yml @@ -2,6 +2,7 @@ version: "3.9" volumes: vhost: + rabbitmq_data: services: podverse_db: @@ -35,3 +36,35 @@ services: options: max-file: '1' max-size: '50m' + + podverse_queue: + image: rabbitmq:3-management + container_name: podverse_queue_local + ports: + - '5672:5672' + - '15672:15672' + env_file: + - ../../config/podverse-queue-local.env + restart: always + shm_size: 1gb + logging: + driver: 'json-file' + options: + max-file: '1' + max-size: '50m' + volumes: + - rabbitmq_data:/var/lib/rabbitmq + + podverse_workers: + image: podverse-workers:latest + container_name: podverse_workers_local + env_file: + - ../../config/podverse-workers-local.env + depends_on: + - podverse_db + shm_size: 1gb + logging: + driver: 'json-file' + options: + max-file: '1' + max-size: '50m' diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..fb57ccd --- /dev/null +++ b/yarn.lock @@ -0,0 +1,4 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + From 908d3d75038934235c3cc0a25c78d4f40aced848 Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Fri, 6 Sep 2024 20:21:36 -0500 Subject: [PATCH 61/73] Rename podverse_queue to podverse_amqp --- .gitignore | 1 + docker-compose/local/docker-compose.yml | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 80b09ba..d366185 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ truffle.log .vscode/terminals.json +config/podverse-amqp-local.env config/podverse-api-local.env config/podverse-db-local.env config/podverse-web-local.env diff --git a/docker-compose/local/docker-compose.yml b/docker-compose/local/docker-compose.yml index 966bf00..2850f4f 100644 --- a/docker-compose/local/docker-compose.yml +++ b/docker-compose/local/docker-compose.yml @@ -37,14 +37,14 @@ services: max-file: '1' max-size: '50m' - podverse_queue: + podverse_amqp: image: rabbitmq:3-management - container_name: podverse_queue_local + container_name: podverse_amqp_local ports: - '5672:5672' - '15672:15672' env_file: - - ../../config/podverse-queue-local.env + - ../../config/podverse-amqp-local.env restart: always shm_size: 1gb logging: From a540f552b81f877957cc7d797c3ea40022725812 Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Fri, 6 Sep 2024 20:32:04 -0500 Subject: [PATCH 62/73] Remove podverse_workers from makefile --- Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/Makefile b/Makefile index 0449b59..79ec755 100644 --- a/Makefile +++ b/Makefile @@ -44,7 +44,6 @@ local_up_db: local_up_all: docker-compose -f docker-compose/local/docker-compose.yml up podverse_db -d docker-compose -f docker-compose/local/docker-compose.yml up podverse_queue -d - docker-compose -f docker-compose/local/docker-compose.yml up podverse_workers -d .PHONY: local_down local_down: From a38ae57298a346d8820b08d81b06bcb5e0c5c582 Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Fri, 6 Sep 2024 20:33:06 -0500 Subject: [PATCH 63/73] Change podverse_queue to podverse_amqp --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 79ec755..d6db861 100644 --- a/Makefile +++ b/Makefile @@ -43,7 +43,7 @@ local_up_db: .PHONY: local_up_all local_up_all: docker-compose -f docker-compose/local/docker-compose.yml up podverse_db -d - docker-compose -f docker-compose/local/docker-compose.yml up podverse_queue -d + docker-compose -f docker-compose/local/docker-compose.yml up podverse_amqp -d .PHONY: local_down local_down: From 4b51c3e1d0dc33a0641f898243418c42f485a26c Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Fri, 6 Sep 2024 20:50:40 -0500 Subject: [PATCH 64/73] Add podverse_network to docker-compose file --- docker-compose/local/docker-compose.yml | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/docker-compose/local/docker-compose.yml b/docker-compose/local/docker-compose.yml index 2850f4f..c2c6fe5 100644 --- a/docker-compose/local/docker-compose.yml +++ b/docker-compose/local/docker-compose.yml @@ -4,6 +4,9 @@ volumes: vhost: rabbitmq_data: +networks: + podverse_network: + services: podverse_db: image: postgres:16.3 @@ -12,6 +15,8 @@ services: - ../../config/podverse-db-local.env ports: - '5432:5432' + networks: + - podverse_network command: > postgres -c max_connections=200 -c superuser_reserved_connections=20 @@ -40,11 +45,13 @@ services: podverse_amqp: image: rabbitmq:3-management container_name: podverse_amqp_local + env_file: + - ../../config/podverse-amqp-local.env ports: - '5672:5672' - '15672:15672' - env_file: - - ../../config/podverse-amqp-local.env + networks: + - podverse_network restart: always shm_size: 1gb logging: @@ -60,6 +67,8 @@ services: container_name: podverse_workers_local env_file: - ../../config/podverse-workers-local.env + networks: + - podverse_network depends_on: - podverse_db shm_size: 1gb From 9e9d519b02a77855b26fdf4d5fe82821bad63e12 Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Fri, 6 Sep 2024 23:30:47 -0500 Subject: [PATCH 65/73] Add podverse_workers_debug --- docker-compose/local/docker-compose.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/docker-compose/local/docker-compose.yml b/docker-compose/local/docker-compose.yml index c2c6fe5..fe91ce5 100644 --- a/docker-compose/local/docker-compose.yml +++ b/docker-compose/local/docker-compose.yml @@ -71,6 +71,26 @@ services: - podverse_network depends_on: - podverse_db + - podverse_amqp + shm_size: 1gb + logging: + driver: 'json-file' + options: + max-file: '1' + max-size: '50m' + + podverse_workers_debug: + image: podverse-workers:latest + container_name: podverse_workers_debug + env_file: + - ../../config/podverse-workers-local.env + networks: + - podverse_network + depends_on: + - podverse_db + - podverse_amqp + volumes: + - /home/mitch/logs/podverse-workers:/var/logs/pv-workers shm_size: 1gb logging: driver: 'json-file' From d206bac21a7563e8e13e498682e9b4bae3bc4697 Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Sat, 7 Sep 2024 19:09:12 -0500 Subject: [PATCH 66/73] Add npm-link-modules.sh and add example env files --- .gitignore | 10 ++-- Makefile | 28 +++++----- config/podverse-amqp.env.example | 5 ++ ...al.env.example => podverse-db.env.example} | 4 +- config/podverse-workers.env.example | 0 docker-compose/local/docker-compose.yml | 14 ++--- npm-link-modules.sh | 52 +++++++++++++++++++ 7 files changed, 85 insertions(+), 28 deletions(-) create mode 100644 config/podverse-amqp.env.example rename config/{podverse-db-local.env.example => podverse-db.env.example} (52%) create mode 100644 config/podverse-workers.env.example create mode 100755 npm-link-modules.sh diff --git a/.gitignore b/.gitignore index d366185..3771aea 100644 --- a/.gitignore +++ b/.gitignore @@ -6,11 +6,11 @@ truffle.log .vscode/terminals.json -config/podverse-amqp-local.env -config/podverse-api-local.env -config/podverse-db-local.env -config/podverse-web-local.env -config/podverse-workers-local.env +config/podverse-amqp.env +config/podverse-api.env +config/podverse-db.env +config/podverse-web.env +config/podverse-workers.env config/podverse-db-sandbox.env diff --git a/Makefile b/Makefile index d6db861..68a320d 100644 --- a/Makefile +++ b/Makefile @@ -14,21 +14,21 @@ endif say_hello: @echo "Hello Podverse" -.PHONY: local_validate_init -local_validate_init: config/podverse-api-local.env config/podverse-db-local.env +.PHONY: validate_init +validate_init: config/podverse-api.env config/podverse-db.env -config/podverse-api-local.env: +config/podverse-api.env: @echo "Missing: $@" @echo "Copying from example file" cp ./$@.example ./$@ -config/podverse-db-local.env: +config/podverse-db.env: @echo "Missing: $@" @echo "Copying from example file" cp ./$@.example ./$@ -.PHONY: local_nginx_proxy -local_nginx_proxy: +.PHONY: nginx_proxy +nginx_proxy: @echo 'Generate new cert' test -d proxy/local/certs || mkdir -p proxy/local/certs cd proxy/local/certs && openssl genrsa -out podverse-server.key 4096 @@ -36,17 +36,17 @@ local_nginx_proxy: cd proxy/local/certs && openssl req -new -sha256 -key podverse-server.key -subj "/C=US/ST=Jefferson/L=Grand/O=EXA/OU=MPL/CN=podverse.local" -reqexts SAN -config <(cat /etc/ssl/openssl.cnf <(printf "[SAN]\nsubjectAltName=DNS:podverse.local,DNS:www.podverse.local,DNS:api.podverse.local")) -out podverse-server.csr cd proxy/local/certs && openssl x509 -req -days 365 -in podverse-server.csr -signkey podverse-server.key -out podverse-server.crt -.PHONY: local_up_db -local_up_db: +.PHONY: up_db +up_db: docker-compose -f docker-compose/local/docker-compose.yml up podverse_db -d -.PHONY: local_up_all -local_up_all: +.PHONY: up_all +up_all: docker-compose -f docker-compose/local/docker-compose.yml up podverse_db -d docker-compose -f docker-compose/local/docker-compose.yml up podverse_amqp -d -.PHONY: local_down -local_down: +.PHONY: down +down: docker-compose -f docker-compose/local/docker-compose.yml down proxy/local/certs: @@ -64,6 +64,6 @@ proxy/local/certs/podverse-server.csr: proxy/local/certs/podverse-server.key proxy/local/certs/podverse-server.crt: proxy/local/certs/podverse-server.csr openssl x509 -req -days 365 -in $< -signkey proxy/local/certs/podverse-server.key -out $@ -.PHONY: local_nginx_proxy_cert -local_nginx_proxy_cert: proxy/local/certs proxy/local/certs/podverse-server.key proxy/local/certs/podverse-server.key.insecure proxy/local/certs/podverse-server.csr proxy/local/certs/podverse-server.crt +.PHONY: nginx_proxy_cert +nginx_proxy_cert: proxy/local/certs proxy/local/certs/podverse-server.key proxy/local/certs/podverse-server.key.insecure proxy/local/certs/podverse-server.csr proxy/local/certs/podverse-server.crt @echo 'Generate new cert' diff --git a/config/podverse-amqp.env.example b/config/podverse-amqp.env.example new file mode 100644 index 0000000..507eb70 --- /dev/null +++ b/config/podverse-amqp.env.example @@ -0,0 +1,5 @@ +RABBITMQ_HOST=podverse_amqp +RABBITMQ_PORT=5672 +RABBITMQ_DEFAULT_USER= +RABBITMQ_DEFAULT_PASS= +RABBITMQ_VHOST=/ diff --git a/config/podverse-db-local.env.example b/config/podverse-db.env.example similarity index 52% rename from config/podverse-db-local.env.example rename to config/podverse-db.env.example index bcebe0b..dc8e99e 100644 --- a/config/podverse-db-local.env.example +++ b/config/podverse-db.env.example @@ -1,4 +1,4 @@ -POSTGRES_USER=user -POSTGRES_PASSWORD=mysecretpw +POSTGRES_USER= +POSTGRES_PASSWORD= POSTGRES_DB=db PGDATA=/var/lib/postgresql/data/pgdata diff --git a/config/podverse-workers.env.example b/config/podverse-workers.env.example new file mode 100644 index 0000000..e69de29 diff --git a/docker-compose/local/docker-compose.yml b/docker-compose/local/docker-compose.yml index fe91ce5..58fed7c 100644 --- a/docker-compose/local/docker-compose.yml +++ b/docker-compose/local/docker-compose.yml @@ -10,9 +10,9 @@ networks: services: podverse_db: image: postgres:16.3 - container_name: podverse_db_local + container_name: podverse_db env_file: - - ../../config/podverse-db-local.env + - ../../config/podverse-db.env ports: - '5432:5432' networks: @@ -44,9 +44,9 @@ services: podverse_amqp: image: rabbitmq:3-management - container_name: podverse_amqp_local + container_name: podverse_amqp env_file: - - ../../config/podverse-amqp-local.env + - ../../config/podverse-amqp.env ports: - '5672:5672' - '15672:15672' @@ -64,9 +64,9 @@ services: podverse_workers: image: podverse-workers:latest - container_name: podverse_workers_local + container_name: podverse_workers env_file: - - ../../config/podverse-workers-local.env + - ../../config/podverse-workers.env networks: - podverse_network depends_on: @@ -83,7 +83,7 @@ services: image: podverse-workers:latest container_name: podverse_workers_debug env_file: - - ../../config/podverse-workers-local.env + - ../../config/podverse-workers.env networks: - podverse_network depends_on: diff --git a/npm-link-modules.sh b/npm-link-modules.sh new file mode 100755 index 0000000..c3330da --- /dev/null +++ b/npm-link-modules.sh @@ -0,0 +1,52 @@ +#!/bin/bash + +cd ../podverse-api +npm install + +cd ../podverse-external-services +npm install +npm link + +cd ../podverse-helpers +npm install +npm link + +cd ../podverse-orm +npm install +npm link + +cd ../podverse-parser +npm install +npm link + +cd ../podverse-queue +npm install +npm link + +cd ../podverse-workers +npm install + +cd ../podverse-api +npm link podverse-helpers +npm link podverse-orm +npm link podverse-parser + +cd ../podverse-external-services +npm link podverse-helpers + +cd ../podverse-orm +npm link podverse-helpers + +cd ../podverse-parser +npm link podverse-helpers +npm link podverse-orm + +cd ../podverse-queue +npm link podverse-external-services +npm link podverse-helpers +npm link podverse-orm +npm link podverse-parser + +cd ../podverse-workers +npm link podverse-helpers +npm link podverse-queue From f5876b5afd550bd50bcb27f09d3c7b454431a3eb Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Sun, 8 Sep 2024 16:55:45 -0500 Subject: [PATCH 67/73] Add dev/local-dev-setup.md; Attach init_database.sql file to podverse_db container --- dev/local-dev-setup.md | 53 +++++++++++++++++++ .../npm-link-modules.sh | 0 docker-compose/local/docker-compose.yml | 2 + 3 files changed, 55 insertions(+) create mode 100644 dev/local-dev-setup.md rename npm-link-modules.sh => dev/npm-link-modules.sh (100%) diff --git a/dev/local-dev-setup.md b/dev/local-dev-setup.md new file mode 100644 index 0000000..8f2680a --- /dev/null +++ b/dev/local-dev-setup.md @@ -0,0 +1,53 @@ +# Local Dev Setup + +Podverse uses many modules that are maintained in separate repos. This guide is intended to help you use shortcuts for an easier development workflow. + +## Summary + +- Setup environment variables for Docker services and local apps. +- Run the required Docker services. +- Initialize the database schema. +- Install and link all NPM dependencies. +- Run (build + hot reload) all Podverse modules in separate terminals. + +## Environment Variables + +Before running a Podverse Docker service, you will need to create an enviroment variable file for it within the `podverse-ops/config` directory. + +Duplicate each of the `.env.example` files found within `podverse-ops/config` and add the corresponding values. + +The Podverse repos that run locally (the ones that don't simply need to build, but need to run) will need their own `.env` file within their project directory for local development purposes. For example, for local dev, you will need a corresponding `podverse-api/.env` file, and a `podverse-workers/.env` file. + +## Required Docker services + +The Podverse infrastructure requires 2 Docker services: +- `podverse_db` - a Postgres database +- `podverse_amqp` - a RabbitMQ instance (AMQP queue service) + +You will need Docker installed locally. To start these containers in the background, from the root of `podverse-ops`, run the following command (using either `docker-compose` or `docker compose`): + +``` +docker-compose -f ./docker/docker-compose.yml up -d +``` + +## Initialize Database Schema + +When you start a clean instance of `podverse_db`, you will need to initialize the database schema. + +To initialize the database, run the SQL found in the `podverse-ops/database/init_database.sql` file. Execute the following command from the root of the `podverse-ops` repo: + +``` +docker exec -i podverse_db psql -U user -d postgres -f /opt/database/combined/init_database.sql +``` + +Note: the `user` and `postgres` value may need to change depending on your environment variables. + +## Install and link all dependencies + +For a convenient local dev workflow, you can clone all of the Podverse repos on your machine within the same directory, and then run the `podverse-ops/dev/npm-link-modules.sh` script from the root of the `podverse-ops` directory. This will handle 1) installing all the `node_modules` for those repos, and 2) `npm link`-ing the required podverse dependencies for each individual module. + +## Open and run all repos in separate terminals + +If you would like to use one command to run all of the Podverse modules in separate terminals, you can use the VS Code extension Terminals Manager. + +To make it work, duplicate the `podverse-ops/.vscode/terminals.json.example` file, rename it to `terminals.json`, and update the paths in the file to point to where you have the repos cloned locally. Then, with the `terminals.json` file open in VS Code, open the Command Palette, and select `Terminals: Run`. This will open a terminal in each of the (actively developed) Podverse modules, with the `npm run dev:watch` command running. diff --git a/npm-link-modules.sh b/dev/npm-link-modules.sh similarity index 100% rename from npm-link-modules.sh rename to dev/npm-link-modules.sh diff --git a/docker-compose/local/docker-compose.yml b/docker-compose/local/docker-compose.yml index 58fed7c..e515c0d 100644 --- a/docker-compose/local/docker-compose.yml +++ b/docker-compose/local/docker-compose.yml @@ -17,6 +17,8 @@ services: - '5432:5432' networks: - podverse_network + volumes: + - ../../database/combined/init_database.sql:/opt/database/combined/init_database.sql command: > postgres -c max_connections=200 -c superuser_reserved_connections=20 From c73a12916e2c5e62ca7f887296226bfc37827361 Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Sun, 8 Sep 2024 23:28:47 -0500 Subject: [PATCH 68/73] Update env examples; update npm-link-modules.sh; update docker-compose.yml --- .vscode/terminals.json.example | 34 +++++++++---------- config/podverse-db.env.example | 6 ++-- config/podverse-workers.env.example | 27 +++++++++++++++ dev/deploying.md | 4 +++ dev/npm-link-modules.sh | 24 +++++++++++++ docker-compose/{local => }/docker-compose.yml | 10 +++--- 6 files changed, 80 insertions(+), 25 deletions(-) create mode 100644 dev/deploying.md rename docker-compose/{local => }/docker-compose.yml (89%) diff --git a/.vscode/terminals.json.example b/.vscode/terminals.json.example index 9d18418..8862c99 100644 --- a/.vscode/terminals.json.example +++ b/.vscode/terminals.json.example @@ -5,13 +5,15 @@ "name": "Podverse API", "description": "podverse-api", "cwd": "~/repos/podverse-api", - "open": true + "open": true, + "command": "npm run dev:watch" }, { "name": "Podverse External Services", "description": "podverse-external-services", "cwd": "~/repos/podverse-external-services", - "open": true + "open": true, + "command": "npm run build:watch" }, { "name": "Podverse F-Droid", @@ -19,6 +21,13 @@ "cwd": "~/repos/podverse-fdroid", "open": true }, + { + "name": "Podverse Helpers", + "description": "podverse-helpers", + "cwd": "~/repos/podverse-helpers", + "open": true, + "command": "npm run build:watch" + }, { "name": "Podverse Ops", "description": "podverse-ops", @@ -29,19 +38,22 @@ "name": "Podverse ORM", "description": "podverse-orm", "cwd": "~/repos/podverse-orm", - "open": true + "open": true, + "command": "npm run build:watch" }, { "name": "Podverse Parser", "description": "podverse-parser", "cwd": "~/repos/podverse-parser", - "open": true + "open": true, + "command": "npm run build:watch" }, { "name": "Podverse Queue", "description": "podverse-queue", "cwd": "~/repos/podverse-queue", - "open": true + "open": true, + "command": "npm run build:watch" }, { "name": "Podverse RN", @@ -49,18 +61,6 @@ "cwd": "~/repos/podverse-rn", "open": true }, - { - "name": "Podverse Serverless", - "description": "podverse-serverless", - "cwd": "~/repos/podverse-serverless", - "open": true - }, - { - "name": "Podverse Shared", - "description": "podverse-shared", - "cwd": "~/repos/podverse-shared", - "open": true - }, { "name": "Podverse Web", "description": "podverse-web", diff --git a/config/podverse-db.env.example b/config/podverse-db.env.example index dc8e99e..001c4f8 100644 --- a/config/podverse-db.env.example +++ b/config/podverse-db.env.example @@ -1,4 +1,4 @@ -POSTGRES_USER= -POSTGRES_PASSWORD= -POSTGRES_DB=db +POSTGRES_USER=user +POSTGRES_PASSWORD=mysecretpw +POSTGRES_DB=postgres PGDATA=/var/lib/postgresql/data/pgdata diff --git a/config/podverse-workers.env.example b/config/podverse-workers.env.example index e69de29..a15fce5 100644 --- a/config/podverse-workers.env.example +++ b/config/podverse-workers.env.example @@ -0,0 +1,27 @@ +NODE_ENV=production + +RABBITMQ_HOST=podverse_queue +RABBITMQ_PORT=5672 +RABBITMQ_USERNAME=user +RABBITMQ_PASSWORD=mysecretpw +RABBITMQ_VHOST=/ + +RABBITMQ_QUEUE_NAMES=rss-slow,rss-fast,rss-live + +##### +##### Postgres +##### + +# LOCAL +DB_HOST=podverse_db +DB_PORT=5432 +DB_USERNAME=user +DB_PASSWORD=mysecretpw +DB_DATABASE=postgres +DB_SSL_CONNECTION= + +LOG_LEVEL=info + +PODCAST_INDEX_BASE_URL=https://api.podcastindex.org/api/1.0 +PODCAST_INDEX_AUTH_KEY=SD5ASUREEUADPX36SX7P +PODCAST_INDEX_SECRET_KEY=VYCLYE43jpyPsgE72sdEJ^MtPSGnPKtdZsuzPATX diff --git a/dev/deploying.md b/dev/deploying.md new file mode 100644 index 0000000..08b6c47 --- /dev/null +++ b/dev/deploying.md @@ -0,0 +1,4 @@ +# Deploying + +TODO: + diff --git a/dev/npm-link-modules.sh b/dev/npm-link-modules.sh index c3330da..b365367 100755 --- a/dev/npm-link-modules.sh +++ b/dev/npm-link-modules.sh @@ -1,52 +1,76 @@ #!/bin/bash +echo "Clearing npm cache..." +npm cache clean --force + +echo "Installing podverse-api dependencies..." cd ../podverse-api +rm -rf node_modules npm install +echo "Installing podverse-external-services dependencies..." cd ../podverse-external-services +rm -rf node_modules npm install npm link +echo "Installing podverse-helpers dependencies..." cd ../podverse-helpers +rm -rf node_modules npm install npm link +echo "Installing podverse-orm dependencies..." cd ../podverse-orm +rm -rf node_modules npm install npm link +echo "Installing podverse-parser dependencies..." cd ../podverse-parser +rm -rf node_modules npm install npm link +echo "Installing podverse-queue dependencies..." cd ../podverse-queue +rm -rf node_modules npm install npm link +echo "Installing podverse-workers dependencies..." cd ../podverse-workers +rm -rf node_modules npm install +echo "Linking podverse-api dependencies..." cd ../podverse-api npm link podverse-helpers npm link podverse-orm npm link podverse-parser +echo "Linking podverse-external-services dependencies..." cd ../podverse-external-services npm link podverse-helpers +echo "Linking podverse-orm dependencies..." cd ../podverse-orm npm link podverse-helpers +echo "Linking podverse-parser dependencies..." cd ../podverse-parser npm link podverse-helpers npm link podverse-orm +echo "Linking podverse-queue dependencies..." cd ../podverse-queue npm link podverse-external-services npm link podverse-helpers npm link podverse-orm npm link podverse-parser +echo "Linking podverse-workers dependencies..." cd ../podverse-workers npm link podverse-helpers +npm link podverse-orm npm link podverse-queue diff --git a/docker-compose/local/docker-compose.yml b/docker-compose/docker-compose.yml similarity index 89% rename from docker-compose/local/docker-compose.yml rename to docker-compose/docker-compose.yml index e515c0d..f4c54da 100644 --- a/docker-compose/local/docker-compose.yml +++ b/docker-compose/docker-compose.yml @@ -12,13 +12,13 @@ services: image: postgres:16.3 container_name: podverse_db env_file: - - ../../config/podverse-db.env + - ../config/podverse-db.env ports: - '5432:5432' networks: - podverse_network volumes: - - ../../database/combined/init_database.sql:/opt/database/combined/init_database.sql + - ../database/combined/init_database.sql:/opt/database/combined/init_database.sql command: > postgres -c max_connections=200 -c superuser_reserved_connections=20 @@ -48,7 +48,7 @@ services: image: rabbitmq:3-management container_name: podverse_amqp env_file: - - ../../config/podverse-amqp.env + - ../config/podverse-amqp.env ports: - '5672:5672' - '15672:15672' @@ -68,7 +68,7 @@ services: image: podverse-workers:latest container_name: podverse_workers env_file: - - ../../config/podverse-workers.env + - ../config/podverse-workers.env networks: - podverse_network depends_on: @@ -85,7 +85,7 @@ services: image: podverse-workers:latest container_name: podverse_workers_debug env_file: - - ../../config/podverse-workers.env + - ../config/podverse-workers.env networks: - podverse_network depends_on: From 0f90c1c85e3a2a5a88829ce59e025448d08d5ecc Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Mon, 9 Sep 2024 05:40:58 -0500 Subject: [PATCH 69/73] Update npm-link-modules.sh --- dev/npm-link-modules.sh | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/dev/npm-link-modules.sh b/dev/npm-link-modules.sh index b365367..7576807 100755 --- a/dev/npm-link-modules.sh +++ b/dev/npm-link-modules.sh @@ -12,37 +12,57 @@ echo "Installing podverse-external-services dependencies..." cd ../podverse-external-services rm -rf node_modules npm install -npm link + echo "Installing podverse-helpers dependencies..." cd ../podverse-helpers rm -rf node_modules npm install -npm link echo "Installing podverse-orm dependencies..." cd ../podverse-orm rm -rf node_modules npm install -npm link echo "Installing podverse-parser dependencies..." cd ../podverse-parser rm -rf node_modules npm install -npm link echo "Installing podverse-queue dependencies..." cd ../podverse-queue rm -rf node_modules npm install -npm link echo "Installing podverse-workers dependencies..." cd ../podverse-workers rm -rf node_modules npm install + + +echo "Linking podverse-external-services dependency..." +cd ../podverse-external-services +npm link + +echo "Linking podverse-helpers dependency..." +cd ../podverse-helpers +npm link + +echo "Linking podverse-orm dependency..." +cd ../podverse-orm +npm link + +echo "Linking podverse-parser dependency..." +cd ../podverse-parser +npm link + +echo "Linking podverse-queue dependency..." +cd ../podverse-queue +npm link + + + echo "Linking podverse-api dependencies..." cd ../podverse-api npm link podverse-helpers @@ -73,4 +93,5 @@ echo "Linking podverse-workers dependencies..." cd ../podverse-workers npm link podverse-helpers npm link podverse-orm +npm link podverse-parser npm link podverse-queue From dc82f5a128b08e3ab84cc530b1046c38ff70fc44 Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Thu, 19 Sep 2024 03:11:13 -0500 Subject: [PATCH 70/73] Add foreign key indexes --- config/podverse-workers.env.example | 5 +- database/combined/init_database.sql | 189 +++++++++++++++++- database/migrations/0000_init_helpers.sql | 1 + .../0001_init_podcasting_20_database.sql | 113 +++++++++++ database/migrations/0002_account.sql | 15 ++ database/migrations/0003_clip.sql | 4 + database/migrations/0004_playlist.sql | 16 ++ database/migrations/0005_queue.sql | 15 ++ .../0006_account_following_tables.sql | 11 + database/migrations/0007_notifications.sql | 7 +- .../0008_purchases_paypal_apple_google.sql | 5 + .../0009_membership_claim_token.sql | 2 + 12 files changed, 379 insertions(+), 4 deletions(-) diff --git a/config/podverse-workers.env.example b/config/podverse-workers.env.example index a15fce5..1778d0f 100644 --- a/config/podverse-workers.env.example +++ b/config/podverse-workers.env.example @@ -21,7 +21,8 @@ DB_DATABASE=postgres DB_SSL_CONNECTION= LOG_LEVEL=info +LOG_TIMER= PODCAST_INDEX_BASE_URL=https://api.podcastindex.org/api/1.0 -PODCAST_INDEX_AUTH_KEY=SD5ASUREEUADPX36SX7P -PODCAST_INDEX_SECRET_KEY=VYCLYE43jpyPsgE72sdEJ^MtPSGnPKtdZsuzPATX +PODCAST_INDEX_AUTH_KEY= +PODCAST_INDEX_SECRET_KEY= diff --git a/database/combined/init_database.sql b/database/combined/init_database.sql index 4a55c63..9782291 100644 --- a/database/combined/init_database.sql +++ b/database/combined/init_database.sql @@ -12,6 +12,7 @@ CREATE DOMAIN varchar_normal AS VARCHAR(255); CREATE DOMAIN varchar_long AS VARCHAR(2500); CREATE DOMAIN varchar_email AS VARCHAR(255) CHECK (VALUE ~ '^.+@.+\..+$'); +CREATE DOMAIN varchar_fcm_token AS VARCHAR(255); CREATE DOMAIN varchar_fqdn AS VARCHAR(253); CREATE DOMAIN varchar_guid AS VARCHAR(36); CREATE DOMAIN varchar_md5 AS VARCHAR(32); @@ -139,6 +140,8 @@ CREATE TABLE feed ( updated_at server_time_with_default ); +CREATE INDEX idx_feed_feed_flag_status_id ON feed(feed_flag_status_id); + CREATE TRIGGER set_updated_at_feed BEFORE UPDATE ON feed FOR EACH ROW @@ -153,6 +156,8 @@ CREATE TABLE feed_log ( parse_errors INTEGER DEFAULT 0 ); +CREATE INDEX idx_feed_log_feed_id ON feed_log(feed_id); + --** CHANNEL -- <channel> @@ -179,6 +184,8 @@ CREATE TABLE channel ( CREATE UNIQUE INDEX channel_podcast_guid_unique ON channel(podcast_guid) WHERE podcast_guid IS NOT NULL; CREATE UNIQUE INDEX channel_slug ON channel(slug) WHERE slug IS NOT NULL; +CREATE INDEX idx_channel_feed_id ON channel(feed_id); +CREATE INDEX idx_channel_medium_id ON channel(medium_id); --** CHANNEL > ABOUT > ITUNES TYPE @@ -205,6 +212,9 @@ CREATE TABLE channel_about ( website_link_url varchar_url -- <link> ); +CREATE INDEX idx_channel_about_channel_id ON channel_about(channel_id); +CREATE INDEX idx_channel_about_itunes_type_id ON channel_about(itunes_type_id); + --** CHANNEL > CATEGORY CREATE TABLE channel_category ( @@ -213,6 +223,9 @@ CREATE TABLE channel_category ( parent_id INTEGER REFERENCES channel_category(id) ON DELETE CASCADE ); +CREATE INDEX idx_channel_category_channel_id ON channel_category(channel_id); +CREATE INDEX idx_channel_category_parent_id ON channel_category(parent_id); + --** CHANNEL > CHAT -- <channel> -> <podcast:chat> @@ -225,6 +238,8 @@ CREATE TABLE channel_chat ( space varchar_normal ); +CREATE INDEX idx_channel_chat_channel_id ON channel_chat(channel_id); + --** CHANNEL > DESCRIPTION -- <channel> -> <description> AND possibly other tags that contain a description @@ -235,6 +250,8 @@ CREATE TABLE channel_description ( value varchar_long NOT NULL ); +CREATE INDEX idx_channel_description_channel_id ON channel_description(channel_id); + --** CHANNEL > FUNDING -- <channel> -> <podcast:funding> @@ -245,6 +262,8 @@ CREATE TABLE channel_funding ( title varchar_normal ); +CREATE INDEX idx_channel_funding_channel_id ON channel_funding(channel_id); + --** CHANNEL > IMAGE -- <channel> -> <podcast:image> AND all other image tags in the rss feed @@ -260,6 +279,8 @@ CREATE TABLE channel_image ( is_resized BOOLEAN DEFAULT FALSE ); +CREATE INDEX idx_channel_image_channel_id ON channel_image(channel_id); + --** CHANNEL > INTERNAL SETTINGS CREATE TABLE channel_internal_settings ( @@ -270,6 +291,8 @@ CREATE TABLE channel_internal_settings ( embed_approved_media_url_paths TEXT ); +CREATE INDEX idx_channel_internal_settings_channel_id ON channel_internal_settings(channel_id); + --** CHANNEL > LICENSE -- <channel> -> <podcast:license> @@ -281,6 +304,8 @@ CREATE TABLE channel_license ( url varchar_url ); +CREATE INDEX idx_channel_license_channel_id ON channel_license(channel_id); + --** CHANNEL > LOCATION -- <channel> -> <podcast:location> @@ -293,6 +318,8 @@ CREATE TABLE channel_location ( name varchar_normal ); +CREATE INDEX idx_channel_location_channel_id ON channel_location(channel_id); + --** CHANNEL > PERSON -- <channel> -> <podcast:person> @@ -306,6 +333,8 @@ CREATE TABLE channel_person ( href varchar_url ); +CREATE INDEX idx_channel_person_channel_id ON channel_person(channel_id); + --** CHANNEL > PODROLL -- <channel> -> <podcast:podroll> @@ -314,6 +343,8 @@ CREATE TABLE channel_podroll ( channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE ); +CREATE INDEX idx_channel_podroll_channel_id ON channel_podroll(channel_id); + --** CHANNEL > PODROLL > REMOTE ITEM -- <channel> -> <podcast:podroll> --> <podcast:remoteItem> @@ -327,6 +358,9 @@ CREATE TABLE channel_podroll_remote_item ( medium_id INTEGER REFERENCES medium(id) ); +CREATE INDEX idx_channel_podroll_remote_item_channel_podroll_id ON channel_podroll_remote_item(channel_podroll_id); +CREATE INDEX idx_channel_podroll_remote_item_medium_id ON channel_podroll_remote_item(medium_id); + --** CHANNEL > PUBLISHER -- <channel> -> <podcast:publisher> @@ -335,6 +369,8 @@ CREATE TABLE channel_publisher ( channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE ); +CREATE INDEX idx_channel_publisher_channel_id ON channel_publisher(channel_id); + --** CHANNEL > PUBLISHER > REMOTE ITEM -- <channel> -> <podcast:publisher> -> <podcast:remoteItem> @@ -348,6 +384,9 @@ CREATE TABLE channel_publisher_remote_item ( medium_id INTEGER REFERENCES medium(id) ); +CREATE INDEX idx_channel_publisher_remote_item_channel_publisher_id ON channel_publisher_remote_item(channel_publisher_id); +CREATE INDEX idx_channel_publisher_remote_item_medium_id ON channel_publisher_remote_item(medium_id); + --** CHANNEL > REMOTE ITEM -- Remote items at the channel level are only used when the <podcast:medium> for the channel @@ -364,6 +403,9 @@ CREATE TABLE channel_remote_item ( medium_id INTEGER REFERENCES medium(id) ); +CREATE INDEX idx_channel_remote_item_channel_id ON channel_remote_item(channel_id); +CREATE INDEX idx_channel_remote_item_medium_id ON channel_remote_item(medium_id); + --** CHANNEL > SEASON -- channels with seasons need to be rendered in client apps differently. @@ -382,6 +424,8 @@ CREATE TABLE channel_season ( name varchar_normal ); +CREATE INDEX idx_channel_season_channel_id ON channel_season(channel_id); + --** CHANNEL > SOCIAL INTERACT -- <channel> -> <podcast:socialInteract> @@ -395,6 +439,8 @@ CREATE TABLE channel_social_interact ( priority INTEGER ); +CREATE INDEX idx_channel_social_interact_channel_id ON channel_social_interact(channel_id); + --** CHANNEL > TRAILER -- <channel> -> <podcast:trailer> @@ -410,6 +456,9 @@ CREATE TABLE channel_trailer ( UNIQUE (channel_id, url) ); +CREATE INDEX idx_channel_trailer_channel_id ON channel_trailer(channel_id); +CREATE INDEX idx_channel_trailer_channel_season_id ON channel_trailer(channel_season_id); + --** CHANNEL > TXT -- <channel> -> <podcast:txt> @@ -420,6 +469,8 @@ CREATE TABLE channel_txt ( value varchar_long NOT NULL ); +CREATE INDEX idx_channel_txt_channel_id ON channel_txt(channel_id); + --** CHANNEL > VALUE -- <channel> -> <podcast:value> @@ -431,6 +482,8 @@ CREATE TABLE channel_value ( suggested FLOAT ); +CREATE INDEX idx_channel_value_channel_id ON channel_value(channel_id); + --** CHANNEL > VALUE > RECEIPIENT -- <channel> -> <podcast:value> -> <podcast:valueRecipient> @@ -446,6 +499,8 @@ CREATE TABLE channel_value_recipient ( fee BOOLEAN DEFAULT FALSE ); +CREATE INDEX idx_channel_value_recipient_channel_value_id ON channel_value_recipient(channel_value_id); + --** ITEM -- Technically the item table could be named channel_item, but it seems easier to understand as item. @@ -468,6 +523,7 @@ CREATE TABLE item ( ); CREATE UNIQUE INDEX item_slug ON item(slug) WHERE slug IS NOT NULL; +CREATE INDEX idx_item_channel_id ON item(channel_id); --** ITEM > ABOUT > ITUNES TYPE @@ -490,6 +546,9 @@ CREATE TABLE item_about ( item_itunes_episode_type_id INTEGER REFERENCES item_itunes_episode_type(id) -- <itunes:episodeType> ); +CREATE INDEX idx_item_about_item_id ON item_about(item_id); +CREATE INDEX idx_item_about_item_itunes_episode_type_id ON item_about(item_itunes_episode_type_id); + --** ITEM > CHAPTERS -- <item> -> <podcast:chapters> @@ -500,6 +559,8 @@ CREATE TABLE item_chapters_feed ( type varchar_short NOT NULL ); +CREATE INDEX idx_item_chapters_feed_item_id ON item_chapters_feed(item_id); + --** ITEM > CHAPTERS > LOG -- <item> -> <podcast:chapters> -> parsing logs @@ -513,6 +574,8 @@ CREATE TABLE item_chapters_feed_log ( parse_errors INTEGER DEFAULT 0 ); +CREATE INDEX idx_item_chapters_feed_log_item_chapters_feed_id ON item_chapters_feed_log(item_chapters_feed_id); + --** ITEM > CHAPTERS > CHAPTER -- -- <item> -> <podcast:chapters> -> chapter items correspond with jsonChapters.md example file @@ -528,6 +591,8 @@ CREATE TABLE item_chapter ( table_of_contents BOOLEAN DEFAULT TRUE ); +CREATE INDEX idx_item_chapter_item_chapters_feed_id ON item_chapter(item_chapters_feed_id); + --** ITEM > CHAPTER > LOCATION -- <item> -> <podcast:chapters> -> chapter items correspond with jsonChapters.md example file @@ -540,6 +605,8 @@ CREATE TABLE item_chapter_location ( name varchar_normal ); +CREATE INDEX idx_item_chapter_location_item_chapter_id ON item_chapter_location(item_chapter_id); + --** ITEM > CHAT -- <item> -> <podcast:chat> @@ -552,6 +619,8 @@ CREATE TABLE item_chat ( space varchar_normal ); +CREATE INDEX idx_item_chat_item_id ON item_chat(item_id); + --** ITEM > CONTENT LINK -- <item> -> <podcast:contentLink> @@ -562,6 +631,8 @@ CREATE TABLE item_content_link ( title varchar_normal ); +CREATE INDEX idx_item_content_link_item_id ON item_content_link(item_id); + --** ITEM > DESCRIPTION -- <item> -> <description> AND possibly other tags that contain a description @@ -572,6 +643,8 @@ CREATE TABLE item_description ( value varchar_long NOT NULL ); +CREATE INDEX idx_item_description_item_id ON item_description(item_id); + --** ITEM > ENCLOSURE (AKA ALTERNATE ENCLOSURE) -- NOTE: the older <enclosure> tag style is integrated into the item_enclosure table. @@ -591,6 +664,8 @@ CREATE TABLE item_enclosure ( item_enclosure_default BOOLEAN DEFAULT FALSE ); +CREATE INDEX idx_item_enclosure_item_id ON item_enclosure(item_id); + -- <item> -> <podcast:alternateEnclosure> -> <podcast:source> CREATE TABLE item_enclosure_source ( id SERIAL PRIMARY KEY, @@ -599,6 +674,8 @@ CREATE TABLE item_enclosure_source ( content_type varchar_short ); +CREATE INDEX idx_item_enclosure_source_item_id ON item_enclosure_source(item_enclosure_id); + -- <item> -> <podcast:alternateEnclosure> -> <podcast:integrity> CREATE TABLE item_enclosure_integrity ( id SERIAL PRIMARY KEY, @@ -607,6 +684,8 @@ CREATE TABLE item_enclosure_integrity ( value varchar_long NOT NULL ); +CREATE INDEX idx_item_enclosure_integrity_item_enclosure_id ON item_enclosure_integrity(item_enclosure_id); + --** ITEM > FUNDING -- <item> -> <podcast:funding> @@ -617,6 +696,8 @@ CREATE TABLE item_funding ( title varchar_normal ); +CREATE INDEX idx_item_funding_item_id ON item_funding(item_id); + --** ITEM > IMAGE -- <item> -> <podcast:image> AND all other image tags in the rss feed @@ -632,6 +713,8 @@ CREATE TABLE item_image ( is_resized BOOLEAN DEFAULT FALSE ); +CREATE INDEX idx_item_image_item_id ON item_image(item_id); + --** ITEM > LICENSE -- <item> -> <podcast:license> @@ -643,6 +726,8 @@ CREATE TABLE item_license ( url varchar_url ); +CREATE INDEX idx_item_license_item_id ON item_license(item_id); + --** ITEM > LOCATION -- <item> -> <podcast:location> @@ -655,6 +740,8 @@ CREATE TABLE item_location ( name varchar_normal ); +CREATE INDEX idx_item_location_item_id ON item_location(item_id); + --** ITEM > PERSON -- <item> -> <podcast:person> @@ -668,6 +755,8 @@ CREATE TABLE item_person ( href varchar_url ); +CREATE INDEX idx_item_person_item_id ON item_person(item_id); + --** ITEM > SEASON -- <item> -> <podcast:season> @@ -678,6 +767,9 @@ CREATE TABLE item_season ( title varchar_normal ); +CREATE INDEX idx_item_season_channel_season_id ON item_season(channel_season_id); +CREATE INDEX idx_item_season_item_id ON item_season(item_id); + --** ITEM > SEASON > EPISODE -- <item> -> <podcast:season> -> <podcast:episode> @@ -688,6 +780,8 @@ CREATE TABLE item_season_episode ( number FLOAT NOT NULL ); +CREATE INDEX idx_item_season_episode_item_id ON item_season_episode(item_id); + --** ITEM > SOCIAL INTERACT -- <item> -> <podcast:socialInteract> @@ -701,6 +795,8 @@ CREATE TABLE item_social_interact ( priority INTEGER ); +CREATE INDEX idx_item_social_interact_item_id ON item_social_interact(item_id); + --** ITEM > SOUNDBITE -- <item> -> <podcast:soundbite> @@ -713,6 +809,8 @@ CREATE TABLE item_soundbite ( title varchar_normal ); +CREATE INDEX idx_item_soundbite_item_id ON item_soundbite(item_id); + --** ITEM > TRANSCRIPT -- <item> -> <podcast:transcript> @@ -725,6 +823,8 @@ CREATE TABLE item_transcript ( rel VARCHAR(50) CHECK (rel IS NULL OR rel = 'captions') ); +CREATE INDEX idx_item_transcript_item_id ON item_transcript(item_id); + --** ITEM > TXT -- <item> -> <podcast:txt> @@ -735,6 +835,8 @@ CREATE TABLE item_txt ( value varchar_long NOT NULL ); +CREATE INDEX idx_item_txt_item_id ON item_txt(item_id); + --** ITEM > VALUE -- <item> -> <podcast:value> @@ -746,6 +848,8 @@ CREATE TABLE item_value ( suggested FLOAT ); +CREATE INDEX idx_item_value_item_id ON item_value(item_id); + --** ITEM > VALUE > RECEIPIENT -- <item> -> <podcast:value> -> <podcast:valueRecipient> @@ -761,6 +865,8 @@ CREATE TABLE item_value_recipient ( fee BOOLEAN DEFAULT FALSE ); +CREATE INDEX idx_item_value_recipient_item_value_id ON item_value_recipient(item_value_id); + --** ITEM > VALUE > TIME SPLIT -- <item> -> <podcast:value> -> <podcast:valueTimeSplit> @@ -773,6 +879,8 @@ CREATE TABLE item_value_time_split ( remote_percentage media_player_time DEFAULT 100 ); +CREATE INDEX idx_item_value_time_split_item_value_id ON item_value_time_split(item_value_id); + --** ITEM > VALUE > TIME SPLIT > REMOTE ITEM -- <item> -> <podcast:value> -> <podcast:valueTimeSplit> -> <podcast:remoteItem> @@ -785,6 +893,8 @@ CREATE TABLE item_value_time_split_remote_item ( title varchar_normal ); +CREATE INDEX idx_item_value_time_split_remote_item_item_value_time_split_id ON item_value_time_split_remote_item(item_value_time_split_id); + --** ITEM > VALUE > TIME SPLIT > VALUE RECIPEINT -- <item> -> <podcast:value> -> <podcast:valueTimeSplit> -> <podcast:valueRecipient> @@ -800,6 +910,8 @@ CREATE TABLE item_value_time_split_recipient ( fee BOOLEAN DEFAULT FALSE ); +CREATE INDEX idx_item_value_time_split_recipient_item_value_time_split_id ON item_value_time_split_recipient(item_value_time_split_id); + --** LIVE ITEM > STATUS CREATE TABLE live_item_status ( @@ -824,6 +936,8 @@ CREATE TABLE live_item ( chat_web_url varchar_url ); +CREATE INDEX idx_live_item_item_id ON live_item(item_id); +CREATE INDEX idx_live_item_live_item_status_id ON live_item(live_item_status_id); -- 0002 migration @@ -841,6 +955,8 @@ CREATE TABLE account ( sharable_status_id INTEGER NOT NULL REFERENCES sharable_status(id) ); +CREATE INDEX idx_account_sharable_status_id ON account(sharable_status_id); + CREATE TABLE account_credentials ( id SERIAL PRIMARY KEY, account_id integer REFERENCES account(id) ON DELETE CASCADE, @@ -848,6 +964,8 @@ CREATE TABLE account_credentials ( password varchar_password NOT NULL ); +CREATE INDEX idx_account_credentials_account_id ON account_credentials(account_id); + CREATE TABLE account_profile ( id SERIAL PRIMARY KEY, account_id integer REFERENCES account(id) ON DELETE CASCADE, @@ -855,6 +973,8 @@ CREATE TABLE account_profile ( bio varchar_long ); +CREATE INDEX idx_account_profile_account_id ON account_profile(account_id); + CREATE TABLE account_reset_password ( id SERIAL PRIMARY KEY, account_id integer REFERENCES account(id) ON DELETE CASCADE, @@ -862,6 +982,8 @@ CREATE TABLE account_reset_password ( reset_token_expires_at TIMESTAMP ); +CREATE INDEX idx_account_reset_password_account_id ON account_reset_password(account_id); + CREATE TABLE account_verification ( id SERIAL PRIMARY KEY, account_id integer REFERENCES account(id) ON DELETE CASCADE, @@ -869,6 +991,8 @@ CREATE TABLE account_verification ( verification_token_expires_at TIMESTAMP ); +CREATE INDEX idx_account_verification_account_id ON account_verification(account_id); + CREATE TABLE account_membership ( id SERIAL PRIMARY KEY, tier TEXT UNIQUE CHECK (tier IN ('trial', 'basic')) @@ -883,6 +1007,9 @@ CREATE TABLE account_membership_status ( membership_expires_at TIMESTAMP ); +CREATE INDEX idx_account_membership_status_account_id ON account_membership_status(account_id); +CREATE INDEX idx_account_membership_status_account_membership_id ON account_membership_status(account_membership_id); + CREATE TABLE account_admin_roles ( id SERIAL PRIMARY KEY, account_id integer REFERENCES account(id) ON DELETE CASCADE, @@ -890,6 +1017,8 @@ CREATE TABLE account_admin_roles ( podping_admin BOOLEAN DEFAULT FALSE ); +CREATE INDEX idx_account_admin_roles_account_id ON account_admin_roles(account_id); + -- 0003 migration CREATE TABLE clip ( @@ -904,6 +1033,10 @@ CREATE TABLE clip ( sharable_status_id INTEGER NOT NULL REFERENCES sharable_status(id) ); +CREATE INDEX idx_clip_account_id ON clip(account_id); +CREATE INDEX idx_clip_item_id ON clip(item_id); +CREATE INDEX idx_clip_sharable_status_id ON clip(sharable_status_id); + -- 0004 migration CREATE TABLE playlist ( @@ -919,6 +1052,10 @@ CREATE TABLE playlist ( medium_id INTEGER NOT NULL REFERENCES medium(id) ); +CREATE INDEX idx_playlist_account_id ON playlist(account_id); +CREATE INDEX idx_playlist_sharable_status_id ON playlist(sharable_status_id); +CREATE INDEX idx_playlist_medium_id ON playlist(medium_id); + CREATE TABLE playlist_resource_base ( id SERIAL PRIMARY KEY, playlist_id INTEGER NOT NULL REFERENCES playlist(id) ON DELETE CASCADE, @@ -926,26 +1063,38 @@ CREATE TABLE playlist_resource_base ( UNIQUE (playlist_id, list_position) ); +CREATE INDEX idx_playlist_resource_base_playlist_id ON playlist_resource_base(playlist_id); + CREATE TABLE playlist_resource_item ( item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE ) INHERITS (playlist_resource_base); +CREATE INDEX idx_playlist_resource_item_item_id ON playlist_resource_item(item_id); + CREATE TABLE playlist_resource_item_add_by_rss ( resource_data jsonb NOT NULL ) INHERITS (playlist_resource_base); +CREATE INDEX idx_playlist_resource_item_add_by_rss_resource_data ON playlist_resource_item_add_by_rss USING gin (resource_data); + CREATE TABLE playlist_resource_item_chapter ( item_chapter_id INTEGER NOT NULL REFERENCES item_chapter(id) ON DELETE CASCADE ) INHERITS (playlist_resource_base); +CREATE INDEX idx_playlist_resource_item_chapter_item_chapter_id ON playlist_resource_item_chapter(item_chapter_id); + CREATE TABLE playlist_resource_clip ( clip_id INTEGER NOT NULL REFERENCES clip(id) ON DELETE CASCADE ) INHERITS (playlist_resource_base); +CREATE INDEX idx_playlist_resource_clip_clip_id ON playlist_resource_clip(clip_id); + CREATE TABLE playlist_resource_item_soundbite ( soundbite_id INTEGER NOT NULL REFERENCES item_soundbite(id) ON DELETE CASCADE ) INHERITS (playlist_resource_base); +CREATE INDEX idx_playlist_resource_item_soundbite_soundbite_id ON playlist_resource_item_soundbite(soundbite_id); + CREATE OR REPLACE FUNCTION delete_playlist_resource_base() RETURNS TRIGGER AS $$ BEGIN @@ -988,6 +1137,9 @@ CREATE TABLE queue ( UNIQUE (account_id, medium_id) ); +CREATE INDEX idx_queue_account_id ON queue(account_id); +CREATE INDEX idx_queue_medium_id ON queue(medium_id); + CREATE TABLE queue_resource_base ( id SERIAL PRIMARY KEY, queue_id INTEGER NOT NULL REFERENCES queue(id) ON DELETE CASCADE, @@ -998,31 +1150,43 @@ CREATE TABLE queue_resource_base ( completed BOOLEAN NOT NULL DEFAULT FALSE ); +CREATE INDEX idx_queue_resource_base_queue_id ON queue_resource_base(queue_id); + CREATE TABLE queue_resource_item ( item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, UNIQUE (queue_id) ) INHERITS (queue_resource_base); +CREATE INDEX idx_queue_resource_item_item_id ON queue_resource_item(item_id); + CREATE TABLE queue_resource_item_add_by_rss ( resource_data jsonb NOT NULL, UNIQUE (queue_id) ) INHERITS (queue_resource_base); +CREATE INDEX idx_queue_resource_item_add_by_rss_resource_data ON queue_resource_item_add_by_rss USING gin (resource_data); + CREATE TABLE queue_resource_item_chapter ( item_chapter_id INTEGER NOT NULL REFERENCES item_chapter(id) ON DELETE CASCADE, UNIQUE (queue_id) ) INHERITS (queue_resource_base); +CREATE INDEX idx_queue_resource_item_chapter_item_chapter_id ON queue_resource_item_chapter(item_chapter_id); + CREATE TABLE queue_resource_clip ( clip_id INTEGER NOT NULL REFERENCES clip(id) ON DELETE CASCADE, UNIQUE (queue_id) ) INHERITS (queue_resource_base); +CREATE INDEX idx_queue_resource_clip_clip_id ON queue_resource_clip(clip_id); + CREATE TABLE queue_resource_item_soundbite ( soundbite_id INTEGER NOT NULL REFERENCES item_soundbite(id) ON DELETE CASCADE, UNIQUE (queue_id) ) INHERITS (queue_resource_base); +CREATE INDEX idx_queue_resource_item_soundbite_soundbite_id ON queue_resource_item_soundbite(soundbite_id); + CREATE OR REPLACE FUNCTION delete_queue_resource_base() RETURNS TRIGGER AS $$ BEGIN @@ -1064,18 +1228,27 @@ CREATE TABLE account_following_account ( PRIMARY KEY (account_id, following_account_id) ); +CREATE INDEX idx_account_following_account_account_id ON account_following_account(account_id); +CREATE INDEX idx_account_following_account_following_account_id ON account_following_account(following_account_id); + CREATE TABLE account_following_channel ( account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, PRIMARY KEY (account_id, channel_id) ); +CREATE INDEX idx_account_following_channel_account_id ON account_following_channel(account_id); +CREATE INDEX idx_account_following_channel_channel_id ON account_following_channel(channel_id); + CREATE TABLE account_following_playlist ( account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, playlist_id INTEGER NOT NULL REFERENCES playlist(id) ON DELETE CASCADE, PRIMARY KEY (account_id, playlist_id) ); +CREATE INDEX idx_account_following_playlist_account_id ON account_following_playlist(account_id); +CREATE INDEX idx_account_following_playlist_playlist_id ON account_following_playlist(playlist_id); + CREATE TABLE account_following_add_by_rss_channel ( account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, feed_url varchar_url NOT NULL, @@ -1084,6 +1257,8 @@ CREATE TABLE account_following_add_by_rss_channel ( image_url varchar_url ); +CREATE INDEX idx_account_following_add_by_rss_channel_account_id ON account_following_add_by_rss_channel(account_id); + -- 0007 CREATE TABLE account_notification ( @@ -1092,6 +1267,9 @@ CREATE TABLE account_notification ( PRIMARY KEY (channel_id, account_id) ); +CREATE INDEX idx_account_notification_channel_id ON account_notification(channel_id); +CREATE INDEX idx_account_notification_account_id ON account_notification(account_id); + CREATE TABLE account_up_device ( account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, up_endpoint varchar_url PRIMARY KEY, @@ -1099,13 +1277,15 @@ CREATE TABLE account_up_device ( up_auth_key varchar_long NOT NULL ); -CREATE DOMAIN varchar_fcm_token AS VARCHAR(255); +CREATE INDEX idx_account_up_device_account_id ON account_up_device(account_id); CREATE TABLE account_fcm_device ( fcm_token varchar_fcm_token PRIMARY KEY, account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE ); +CREATE INDEX idx_account_fcm_device_account_id ON account_fcm_device(account_id); + -- 0008 CREATE TABLE account_paypal_order ( @@ -1114,6 +1294,8 @@ CREATE TABLE account_paypal_order ( state VARCHAR ); +CREATE INDEX idx_account_paypal_order_account_id ON account_paypal_order(account_id); + CREATE TABLE account_app_store_purchase ( account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, transaction_id VARCHAR PRIMARY KEY, @@ -1139,6 +1321,8 @@ CREATE TABLE account_app_store_purchase ( web_order_line_item_id VARCHAR ); +CREATE INDEX idx_account_app_store_purchase_account_id ON account_app_store_purchase(account_id); + CREATE TABLE account_google_play_purchase ( account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, transaction_id VARCHAR PRIMARY KEY, @@ -1152,6 +1336,7 @@ CREATE TABLE account_google_play_purchase ( purchase_token VARCHAR UNIQUE NOT NULL ); +CREATE INDEX idx_account_google_play_purchase_account_id ON account_google_play_purchase(account_id); -- 0009 @@ -1162,3 +1347,5 @@ CREATE TABLE membership_claim_token ( account_membership_id INT REFERENCES account_membership(id) ON DELETE CASCADE ); +CREATE INDEX idx_membership_claim_token_account_membership_id ON membership_claim_token(account_membership_id); + diff --git a/database/migrations/0000_init_helpers.sql b/database/migrations/0000_init_helpers.sql index 167c585..c39b172 100644 --- a/database/migrations/0000_init_helpers.sql +++ b/database/migrations/0000_init_helpers.sql @@ -12,6 +12,7 @@ CREATE DOMAIN varchar_normal AS VARCHAR(255); CREATE DOMAIN varchar_long AS VARCHAR(2500); CREATE DOMAIN varchar_email AS VARCHAR(255) CHECK (VALUE ~ '^.+@.+\..+$'); +CREATE DOMAIN varchar_fcm_token AS VARCHAR(255); CREATE DOMAIN varchar_fqdn AS VARCHAR(253); CREATE DOMAIN varchar_guid AS VARCHAR(36); CREATE DOMAIN varchar_md5 AS VARCHAR(32); diff --git a/database/migrations/0001_init_podcasting_20_database.sql b/database/migrations/0001_init_podcasting_20_database.sql index a0573f5..b46aa70 100644 --- a/database/migrations/0001_init_podcasting_20_database.sql +++ b/database/migrations/0001_init_podcasting_20_database.sql @@ -101,6 +101,8 @@ CREATE TABLE feed ( updated_at server_time_with_default ); +CREATE INDEX idx_feed_feed_flag_status_id ON feed(feed_flag_status_id); + CREATE TRIGGER set_updated_at_feed BEFORE UPDATE ON feed FOR EACH ROW @@ -115,6 +117,8 @@ CREATE TABLE feed_log ( parse_errors INTEGER DEFAULT 0 ); +CREATE INDEX idx_feed_log_feed_id ON feed_log(feed_id); + --** CHANNEL -- <channel> @@ -141,6 +145,8 @@ CREATE TABLE channel ( CREATE UNIQUE INDEX channel_podcast_guid_unique ON channel(podcast_guid) WHERE podcast_guid IS NOT NULL; CREATE UNIQUE INDEX channel_slug ON channel(slug) WHERE slug IS NOT NULL; +CREATE INDEX idx_channel_feed_id ON channel(feed_id); +CREATE INDEX idx_channel_medium_id ON channel(medium_id); --** CHANNEL > ABOUT > ITUNES TYPE @@ -167,6 +173,9 @@ CREATE TABLE channel_about ( website_link_url varchar_url -- <link> ); +CREATE INDEX idx_channel_about_channel_id ON channel_about(channel_id); +CREATE INDEX idx_channel_about_itunes_type_id ON channel_about(itunes_type_id); + --** CHANNEL > CATEGORY CREATE TABLE channel_category ( @@ -175,6 +184,9 @@ CREATE TABLE channel_category ( parent_id INTEGER REFERENCES channel_category(id) ON DELETE CASCADE ); +CREATE INDEX idx_channel_category_channel_id ON channel_category(channel_id); +CREATE INDEX idx_channel_category_parent_id ON channel_category(parent_id); + --** CHANNEL > CHAT -- <channel> -> <podcast:chat> @@ -187,6 +199,8 @@ CREATE TABLE channel_chat ( space varchar_normal ); +CREATE INDEX idx_channel_chat_channel_id ON channel_chat(channel_id); + --** CHANNEL > DESCRIPTION -- <channel> -> <description> AND possibly other tags that contain a description @@ -197,6 +211,8 @@ CREATE TABLE channel_description ( value varchar_long NOT NULL ); +CREATE INDEX idx_channel_description_channel_id ON channel_description(channel_id); + --** CHANNEL > FUNDING -- <channel> -> <podcast:funding> @@ -207,6 +223,8 @@ CREATE TABLE channel_funding ( title varchar_normal ); +CREATE INDEX idx_channel_funding_channel_id ON channel_funding(channel_id); + --** CHANNEL > IMAGE -- <channel> -> <podcast:image> AND all other image tags in the rss feed @@ -222,6 +240,8 @@ CREATE TABLE channel_image ( is_resized BOOLEAN DEFAULT FALSE ); +CREATE INDEX idx_channel_image_channel_id ON channel_image(channel_id); + --** CHANNEL > INTERNAL SETTINGS CREATE TABLE channel_internal_settings ( @@ -232,6 +252,8 @@ CREATE TABLE channel_internal_settings ( embed_approved_media_url_paths TEXT ); +CREATE INDEX idx_channel_internal_settings_channel_id ON channel_internal_settings(channel_id); + --** CHANNEL > LICENSE -- <channel> -> <podcast:license> @@ -243,6 +265,8 @@ CREATE TABLE channel_license ( url varchar_url ); +CREATE INDEX idx_channel_license_channel_id ON channel_license(channel_id); + --** CHANNEL > LOCATION -- <channel> -> <podcast:location> @@ -255,6 +279,8 @@ CREATE TABLE channel_location ( name varchar_normal ); +CREATE INDEX idx_channel_location_channel_id ON channel_location(channel_id); + --** CHANNEL > PERSON -- <channel> -> <podcast:person> @@ -268,6 +294,8 @@ CREATE TABLE channel_person ( href varchar_url ); +CREATE INDEX idx_channel_person_channel_id ON channel_person(channel_id); + --** CHANNEL > PODROLL -- <channel> -> <podcast:podroll> @@ -276,6 +304,8 @@ CREATE TABLE channel_podroll ( channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE ); +CREATE INDEX idx_channel_podroll_channel_id ON channel_podroll(channel_id); + --** CHANNEL > PODROLL > REMOTE ITEM -- <channel> -> <podcast:podroll> --> <podcast:remoteItem> @@ -289,6 +319,9 @@ CREATE TABLE channel_podroll_remote_item ( medium_id INTEGER REFERENCES medium(id) ); +CREATE INDEX idx_channel_podroll_remote_item_channel_podroll_id ON channel_podroll_remote_item(channel_podroll_id); +CREATE INDEX idx_channel_podroll_remote_item_medium_id ON channel_podroll_remote_item(medium_id); + --** CHANNEL > PUBLISHER -- <channel> -> <podcast:publisher> @@ -297,6 +330,8 @@ CREATE TABLE channel_publisher ( channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE ); +CREATE INDEX idx_channel_publisher_channel_id ON channel_publisher(channel_id); + --** CHANNEL > PUBLISHER > REMOTE ITEM -- <channel> -> <podcast:publisher> -> <podcast:remoteItem> @@ -310,6 +345,9 @@ CREATE TABLE channel_publisher_remote_item ( medium_id INTEGER REFERENCES medium(id) ); +CREATE INDEX idx_channel_publisher_remote_item_channel_publisher_id ON channel_publisher_remote_item(channel_publisher_id); +CREATE INDEX idx_channel_publisher_remote_item_medium_id ON channel_publisher_remote_item(medium_id); + --** CHANNEL > REMOTE ITEM -- Remote items at the channel level are only used when the <podcast:medium> for the channel @@ -326,6 +364,9 @@ CREATE TABLE channel_remote_item ( medium_id INTEGER REFERENCES medium(id) ); +CREATE INDEX idx_channel_remote_item_channel_id ON channel_remote_item(channel_id); +CREATE INDEX idx_channel_remote_item_medium_id ON channel_remote_item(medium_id); + --** CHANNEL > SEASON -- channels with seasons need to be rendered in client apps differently. @@ -344,6 +385,8 @@ CREATE TABLE channel_season ( name varchar_normal ); +CREATE INDEX idx_channel_season_channel_id ON channel_season(channel_id); + --** CHANNEL > SOCIAL INTERACT -- <channel> -> <podcast:socialInteract> @@ -357,6 +400,8 @@ CREATE TABLE channel_social_interact ( priority INTEGER ); +CREATE INDEX idx_channel_social_interact_channel_id ON channel_social_interact(channel_id); + --** CHANNEL > TRAILER -- <channel> -> <podcast:trailer> @@ -372,6 +417,9 @@ CREATE TABLE channel_trailer ( UNIQUE (channel_id, url) ); +CREATE INDEX idx_channel_trailer_channel_id ON channel_trailer(channel_id); +CREATE INDEX idx_channel_trailer_channel_season_id ON channel_trailer(channel_season_id); + --** CHANNEL > TXT -- <channel> -> <podcast:txt> @@ -382,6 +430,8 @@ CREATE TABLE channel_txt ( value varchar_long NOT NULL ); +CREATE INDEX idx_channel_txt_channel_id ON channel_txt(channel_id); + --** CHANNEL > VALUE -- <channel> -> <podcast:value> @@ -393,6 +443,8 @@ CREATE TABLE channel_value ( suggested FLOAT ); +CREATE INDEX idx_channel_value_channel_id ON channel_value(channel_id); + --** CHANNEL > VALUE > RECEIPIENT -- <channel> -> <podcast:value> -> <podcast:valueRecipient> @@ -408,6 +460,8 @@ CREATE TABLE channel_value_recipient ( fee BOOLEAN DEFAULT FALSE ); +CREATE INDEX idx_channel_value_recipient_channel_value_id ON channel_value_recipient(channel_value_id); + --** ITEM -- Technically the item table could be named channel_item, but it seems easier to understand as item. @@ -430,6 +484,7 @@ CREATE TABLE item ( ); CREATE UNIQUE INDEX item_slug ON item(slug) WHERE slug IS NOT NULL; +CREATE INDEX idx_item_channel_id ON item(channel_id); --** ITEM > ABOUT > ITUNES TYPE @@ -452,6 +507,9 @@ CREATE TABLE item_about ( item_itunes_episode_type_id INTEGER REFERENCES item_itunes_episode_type(id) -- <itunes:episodeType> ); +CREATE INDEX idx_item_about_item_id ON item_about(item_id); +CREATE INDEX idx_item_about_item_itunes_episode_type_id ON item_about(item_itunes_episode_type_id); + --** ITEM > CHAPTERS -- <item> -> <podcast:chapters> @@ -462,6 +520,8 @@ CREATE TABLE item_chapters_feed ( type varchar_short NOT NULL ); +CREATE INDEX idx_item_chapters_feed_item_id ON item_chapters_feed(item_id); + --** ITEM > CHAPTERS > LOG -- <item> -> <podcast:chapters> -> parsing logs @@ -475,6 +535,8 @@ CREATE TABLE item_chapters_feed_log ( parse_errors INTEGER DEFAULT 0 ); +CREATE INDEX idx_item_chapters_feed_log_item_chapters_feed_id ON item_chapters_feed_log(item_chapters_feed_id); + --** ITEM > CHAPTERS > CHAPTER -- -- <item> -> <podcast:chapters> -> chapter items correspond with jsonChapters.md example file @@ -490,6 +552,8 @@ CREATE TABLE item_chapter ( table_of_contents BOOLEAN DEFAULT TRUE ); +CREATE INDEX idx_item_chapter_item_chapters_feed_id ON item_chapter(item_chapters_feed_id); + --** ITEM > CHAPTER > LOCATION -- <item> -> <podcast:chapters> -> chapter items correspond with jsonChapters.md example file @@ -502,6 +566,8 @@ CREATE TABLE item_chapter_location ( name varchar_normal ); +CREATE INDEX idx_item_chapter_location_item_chapter_id ON item_chapter_location(item_chapter_id); + --** ITEM > CHAT -- <item> -> <podcast:chat> @@ -514,6 +580,8 @@ CREATE TABLE item_chat ( space varchar_normal ); +CREATE INDEX idx_item_chat_item_id ON item_chat(item_id); + --** ITEM > CONTENT LINK -- <item> -> <podcast:contentLink> @@ -524,6 +592,8 @@ CREATE TABLE item_content_link ( title varchar_normal ); +CREATE INDEX idx_item_content_link_item_id ON item_content_link(item_id); + --** ITEM > DESCRIPTION -- <item> -> <description> AND possibly other tags that contain a description @@ -534,6 +604,8 @@ CREATE TABLE item_description ( value varchar_long NOT NULL ); +CREATE INDEX idx_item_description_item_id ON item_description(item_id); + --** ITEM > ENCLOSURE (AKA ALTERNATE ENCLOSURE) -- NOTE: the older <enclosure> tag style is integrated into the item_enclosure table. @@ -553,6 +625,8 @@ CREATE TABLE item_enclosure ( item_enclosure_default BOOLEAN DEFAULT FALSE ); +CREATE INDEX idx_item_enclosure_item_id ON item_enclosure(item_id); + -- <item> -> <podcast:alternateEnclosure> -> <podcast:source> CREATE TABLE item_enclosure_source ( id SERIAL PRIMARY KEY, @@ -561,6 +635,8 @@ CREATE TABLE item_enclosure_source ( content_type varchar_short ); +CREATE INDEX idx_item_enclosure_source_item_id ON item_enclosure_source(item_enclosure_id); + -- <item> -> <podcast:alternateEnclosure> -> <podcast:integrity> CREATE TABLE item_enclosure_integrity ( id SERIAL PRIMARY KEY, @@ -569,6 +645,8 @@ CREATE TABLE item_enclosure_integrity ( value varchar_long NOT NULL ); +CREATE INDEX idx_item_enclosure_integrity_item_enclosure_id ON item_enclosure_integrity(item_enclosure_id); + --** ITEM > FUNDING -- <item> -> <podcast:funding> @@ -579,6 +657,8 @@ CREATE TABLE item_funding ( title varchar_normal ); +CREATE INDEX idx_item_funding_item_id ON item_funding(item_id); + --** ITEM > IMAGE -- <item> -> <podcast:image> AND all other image tags in the rss feed @@ -594,6 +674,8 @@ CREATE TABLE item_image ( is_resized BOOLEAN DEFAULT FALSE ); +CREATE INDEX idx_item_image_item_id ON item_image(item_id); + --** ITEM > LICENSE -- <item> -> <podcast:license> @@ -605,6 +687,8 @@ CREATE TABLE item_license ( url varchar_url ); +CREATE INDEX idx_item_license_item_id ON item_license(item_id); + --** ITEM > LOCATION -- <item> -> <podcast:location> @@ -617,6 +701,8 @@ CREATE TABLE item_location ( name varchar_normal ); +CREATE INDEX idx_item_location_item_id ON item_location(item_id); + --** ITEM > PERSON -- <item> -> <podcast:person> @@ -630,6 +716,8 @@ CREATE TABLE item_person ( href varchar_url ); +CREATE INDEX idx_item_person_item_id ON item_person(item_id); + --** ITEM > SEASON -- <item> -> <podcast:season> @@ -640,6 +728,9 @@ CREATE TABLE item_season ( title varchar_normal ); +CREATE INDEX idx_item_season_channel_season_id ON item_season(channel_season_id); +CREATE INDEX idx_item_season_item_id ON item_season(item_id); + --** ITEM > SEASON > EPISODE -- <item> -> <podcast:season> -> <podcast:episode> @@ -650,6 +741,8 @@ CREATE TABLE item_season_episode ( number FLOAT NOT NULL ); +CREATE INDEX idx_item_season_episode_item_id ON item_season_episode(item_id); + --** ITEM > SOCIAL INTERACT -- <item> -> <podcast:socialInteract> @@ -663,6 +756,8 @@ CREATE TABLE item_social_interact ( priority INTEGER ); +CREATE INDEX idx_item_social_interact_item_id ON item_social_interact(item_id); + --** ITEM > SOUNDBITE -- <item> -> <podcast:soundbite> @@ -675,6 +770,8 @@ CREATE TABLE item_soundbite ( title varchar_normal ); +CREATE INDEX idx_item_soundbite_item_id ON item_soundbite(item_id); + --** ITEM > TRANSCRIPT -- <item> -> <podcast:transcript> @@ -687,6 +784,8 @@ CREATE TABLE item_transcript ( rel VARCHAR(50) CHECK (rel IS NULL OR rel = 'captions') ); +CREATE INDEX idx_item_transcript_item_id ON item_transcript(item_id); + --** ITEM > TXT -- <item> -> <podcast:txt> @@ -697,6 +796,8 @@ CREATE TABLE item_txt ( value varchar_long NOT NULL ); +CREATE INDEX idx_item_txt_item_id ON item_txt(item_id); + --** ITEM > VALUE -- <item> -> <podcast:value> @@ -708,6 +809,8 @@ CREATE TABLE item_value ( suggested FLOAT ); +CREATE INDEX idx_item_value_item_id ON item_value(item_id); + --** ITEM > VALUE > RECEIPIENT -- <item> -> <podcast:value> -> <podcast:valueRecipient> @@ -723,6 +826,8 @@ CREATE TABLE item_value_recipient ( fee BOOLEAN DEFAULT FALSE ); +CREATE INDEX idx_item_value_recipient_item_value_id ON item_value_recipient(item_value_id); + --** ITEM > VALUE > TIME SPLIT -- <item> -> <podcast:value> -> <podcast:valueTimeSplit> @@ -735,6 +840,8 @@ CREATE TABLE item_value_time_split ( remote_percentage media_player_time DEFAULT 100 ); +CREATE INDEX idx_item_value_time_split_item_value_id ON item_value_time_split(item_value_id); + --** ITEM > VALUE > TIME SPLIT > REMOTE ITEM -- <item> -> <podcast:value> -> <podcast:valueTimeSplit> -> <podcast:remoteItem> @@ -747,6 +854,8 @@ CREATE TABLE item_value_time_split_remote_item ( title varchar_normal ); +CREATE INDEX idx_item_value_time_split_remote_item_item_value_time_split_id ON item_value_time_split_remote_item(item_value_time_split_id); + --** ITEM > VALUE > TIME SPLIT > VALUE RECIPEINT -- <item> -> <podcast:value> -> <podcast:valueTimeSplit> -> <podcast:valueRecipient> @@ -762,6 +871,8 @@ CREATE TABLE item_value_time_split_recipient ( fee BOOLEAN DEFAULT FALSE ); +CREATE INDEX idx_item_value_time_split_recipient_item_value_time_split_id ON item_value_time_split_recipient(item_value_time_split_id); + --** LIVE ITEM > STATUS CREATE TABLE live_item_status ( @@ -786,3 +897,5 @@ CREATE TABLE live_item ( chat_web_url varchar_url ); +CREATE INDEX idx_live_item_item_id ON live_item(item_id); +CREATE INDEX idx_live_item_live_item_status_id ON live_item(live_item_status_id); diff --git a/database/migrations/0002_account.sql b/database/migrations/0002_account.sql index c6d417d..e479c75 100644 --- a/database/migrations/0002_account.sql +++ b/database/migrations/0002_account.sql @@ -14,6 +14,8 @@ CREATE TABLE account ( sharable_status_id INTEGER NOT NULL REFERENCES sharable_status(id) ); +CREATE INDEX idx_account_sharable_status_id ON account(sharable_status_id); + CREATE TABLE account_credentials ( id SERIAL PRIMARY KEY, account_id integer REFERENCES account(id) ON DELETE CASCADE, @@ -21,6 +23,8 @@ CREATE TABLE account_credentials ( password varchar_password NOT NULL ); +CREATE INDEX idx_account_credentials_account_id ON account_credentials(account_id); + CREATE TABLE account_profile ( id SERIAL PRIMARY KEY, account_id integer REFERENCES account(id) ON DELETE CASCADE, @@ -28,6 +32,8 @@ CREATE TABLE account_profile ( bio varchar_long ); +CREATE INDEX idx_account_profile_account_id ON account_profile(account_id); + CREATE TABLE account_reset_password ( id SERIAL PRIMARY KEY, account_id integer REFERENCES account(id) ON DELETE CASCADE, @@ -35,6 +41,8 @@ CREATE TABLE account_reset_password ( reset_token_expires_at TIMESTAMP ); +CREATE INDEX idx_account_reset_password_account_id ON account_reset_password(account_id); + CREATE TABLE account_verification ( id SERIAL PRIMARY KEY, account_id integer REFERENCES account(id) ON DELETE CASCADE, @@ -42,6 +50,8 @@ CREATE TABLE account_verification ( verification_token_expires_at TIMESTAMP ); +CREATE INDEX idx_account_verification_account_id ON account_verification(account_id); + CREATE TABLE account_membership ( id SERIAL PRIMARY KEY, tier TEXT UNIQUE CHECK (tier IN ('trial', 'basic')) @@ -56,9 +66,14 @@ CREATE TABLE account_membership_status ( membership_expires_at TIMESTAMP ); +CREATE INDEX idx_account_membership_status_account_id ON account_membership_status(account_id); +CREATE INDEX idx_account_membership_status_account_membership_id ON account_membership_status(account_membership_id); + CREATE TABLE account_admin_roles ( id SERIAL PRIMARY KEY, account_id integer REFERENCES account(id) ON DELETE CASCADE, dev_admin BOOLEAN DEFAULT FALSE, podping_admin BOOLEAN DEFAULT FALSE ); + +CREATE INDEX idx_account_admin_roles_account_id ON account_admin_roles(account_id); diff --git a/database/migrations/0003_clip.sql b/database/migrations/0003_clip.sql index 0b6c135..028001c 100644 --- a/database/migrations/0003_clip.sql +++ b/database/migrations/0003_clip.sql @@ -11,3 +11,7 @@ CREATE TABLE clip ( description varchar_long, sharable_status_id INTEGER NOT NULL REFERENCES sharable_status(id) ); + +CREATE INDEX idx_clip_account_id ON clip(account_id); +CREATE INDEX idx_clip_item_id ON clip(item_id); +CREATE INDEX idx_clip_sharable_status_id ON clip(sharable_status_id); diff --git a/database/migrations/0004_playlist.sql b/database/migrations/0004_playlist.sql index c223144..8b9b4d0 100644 --- a/database/migrations/0004_playlist.sql +++ b/database/migrations/0004_playlist.sql @@ -13,6 +13,10 @@ CREATE TABLE playlist ( medium_id INTEGER NOT NULL REFERENCES medium(id) ); +CREATE INDEX idx_playlist_account_id ON playlist(account_id); +CREATE INDEX idx_playlist_sharable_status_id ON playlist(sharable_status_id); +CREATE INDEX idx_playlist_medium_id ON playlist(medium_id); + CREATE TABLE playlist_resource_base ( id SERIAL PRIMARY KEY, playlist_id INTEGER NOT NULL REFERENCES playlist(id) ON DELETE CASCADE, @@ -20,26 +24,38 @@ CREATE TABLE playlist_resource_base ( UNIQUE (playlist_id, list_position) ); +CREATE INDEX idx_playlist_resource_base_playlist_id ON playlist_resource_base(playlist_id); + CREATE TABLE playlist_resource_item ( item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE ) INHERITS (playlist_resource_base); +CREATE INDEX idx_playlist_resource_item_item_id ON playlist_resource_item(item_id); + CREATE TABLE playlist_resource_item_add_by_rss ( resource_data jsonb NOT NULL ) INHERITS (playlist_resource_base); +CREATE INDEX idx_playlist_resource_item_add_by_rss_resource_data ON playlist_resource_item_add_by_rss USING gin (resource_data); + CREATE TABLE playlist_resource_item_chapter ( item_chapter_id INTEGER NOT NULL REFERENCES item_chapter(id) ON DELETE CASCADE ) INHERITS (playlist_resource_base); +CREATE INDEX idx_playlist_resource_item_chapter_item_chapter_id ON playlist_resource_item_chapter(item_chapter_id); + CREATE TABLE playlist_resource_clip ( clip_id INTEGER NOT NULL REFERENCES clip(id) ON DELETE CASCADE ) INHERITS (playlist_resource_base); +CREATE INDEX idx_playlist_resource_clip_clip_id ON playlist_resource_clip(clip_id); + CREATE TABLE playlist_resource_item_soundbite ( soundbite_id INTEGER NOT NULL REFERENCES item_soundbite(id) ON DELETE CASCADE ) INHERITS (playlist_resource_base); +CREATE INDEX idx_playlist_resource_item_soundbite_soundbite_id ON playlist_resource_item_soundbite(soundbite_id); + CREATE OR REPLACE FUNCTION delete_playlist_resource_base() RETURNS TRIGGER AS $$ BEGIN diff --git a/database/migrations/0005_queue.sql b/database/migrations/0005_queue.sql index 55279fd..61a817b 100644 --- a/database/migrations/0005_queue.sql +++ b/database/migrations/0005_queue.sql @@ -7,6 +7,9 @@ CREATE TABLE queue ( UNIQUE (account_id, medium_id) ); +CREATE INDEX idx_queue_account_id ON queue(account_id); +CREATE INDEX idx_queue_medium_id ON queue(medium_id); + CREATE TABLE queue_resource_base ( id SERIAL PRIMARY KEY, queue_id INTEGER NOT NULL REFERENCES queue(id) ON DELETE CASCADE, @@ -17,31 +20,43 @@ CREATE TABLE queue_resource_base ( completed BOOLEAN NOT NULL DEFAULT FALSE ); +CREATE INDEX idx_queue_resource_base_queue_id ON queue_resource_base(queue_id); + CREATE TABLE queue_resource_item ( item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, UNIQUE (queue_id) ) INHERITS (queue_resource_base); +CREATE INDEX idx_queue_resource_item_item_id ON queue_resource_item(item_id); + CREATE TABLE queue_resource_item_add_by_rss ( resource_data jsonb NOT NULL, UNIQUE (queue_id) ) INHERITS (queue_resource_base); +CREATE INDEX idx_queue_resource_item_add_by_rss_resource_data ON queue_resource_item_add_by_rss USING gin (resource_data); + CREATE TABLE queue_resource_item_chapter ( item_chapter_id INTEGER NOT NULL REFERENCES item_chapter(id) ON DELETE CASCADE, UNIQUE (queue_id) ) INHERITS (queue_resource_base); +CREATE INDEX idx_queue_resource_item_chapter_item_chapter_id ON queue_resource_item_chapter(item_chapter_id); + CREATE TABLE queue_resource_clip ( clip_id INTEGER NOT NULL REFERENCES clip(id) ON DELETE CASCADE, UNIQUE (queue_id) ) INHERITS (queue_resource_base); +CREATE INDEX idx_queue_resource_clip_clip_id ON queue_resource_clip(clip_id); + CREATE TABLE queue_resource_item_soundbite ( soundbite_id INTEGER NOT NULL REFERENCES item_soundbite(id) ON DELETE CASCADE, UNIQUE (queue_id) ) INHERITS (queue_resource_base); +CREATE INDEX idx_queue_resource_item_soundbite_soundbite_id ON queue_resource_item_soundbite(soundbite_id); + CREATE OR REPLACE FUNCTION delete_queue_resource_base() RETURNS TRIGGER AS $$ BEGIN diff --git a/database/migrations/0006_account_following_tables.sql b/database/migrations/0006_account_following_tables.sql index 27f4a3f..208418a 100644 --- a/database/migrations/0006_account_following_tables.sql +++ b/database/migrations/0006_account_following_tables.sql @@ -6,18 +6,27 @@ CREATE TABLE account_following_account ( PRIMARY KEY (account_id, following_account_id) ); +CREATE INDEX idx_account_following_account_account_id ON account_following_account(account_id); +CREATE INDEX idx_account_following_account_following_account_id ON account_following_account(following_account_id); + CREATE TABLE account_following_channel ( account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, PRIMARY KEY (account_id, channel_id) ); +CREATE INDEX idx_account_following_channel_account_id ON account_following_channel(account_id); +CREATE INDEX idx_account_following_channel_channel_id ON account_following_channel(channel_id); + CREATE TABLE account_following_playlist ( account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, playlist_id INTEGER NOT NULL REFERENCES playlist(id) ON DELETE CASCADE, PRIMARY KEY (account_id, playlist_id) ); +CREATE INDEX idx_account_following_playlist_account_id ON account_following_playlist(account_id); +CREATE INDEX idx_account_following_playlist_playlist_id ON account_following_playlist(playlist_id); + CREATE TABLE account_following_add_by_rss_channel ( account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, feed_url varchar_url NOT NULL, @@ -25,3 +34,5 @@ CREATE TABLE account_following_add_by_rss_channel ( title varchar_normal, image_url varchar_url ); + +CREATE INDEX idx_account_following_add_by_rss_channel_account_id ON account_following_add_by_rss_channel(account_id); diff --git a/database/migrations/0007_notifications.sql b/database/migrations/0007_notifications.sql index 3870db7..aa2f482 100644 --- a/database/migrations/0007_notifications.sql +++ b/database/migrations/0007_notifications.sql @@ -6,6 +6,9 @@ CREATE TABLE account_notification ( PRIMARY KEY (channel_id, account_id) ); +CREATE INDEX idx_account_notification_channel_id ON account_notification(channel_id); +CREATE INDEX idx_account_notification_account_id ON account_notification(account_id); + CREATE TABLE account_up_device ( account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, up_endpoint varchar_url PRIMARY KEY, @@ -13,9 +16,11 @@ CREATE TABLE account_up_device ( up_auth_key varchar_long NOT NULL ); -CREATE DOMAIN varchar_fcm_token AS VARCHAR(255); +CREATE INDEX idx_account_up_device_account_id ON account_up_device(account_id); CREATE TABLE account_fcm_device ( fcm_token varchar_fcm_token PRIMARY KEY, account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE ); + +CREATE INDEX idx_account_fcm_device_account_id ON account_fcm_device(account_id); diff --git a/database/migrations/0008_purchases_paypal_apple_google.sql b/database/migrations/0008_purchases_paypal_apple_google.sql index a9119f6..5dd43b5 100644 --- a/database/migrations/0008_purchases_paypal_apple_google.sql +++ b/database/migrations/0008_purchases_paypal_apple_google.sql @@ -6,6 +6,8 @@ CREATE TABLE account_paypal_order ( state VARCHAR ); +CREATE INDEX idx_account_paypal_order_account_id ON account_paypal_order(account_id); + CREATE TABLE account_app_store_purchase ( account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, transaction_id VARCHAR PRIMARY KEY, @@ -31,6 +33,8 @@ CREATE TABLE account_app_store_purchase ( web_order_line_item_id VARCHAR ); +CREATE INDEX idx_account_app_store_purchase_account_id ON account_app_store_purchase(account_id); + CREATE TABLE account_google_play_purchase ( account_id INTEGER NOT NULL REFERENCES account(id) ON DELETE CASCADE, transaction_id VARCHAR PRIMARY KEY, @@ -44,3 +48,4 @@ CREATE TABLE account_google_play_purchase ( purchase_token VARCHAR UNIQUE NOT NULL ); +CREATE INDEX idx_account_google_play_purchase_account_id ON account_google_play_purchase(account_id); diff --git a/database/migrations/0009_membership_claim_token.sql b/database/migrations/0009_membership_claim_token.sql index bdc62ae..3686e08 100644 --- a/database/migrations/0009_membership_claim_token.sql +++ b/database/migrations/0009_membership_claim_token.sql @@ -6,3 +6,5 @@ CREATE TABLE membership_claim_token ( years_to_add INT DEFAULT 1, account_membership_id INT REFERENCES account_membership(id) ON DELETE CASCADE ); + +CREATE INDEX idx_membership_claim_token_account_membership_id ON membership_claim_token(account_membership_id); From 250e6dd4920c77e3b3f2a4e10db2e3a9bcc8077c Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Thu, 19 Sep 2024 03:11:23 -0500 Subject: [PATCH 71/73] Add comments to npm-link-modules.sh --- dev/npm-link-modules.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/dev/npm-link-modules.sh b/dev/npm-link-modules.sh index 7576807..74ad0cb 100755 --- a/dev/npm-link-modules.sh +++ b/dev/npm-link-modules.sh @@ -1,5 +1,7 @@ #!/bin/bash +# Delete and reinstall all node_modules + echo "Clearing npm cache..." npm cache clean --force @@ -13,7 +15,6 @@ cd ../podverse-external-services rm -rf node_modules npm install - echo "Installing podverse-helpers dependencies..." cd ../podverse-helpers rm -rf node_modules @@ -39,7 +40,7 @@ cd ../podverse-workers rm -rf node_modules npm install - +# Link dependencies to npm echo "Linking podverse-external-services dependency..." cd ../podverse-external-services @@ -61,7 +62,7 @@ echo "Linking podverse-queue dependency..." cd ../podverse-queue npm link - +# Link dependencies to conuming projects echo "Linking podverse-api dependencies..." cd ../podverse-api From 608c4609e45218bdf078ac62ac9df04756d17287 Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Sat, 21 Sep 2024 16:33:58 -0500 Subject: [PATCH 72/73] Update npm-link-modules --- dev/npm-link-modules.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/dev/npm-link-modules.sh b/dev/npm-link-modules.sh index 74ad0cb..4e0a425 100755 --- a/dev/npm-link-modules.sh +++ b/dev/npm-link-modules.sh @@ -80,6 +80,7 @@ npm link podverse-helpers echo "Linking podverse-parser dependencies..." cd ../podverse-parser +npm link podverse-external-services npm link podverse-helpers npm link podverse-orm From bf2403fec91c8be3f628ef827473a0697f9b74e6 Mon Sep 17 00:00:00 2001 From: Mitch Downey <mitchldowney@gmail.com> Date: Sat, 21 Sep 2024 16:56:54 -0500 Subject: [PATCH 73/73] Fix OneToOne unique relationships; add indexes to remote_item tables --- database/combined/init_database.sql | 64 +++++++++++-------- .../0001_init_podcasting_20_database.sql | 64 +++++++++++-------- 2 files changed, 76 insertions(+), 52 deletions(-) diff --git a/database/combined/init_database.sql b/database/combined/init_database.sql index 9782291..ebf1323 100644 --- a/database/combined/init_database.sql +++ b/database/combined/init_database.sql @@ -149,7 +149,7 @@ EXECUTE FUNCTION set_updated_at_field(); CREATE TABLE feed_log ( id SERIAL PRIMARY KEY, - feed_id INTEGER NOT NULL REFERENCES feed(id) ON DELETE CASCADE, + feed_id INTEGER NOT NULL UNIQUE REFERENCES feed(id) ON DELETE CASCADE, last_http_status INTEGER, last_good_http_status_time server_time, last_finished_parse_time server_time, @@ -165,7 +165,7 @@ CREATE TABLE channel ( id SERIAL PRIMARY KEY, id_text short_id_v2 UNIQUE NOT NULL, slug varchar_slug, - feed_id INTEGER NOT NULL REFERENCES feed(id) ON DELETE CASCADE, + feed_id INTEGER NOT NULL UNIQUE REFERENCES feed(id) ON DELETE CASCADE, podcast_index_id INTEGER UNIQUE NOT NULL, podcast_guid UUID UNIQUE, -- <podcast:guid> title varchar_normal, @@ -176,6 +176,10 @@ CREATE TABLE channel ( -- from the Podcast Index API. has_podcast_index_value BOOLEAN DEFAULT FALSE, + -- this column is used for optimization purposes to determine if all of the items + -- for a channel need to have their value time split remote items parsed. + has_value_time_splits BOOLEAN DEFAULT FALSE, + -- hidden items are no longer available in the rss feed, but are still in the database. hidden BOOLEAN DEFAULT FALSE, -- markedForDeletion items are no longer available in the rss feed, and may be able to be deleted. @@ -202,7 +206,7 @@ INSERT INTO channel_itunes_type (itunes_type) VALUES ('episodic'), ('serial'); -- various <channel> child data from multiple tags CREATE TABLE channel_about ( id SERIAL PRIMARY KEY, - channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, + channel_id INTEGER NOT NULL UNIQUE REFERENCES channel(id) ON DELETE CASCADE, author varchar_normal, -- <itunes:author> and <author> episode_count INTEGER, -- aggregated count for convenience explicit BOOLEAN, -- <itunes:explicit> @@ -231,7 +235,7 @@ CREATE INDEX idx_channel_category_parent_id ON channel_category(parent_id); -- <channel> -> <podcast:chat> CREATE TABLE channel_chat ( id SERIAL PRIMARY KEY, - channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, + channel_id INTEGER NOT NULL UNIQUE REFERENCES channel(id) ON DELETE CASCADE, server varchar_fqdn NOT NULL, protocol varchar_short NOT NULL, account_id varchar_normal, @@ -245,8 +249,7 @@ CREATE INDEX idx_channel_chat_channel_id ON channel_chat(channel_id); -- <channel> -> <description> AND possibly other tags that contain a description CREATE TABLE channel_description ( id SERIAL PRIMARY KEY, - channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, - UNIQUE (channel_id), + channel_id INTEGER NOT NULL UNIQUE REFERENCES channel(id) ON DELETE CASCADE, value varchar_long NOT NULL ); @@ -298,8 +301,7 @@ CREATE INDEX idx_channel_internal_settings_channel_id ON channel_internal_settin -- <channel> -> <podcast:license> CREATE TABLE channel_license ( id SERIAL PRIMARY KEY, - channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, - UNIQUE (channel_id), + channel_id INTEGER NOT NULL UNIQUE REFERENCES channel(id) ON DELETE CASCADE, identifier varchar_normal NOT NULL, url varchar_url ); @@ -311,7 +313,7 @@ CREATE INDEX idx_channel_license_channel_id ON channel_license(channel_id); -- <channel> -> <podcast:location> CREATE TABLE channel_location ( id SERIAL PRIMARY KEY, - channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, + channel_id INTEGER NOT NULL UNIQUE REFERENCES channel(id) ON DELETE CASCADE, geo varchar_normal, osm varchar_normal, CHECK (geo IS NOT NULL OR osm IS NOT NULL), @@ -340,7 +342,7 @@ CREATE INDEX idx_channel_person_channel_id ON channel_person(channel_id); -- <channel> -> <podcast:podroll> CREATE TABLE channel_podroll ( id SERIAL PRIMARY KEY, - channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE + channel_id INTEGER NOT NULL UNIQUE REFERENCES channel(id) ON DELETE CASCADE ); CREATE INDEX idx_channel_podroll_channel_id ON channel_podroll(channel_id); @@ -360,13 +362,16 @@ CREATE TABLE channel_podroll_remote_item ( CREATE INDEX idx_channel_podroll_remote_item_channel_podroll_id ON channel_podroll_remote_item(channel_podroll_id); CREATE INDEX idx_channel_podroll_remote_item_medium_id ON channel_podroll_remote_item(medium_id); +CREATE INDEX idx_channel_podroll_remote_item_feed_guid ON channel_podroll_remote_item(feed_guid); +CREATE INDEX idx_channel_podroll_remote_item_feed_url ON channel_podroll_remote_item(feed_url); +CREATE INDEX idx_channel_podroll_remote_item_item_guid ON channel_podroll_remote_item(item_guid); --** CHANNEL > PUBLISHER -- <channel> -> <podcast:publisher> CREATE TABLE channel_publisher ( id SERIAL PRIMARY KEY, - channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE + channel_id INTEGER NOT NULL UNIQUE REFERENCES channel(id) ON DELETE CASCADE ); CREATE INDEX idx_channel_publisher_channel_id ON channel_publisher(channel_id); @@ -376,7 +381,7 @@ CREATE INDEX idx_channel_publisher_channel_id ON channel_publisher(channel_id); -- <channel> -> <podcast:publisher> -> <podcast:remoteItem> CREATE TABLE channel_publisher_remote_item ( id SERIAL PRIMARY KEY, - channel_publisher_id INTEGER NOT NULL REFERENCES channel_publisher(id) ON DELETE CASCADE, + channel_publisher_id INTEGER NOT NULL UNIQUE REFERENCES channel_publisher(id) ON DELETE CASCADE, feed_guid UUID NOT NULL, feed_url varchar_url, item_guid varchar_uri, @@ -386,6 +391,9 @@ CREATE TABLE channel_publisher_remote_item ( CREATE INDEX idx_channel_publisher_remote_item_channel_publisher_id ON channel_publisher_remote_item(channel_publisher_id); CREATE INDEX idx_channel_publisher_remote_item_medium_id ON channel_publisher_remote_item(medium_id); +CREATE INDEX idx_channel_publisher_remote_item_feed_guid ON channel_publisher_remote_item(feed_guid); +CREATE INDEX idx_channel_publisher_remote_item_feed_url ON channel_publisher_remote_item(feed_url); +CREATE INDEX idx_channel_publisher_remote_item_item_guid ON channel_publisher_remote_item(item_guid); --** CHANNEL > REMOTE ITEM @@ -405,6 +413,9 @@ CREATE TABLE channel_remote_item ( CREATE INDEX idx_channel_remote_item_channel_id ON channel_remote_item(channel_id); CREATE INDEX idx_channel_remote_item_medium_id ON channel_remote_item(medium_id); +CREATE INDEX idx_channel_remote_item_feed_guid ON channel_remote_item(feed_guid); +CREATE INDEX idx_channel_remote_item_feed_url ON channel_remote_item(feed_url); +CREATE INDEX idx_channel_remote_item_item_guid ON channel_remote_item(item_guid); --** CHANNEL > SEASON @@ -539,7 +550,7 @@ INSERT INTO item_itunes_episode_type (itunes_episode_type) VALUES ('full'), ('tr CREATE TABLE item_about ( id SERIAL PRIMARY KEY, - item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + item_id INTEGER NOT NULL UNIQUE REFERENCES item(id) ON DELETE CASCADE, duration media_player_time, -- <itunes:duration> explicit BOOLEAN, -- <itunes:explicit> website_link_url varchar_url, -- <link> @@ -554,7 +565,7 @@ CREATE INDEX idx_item_about_item_itunes_episode_type_id ON item_about(item_itune -- <item> -> <podcast:chapters> CREATE TABLE item_chapters_feed ( id SERIAL PRIMARY KEY, - item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + item_id INTEGER NOT NULL UNIQUE REFERENCES item(id) ON DELETE CASCADE, url varchar_url NOT NULL, type varchar_short NOT NULL ); @@ -567,7 +578,7 @@ CREATE INDEX idx_item_chapters_feed_item_id ON item_chapters_feed(item_id); CREATE TABLE item_chapters_feed_log ( id SERIAL PRIMARY KEY, - item_chapters_feed_id INTEGER NOT NULL REFERENCES item_chapters_feed(id) ON DELETE CASCADE, + item_chapters_feed_id INTEGER NOT NULL UNIQUE REFERENCES item_chapters_feed(id) ON DELETE CASCADE, last_http_status INTEGER, last_good_http_status_time server_time, last_finished_parse_time server_time, @@ -598,7 +609,7 @@ CREATE INDEX idx_item_chapter_item_chapters_feed_id ON item_chapter(item_chapter -- <item> -> <podcast:chapters> -> chapter items correspond with jsonChapters.md example file CREATE TABLE item_chapter_location ( id SERIAL PRIMARY KEY, - item_chapter_id INTEGER NOT NULL REFERENCES item_chapter(id) ON DELETE CASCADE, + item_chapter_id INTEGER NOT NULL UNIQUE REFERENCES item_chapter(id) ON DELETE CASCADE, geo varchar_normal, osm varchar_normal, CHECK (geo IS NOT NULL OR osm IS NOT NULL), @@ -612,7 +623,7 @@ CREATE INDEX idx_item_chapter_location_item_chapter_id ON item_chapter_location( -- <item> -> <podcast:chat> CREATE TABLE item_chat ( id SERIAL PRIMARY KEY, - item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + item_id INTEGER NOT NULL UNIQUE REFERENCES item(id) ON DELETE CASCADE, server varchar_fqdn NOT NULL, protocol varchar_short NOT NULL, account_id varchar_normal, @@ -638,8 +649,7 @@ CREATE INDEX idx_item_content_link_item_id ON item_content_link(item_id); -- <item> -> <description> AND possibly other tags that contain a description CREATE TABLE item_description ( id SERIAL PRIMARY KEY, - item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, - UNIQUE (item_id), + item_id INTEGER NOT NULL UNIQUE REFERENCES item(id) ON DELETE CASCADE, value varchar_long NOT NULL ); @@ -679,7 +689,7 @@ CREATE INDEX idx_item_enclosure_source_item_id ON item_enclosure_source(item_enc -- <item> -> <podcast:alternateEnclosure> -> <podcast:integrity> CREATE TABLE item_enclosure_integrity ( id SERIAL PRIMARY KEY, - item_enclosure_id INTEGER NOT NULL REFERENCES item_enclosure_source(id) ON DELETE CASCADE, + item_enclosure_id INTEGER NOT NULL UNIQUE REFERENCES item_enclosure_source(id) ON DELETE CASCADE, type TEXT NOT NULL CHECK (type IN ('sri', 'pgp-signature')), value varchar_long NOT NULL ); @@ -720,8 +730,7 @@ CREATE INDEX idx_item_image_item_id ON item_image(item_id); -- <item> -> <podcast:license> CREATE TABLE item_license ( id SERIAL PRIMARY KEY, - item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, - UNIQUE (item_id), + item_id INTEGER NOT NULL UNIQUE REFERENCES item(id) ON DELETE CASCADE, identifier varchar_normal NOT NULL, url varchar_url ); @@ -733,7 +742,7 @@ CREATE INDEX idx_item_license_item_id ON item_license(item_id); -- <item> -> <podcast:location> CREATE TABLE item_location ( id SERIAL PRIMARY KEY, - item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + item_id INTEGER NOT NULL UNIQUE REFERENCES item(id) ON DELETE CASCADE, geo varchar_normal, osm varchar_normal, CHECK (geo IS NOT NULL OR osm IS NOT NULL), @@ -775,7 +784,7 @@ CREATE INDEX idx_item_season_item_id ON item_season(item_id); -- <item> -> <podcast:season> -> <podcast:episode> CREATE TABLE item_season_episode ( id SERIAL PRIMARY KEY, - item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + item_id INTEGER NOT NULL UNIQUE REFERENCES item(id) ON DELETE CASCADE, display varchar_short, number FLOAT NOT NULL ); @@ -886,7 +895,7 @@ CREATE INDEX idx_item_value_time_split_item_value_id ON item_value_time_split(it -- <item> -> <podcast:value> -> <podcast:valueTimeSplit> -> <podcast:remoteItem> CREATE TABLE item_value_time_split_remote_item ( id SERIAL PRIMARY KEY, - item_value_time_split_id INTEGER NOT NULL REFERENCES item_value_time_split(id) ON DELETE CASCADE, + item_value_time_split_id INTEGER NOT NULL UNIQUE REFERENCES item_value_time_split(id) ON DELETE CASCADE, feed_guid UUID NOT NULL, feed_url varchar_url, item_guid varchar_uri, @@ -894,6 +903,9 @@ CREATE TABLE item_value_time_split_remote_item ( ); CREATE INDEX idx_item_value_time_split_remote_item_item_value_time_split_id ON item_value_time_split_remote_item(item_value_time_split_id); +CREATE INDEX idx_item_value_time_split_remote_item_feed_guid ON item_value_time_split_remote_item(feed_guid); +CREATE INDEX idx_item_value_time_split_remote_item_feed_url ON item_value_time_split_remote_item(feed_url); +CREATE INDEX idx_item_value_time_split_remote_item_item_guid ON item_value_time_split_remote_item(item_guid); --** ITEM > VALUE > TIME SPLIT > VALUE RECIPEINT @@ -929,7 +941,7 @@ INSERT INTO live_item_status (status) VALUES ('pending'), ('live'), ('ended'); -- <channel> -> <podcast:liveItem> CREATE TABLE live_item ( id SERIAL PRIMARY KEY, - item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + item_id INTEGER NOT NULL UNIQUE REFERENCES item(id) ON DELETE CASCADE, live_item_status_id INTEGER NOT NULL REFERENCES live_item_status(id), start_time TIMESTAMPTZ NOT NULL, end_time TIMESTAMPTZ, diff --git a/database/migrations/0001_init_podcasting_20_database.sql b/database/migrations/0001_init_podcasting_20_database.sql index b46aa70..bdbe726 100644 --- a/database/migrations/0001_init_podcasting_20_database.sql +++ b/database/migrations/0001_init_podcasting_20_database.sql @@ -110,7 +110,7 @@ EXECUTE FUNCTION set_updated_at_field(); CREATE TABLE feed_log ( id SERIAL PRIMARY KEY, - feed_id INTEGER NOT NULL REFERENCES feed(id) ON DELETE CASCADE, + feed_id INTEGER NOT NULL UNIQUE REFERENCES feed(id) ON DELETE CASCADE, last_http_status INTEGER, last_good_http_status_time server_time, last_finished_parse_time server_time, @@ -126,7 +126,7 @@ CREATE TABLE channel ( id SERIAL PRIMARY KEY, id_text short_id_v2 UNIQUE NOT NULL, slug varchar_slug, - feed_id INTEGER NOT NULL REFERENCES feed(id) ON DELETE CASCADE, + feed_id INTEGER NOT NULL UNIQUE REFERENCES feed(id) ON DELETE CASCADE, podcast_index_id INTEGER UNIQUE NOT NULL, podcast_guid UUID UNIQUE, -- <podcast:guid> title varchar_normal, @@ -137,6 +137,10 @@ CREATE TABLE channel ( -- from the Podcast Index API. has_podcast_index_value BOOLEAN DEFAULT FALSE, + -- this column is used for optimization purposes to determine if all of the items + -- for a channel need to have their value time split remote items parsed. + has_value_time_splits BOOLEAN DEFAULT FALSE, + -- hidden items are no longer available in the rss feed, but are still in the database. hidden BOOLEAN DEFAULT FALSE, -- markedForDeletion items are no longer available in the rss feed, and may be able to be deleted. @@ -163,7 +167,7 @@ INSERT INTO channel_itunes_type (itunes_type) VALUES ('episodic'), ('serial'); -- various <channel> child data from multiple tags CREATE TABLE channel_about ( id SERIAL PRIMARY KEY, - channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, + channel_id INTEGER NOT NULL UNIQUE REFERENCES channel(id) ON DELETE CASCADE, author varchar_normal, -- <itunes:author> and <author> episode_count INTEGER, -- aggregated count for convenience explicit BOOLEAN, -- <itunes:explicit> @@ -192,7 +196,7 @@ CREATE INDEX idx_channel_category_parent_id ON channel_category(parent_id); -- <channel> -> <podcast:chat> CREATE TABLE channel_chat ( id SERIAL PRIMARY KEY, - channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, + channel_id INTEGER NOT NULL UNIQUE REFERENCES channel(id) ON DELETE CASCADE, server varchar_fqdn NOT NULL, protocol varchar_short NOT NULL, account_id varchar_normal, @@ -206,8 +210,7 @@ CREATE INDEX idx_channel_chat_channel_id ON channel_chat(channel_id); -- <channel> -> <description> AND possibly other tags that contain a description CREATE TABLE channel_description ( id SERIAL PRIMARY KEY, - channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, - UNIQUE (channel_id), + channel_id INTEGER NOT NULL UNIQUE REFERENCES channel(id) ON DELETE CASCADE, value varchar_long NOT NULL ); @@ -259,8 +262,7 @@ CREATE INDEX idx_channel_internal_settings_channel_id ON channel_internal_settin -- <channel> -> <podcast:license> CREATE TABLE channel_license ( id SERIAL PRIMARY KEY, - channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, - UNIQUE (channel_id), + channel_id INTEGER NOT NULL UNIQUE REFERENCES channel(id) ON DELETE CASCADE, identifier varchar_normal NOT NULL, url varchar_url ); @@ -272,7 +274,7 @@ CREATE INDEX idx_channel_license_channel_id ON channel_license(channel_id); -- <channel> -> <podcast:location> CREATE TABLE channel_location ( id SERIAL PRIMARY KEY, - channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE, + channel_id INTEGER NOT NULL UNIQUE REFERENCES channel(id) ON DELETE CASCADE, geo varchar_normal, osm varchar_normal, CHECK (geo IS NOT NULL OR osm IS NOT NULL), @@ -301,7 +303,7 @@ CREATE INDEX idx_channel_person_channel_id ON channel_person(channel_id); -- <channel> -> <podcast:podroll> CREATE TABLE channel_podroll ( id SERIAL PRIMARY KEY, - channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE + channel_id INTEGER NOT NULL UNIQUE REFERENCES channel(id) ON DELETE CASCADE ); CREATE INDEX idx_channel_podroll_channel_id ON channel_podroll(channel_id); @@ -321,13 +323,16 @@ CREATE TABLE channel_podroll_remote_item ( CREATE INDEX idx_channel_podroll_remote_item_channel_podroll_id ON channel_podroll_remote_item(channel_podroll_id); CREATE INDEX idx_channel_podroll_remote_item_medium_id ON channel_podroll_remote_item(medium_id); +CREATE INDEX idx_channel_podroll_remote_item_feed_guid ON channel_podroll_remote_item(feed_guid); +CREATE INDEX idx_channel_podroll_remote_item_feed_url ON channel_podroll_remote_item(feed_url); +CREATE INDEX idx_channel_podroll_remote_item_item_guid ON channel_podroll_remote_item(item_guid); --** CHANNEL > PUBLISHER -- <channel> -> <podcast:publisher> CREATE TABLE channel_publisher ( id SERIAL PRIMARY KEY, - channel_id INTEGER NOT NULL REFERENCES channel(id) ON DELETE CASCADE + channel_id INTEGER NOT NULL UNIQUE REFERENCES channel(id) ON DELETE CASCADE ); CREATE INDEX idx_channel_publisher_channel_id ON channel_publisher(channel_id); @@ -337,7 +342,7 @@ CREATE INDEX idx_channel_publisher_channel_id ON channel_publisher(channel_id); -- <channel> -> <podcast:publisher> -> <podcast:remoteItem> CREATE TABLE channel_publisher_remote_item ( id SERIAL PRIMARY KEY, - channel_publisher_id INTEGER NOT NULL REFERENCES channel_publisher(id) ON DELETE CASCADE, + channel_publisher_id INTEGER NOT NULL UNIQUE REFERENCES channel_publisher(id) ON DELETE CASCADE, feed_guid UUID NOT NULL, feed_url varchar_url, item_guid varchar_uri, @@ -347,6 +352,9 @@ CREATE TABLE channel_publisher_remote_item ( CREATE INDEX idx_channel_publisher_remote_item_channel_publisher_id ON channel_publisher_remote_item(channel_publisher_id); CREATE INDEX idx_channel_publisher_remote_item_medium_id ON channel_publisher_remote_item(medium_id); +CREATE INDEX idx_channel_publisher_remote_item_feed_guid ON channel_publisher_remote_item(feed_guid); +CREATE INDEX idx_channel_publisher_remote_item_feed_url ON channel_publisher_remote_item(feed_url); +CREATE INDEX idx_channel_publisher_remote_item_item_guid ON channel_publisher_remote_item(item_guid); --** CHANNEL > REMOTE ITEM @@ -366,6 +374,9 @@ CREATE TABLE channel_remote_item ( CREATE INDEX idx_channel_remote_item_channel_id ON channel_remote_item(channel_id); CREATE INDEX idx_channel_remote_item_medium_id ON channel_remote_item(medium_id); +CREATE INDEX idx_channel_remote_item_feed_guid ON channel_remote_item(feed_guid); +CREATE INDEX idx_channel_remote_item_feed_url ON channel_remote_item(feed_url); +CREATE INDEX idx_channel_remote_item_item_guid ON channel_remote_item(item_guid); --** CHANNEL > SEASON @@ -500,7 +511,7 @@ INSERT INTO item_itunes_episode_type (itunes_episode_type) VALUES ('full'), ('tr CREATE TABLE item_about ( id SERIAL PRIMARY KEY, - item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + item_id INTEGER NOT NULL UNIQUE REFERENCES item(id) ON DELETE CASCADE, duration media_player_time, -- <itunes:duration> explicit BOOLEAN, -- <itunes:explicit> website_link_url varchar_url, -- <link> @@ -515,7 +526,7 @@ CREATE INDEX idx_item_about_item_itunes_episode_type_id ON item_about(item_itune -- <item> -> <podcast:chapters> CREATE TABLE item_chapters_feed ( id SERIAL PRIMARY KEY, - item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + item_id INTEGER NOT NULL UNIQUE REFERENCES item(id) ON DELETE CASCADE, url varchar_url NOT NULL, type varchar_short NOT NULL ); @@ -528,7 +539,7 @@ CREATE INDEX idx_item_chapters_feed_item_id ON item_chapters_feed(item_id); CREATE TABLE item_chapters_feed_log ( id SERIAL PRIMARY KEY, - item_chapters_feed_id INTEGER NOT NULL REFERENCES item_chapters_feed(id) ON DELETE CASCADE, + item_chapters_feed_id INTEGER NOT NULL UNIQUE REFERENCES item_chapters_feed(id) ON DELETE CASCADE, last_http_status INTEGER, last_good_http_status_time server_time, last_finished_parse_time server_time, @@ -559,7 +570,7 @@ CREATE INDEX idx_item_chapter_item_chapters_feed_id ON item_chapter(item_chapter -- <item> -> <podcast:chapters> -> chapter items correspond with jsonChapters.md example file CREATE TABLE item_chapter_location ( id SERIAL PRIMARY KEY, - item_chapter_id INTEGER NOT NULL REFERENCES item_chapter(id) ON DELETE CASCADE, + item_chapter_id INTEGER NOT NULL UNIQUE REFERENCES item_chapter(id) ON DELETE CASCADE, geo varchar_normal, osm varchar_normal, CHECK (geo IS NOT NULL OR osm IS NOT NULL), @@ -573,7 +584,7 @@ CREATE INDEX idx_item_chapter_location_item_chapter_id ON item_chapter_location( -- <item> -> <podcast:chat> CREATE TABLE item_chat ( id SERIAL PRIMARY KEY, - item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + item_id INTEGER NOT NULL UNIQUE REFERENCES item(id) ON DELETE CASCADE, server varchar_fqdn NOT NULL, protocol varchar_short NOT NULL, account_id varchar_normal, @@ -599,8 +610,7 @@ CREATE INDEX idx_item_content_link_item_id ON item_content_link(item_id); -- <item> -> <description> AND possibly other tags that contain a description CREATE TABLE item_description ( id SERIAL PRIMARY KEY, - item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, - UNIQUE (item_id), + item_id INTEGER NOT NULL UNIQUE REFERENCES item(id) ON DELETE CASCADE, value varchar_long NOT NULL ); @@ -640,7 +650,7 @@ CREATE INDEX idx_item_enclosure_source_item_id ON item_enclosure_source(item_enc -- <item> -> <podcast:alternateEnclosure> -> <podcast:integrity> CREATE TABLE item_enclosure_integrity ( id SERIAL PRIMARY KEY, - item_enclosure_id INTEGER NOT NULL REFERENCES item_enclosure_source(id) ON DELETE CASCADE, + item_enclosure_id INTEGER NOT NULL UNIQUE REFERENCES item_enclosure_source(id) ON DELETE CASCADE, type TEXT NOT NULL CHECK (type IN ('sri', 'pgp-signature')), value varchar_long NOT NULL ); @@ -681,8 +691,7 @@ CREATE INDEX idx_item_image_item_id ON item_image(item_id); -- <item> -> <podcast:license> CREATE TABLE item_license ( id SERIAL PRIMARY KEY, - item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, - UNIQUE (item_id), + item_id INTEGER NOT NULL UNIQUE REFERENCES item(id) ON DELETE CASCADE, identifier varchar_normal NOT NULL, url varchar_url ); @@ -694,7 +703,7 @@ CREATE INDEX idx_item_license_item_id ON item_license(item_id); -- <item> -> <podcast:location> CREATE TABLE item_location ( id SERIAL PRIMARY KEY, - item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + item_id INTEGER NOT NULL UNIQUE REFERENCES item(id) ON DELETE CASCADE, geo varchar_normal, osm varchar_normal, CHECK (geo IS NOT NULL OR osm IS NOT NULL), @@ -736,7 +745,7 @@ CREATE INDEX idx_item_season_item_id ON item_season(item_id); -- <item> -> <podcast:season> -> <podcast:episode> CREATE TABLE item_season_episode ( id SERIAL PRIMARY KEY, - item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + item_id INTEGER NOT NULL UNIQUE REFERENCES item(id) ON DELETE CASCADE, display varchar_short, number FLOAT NOT NULL ); @@ -847,7 +856,7 @@ CREATE INDEX idx_item_value_time_split_item_value_id ON item_value_time_split(it -- <item> -> <podcast:value> -> <podcast:valueTimeSplit> -> <podcast:remoteItem> CREATE TABLE item_value_time_split_remote_item ( id SERIAL PRIMARY KEY, - item_value_time_split_id INTEGER NOT NULL REFERENCES item_value_time_split(id) ON DELETE CASCADE, + item_value_time_split_id INTEGER NOT NULL UNIQUE REFERENCES item_value_time_split(id) ON DELETE CASCADE, feed_guid UUID NOT NULL, feed_url varchar_url, item_guid varchar_uri, @@ -855,6 +864,9 @@ CREATE TABLE item_value_time_split_remote_item ( ); CREATE INDEX idx_item_value_time_split_remote_item_item_value_time_split_id ON item_value_time_split_remote_item(item_value_time_split_id); +CREATE INDEX idx_item_value_time_split_remote_item_feed_guid ON item_value_time_split_remote_item(feed_guid); +CREATE INDEX idx_item_value_time_split_remote_item_feed_url ON item_value_time_split_remote_item(feed_url); +CREATE INDEX idx_item_value_time_split_remote_item_item_guid ON item_value_time_split_remote_item(item_guid); --** ITEM > VALUE > TIME SPLIT > VALUE RECIPEINT @@ -890,7 +902,7 @@ INSERT INTO live_item_status (status) VALUES ('pending'), ('live'), ('ended'); -- <channel> -> <podcast:liveItem> CREATE TABLE live_item ( id SERIAL PRIMARY KEY, - item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + item_id INTEGER NOT NULL UNIQUE REFERENCES item(id) ON DELETE CASCADE, live_item_status_id INTEGER NOT NULL REFERENCES live_item_status(id), start_time TIMESTAMPTZ NOT NULL, end_time TIMESTAMPTZ,