diff --git a/src/migrations/1734100000000-CascadeDeleteRepliesAndQuotes.ts b/src/migrations/1734100000000-CascadeDeleteRepliesAndQuotes.ts deleted file mode 100644 index 48c1094..0000000 --- a/src/migrations/1734100000000-CascadeDeleteRepliesAndQuotes.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class CascadeDeleteRepliesAndQuotes1734100000000 implements MigrationInterface { - name = 'CascadeDeleteRepliesAndQuotes1734100000000'; - - public async up(query_runner: QueryRunner): Promise { - // Create a function that cascades delete for reply and quote tweets - await query_runner.query(` - CREATE OR REPLACE FUNCTION cascade_delete_child_tweets() - RETURNS TRIGGER AS $$ - BEGIN - -- Delete all reply tweets when a parent tweet is deleted - DELETE FROM tweets - WHERE tweet_id IN ( - SELECT reply_tweet_id - FROM tweet_replies - WHERE original_tweet_id = OLD.tweet_id - ); - - -- Delete all quote tweets when a parent tweet is deleted - DELETE FROM tweets - WHERE tweet_id IN ( - SELECT quote_tweet_id - FROM tweet_quotes - WHERE original_tweet_id = OLD.tweet_id - ); - - RETURN OLD; - END; - $$ LANGUAGE plpgsql; - `); - - // Create trigger that runs BEFORE a tweet is deleted - // This ensures the relationships still exist when we query them - await query_runner.query(` - CREATE TRIGGER trigger_cascade_delete_child_tweets - BEFORE DELETE ON tweets - FOR EACH ROW - EXECUTE FUNCTION cascade_delete_child_tweets(); - `); - } - - public async down(query_runner: QueryRunner): Promise { - // Drop the trigger first - await query_runner.query(` - DROP TRIGGER IF EXISTS trigger_cascade_delete_child_tweets ON tweets; - `); - - // Drop the function - await query_runner.query(` - DROP FUNCTION IF EXISTS cascade_delete_child_tweets(); - `); - } -} diff --git a/src/migrations/1734100000002-EnhanceCascadeDeleteWithHashtagsAndES.ts b/src/migrations/1734100000002-EnhanceCascadeDeleteWithHashtagsAndES.ts deleted file mode 100644 index 4609516..0000000 --- a/src/migrations/1734100000002-EnhanceCascadeDeleteWithHashtagsAndES.ts +++ /dev/null @@ -1,137 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class EnhanceCascadeDeleteWithHashtagsAndES1734100000002 implements MigrationInterface { - name = 'EnhanceCascadeDeleteWithHashtagsAndES1736100000002'; - - public async up(query_runner: QueryRunner): Promise { - // Create a table to track deleted tweets for Elasticsearch cleanup - await query_runner.query(` - CREATE TABLE IF NOT EXISTS deleted_tweets_log ( - tweet_id uuid NOT NULL, - content text, - deleted_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), - PRIMARY KEY (tweet_id) - ) - `); - - // Create index for efficient cleanup queries - await query_runner.query(` - CREATE INDEX IF NOT EXISTS idx_deleted_tweets_deleted_at - ON deleted_tweets_log(deleted_at) - `); - - // Drop the old trigger and function - await query_runner.query(` - DROP TRIGGER IF EXISTS trigger_cascade_delete_child_tweets ON tweets; - `); - await query_runner.query(` - DROP FUNCTION IF EXISTS cascade_delete_child_tweets(); - `); - - // Create function that logs deletions with content - await query_runner.query(` - CREATE OR REPLACE FUNCTION cascade_delete_child_tweets() - RETURNS TRIGGER AS $$ - BEGIN - -- Log all child tweets (replies and quotes) with their content - INSERT INTO deleted_tweets_log (tweet_id, content) - SELECT tweet_id, content - FROM tweets - WHERE tweet_id IN ( - SELECT reply_tweet_id - FROM tweet_replies - WHERE original_tweet_id = OLD.tweet_id - - UNION - - SELECT quote_tweet_id - FROM tweet_quotes - WHERE original_tweet_id = OLD.tweet_id - ) - ON CONFLICT (tweet_id) DO NOTHING; - - -- Log the main tweet being deleted with its content - INSERT INTO deleted_tweets_log (tweet_id, content) - VALUES (OLD.tweet_id, OLD.content) - ON CONFLICT (tweet_id) DO NOTHING; - - -- Delete all reply tweets when a parent tweet is deleted - DELETE FROM tweets - WHERE tweet_id IN ( - SELECT reply_tweet_id - FROM tweet_replies - WHERE original_tweet_id = OLD.tweet_id - ); - - -- Delete all quote tweets when a parent tweet is deleted - DELETE FROM tweets - WHERE tweet_id IN ( - SELECT quote_tweet_id - FROM tweet_quotes - WHERE original_tweet_id = OLD.tweet_id - ); - - RETURN OLD; - END; - $$ LANGUAGE plpgsql; - `); - - // Recreate the trigger - await query_runner.query(` - CREATE TRIGGER trigger_cascade_delete_child_tweets - BEFORE DELETE ON tweets - FOR EACH ROW - EXECUTE FUNCTION cascade_delete_child_tweets(); - `); - } - - public async down(query_runner: QueryRunner): Promise { - // Drop the enhanced trigger and function - await query_runner.query(` - DROP TRIGGER IF EXISTS trigger_cascade_delete_child_tweets ON tweets; - `); - await query_runner.query(` - DROP FUNCTION IF EXISTS cascade_delete_child_tweets(); - `); - - // Restore the original simple function - await query_runner.query(` - CREATE OR REPLACE FUNCTION cascade_delete_child_tweets() - RETURNS TRIGGER AS $$ - BEGIN - DELETE FROM tweets - WHERE tweet_id IN ( - SELECT reply_tweet_id - FROM tweet_replies - WHERE original_tweet_id = OLD.tweet_id - ); - - DELETE FROM tweets - WHERE tweet_id IN ( - SELECT quote_tweet_id - FROM tweet_quotes - WHERE original_tweet_id = OLD.tweet_id - ); - - RETURN OLD; - END; - $$ LANGUAGE plpgsql; - `); - - // Recreate the original trigger - await query_runner.query(` - CREATE TRIGGER trigger_cascade_delete_child_tweets - BEFORE DELETE ON tweets - FOR EACH ROW - EXECUTE FUNCTION cascade_delete_child_tweets(); - `); - - // Drop the deleted tweets log table - await query_runner.query(` - DROP INDEX IF EXISTS idx_deleted_tweets_deleted_at; - `); - await query_runner.query(` - DROP TABLE IF EXISTS deleted_tweets_log; - `); - } -} diff --git a/src/migrations/1734100000003-AddIncrementViewsFunction.ts b/src/migrations/1734100000003-AddIncrementViewsFunction.ts deleted file mode 100644 index 4fe6aa0..0000000 --- a/src/migrations/1734100000003-AddIncrementViewsFunction.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddIncrementViewsFunction1734100000003 implements MigrationInterface { - name = 'AddIncrementViewsFunction1734100000003'; - - public async up(query_runner: QueryRunner): Promise { - // Create a function that increments tweet views atomically - await query_runner.query(` - CREATE OR REPLACE FUNCTION increment_tweet_view(p_tweet_id UUID) - RETURNS INTEGER AS $$ - DECLARE - v_new_count INTEGER; - BEGIN - UPDATE tweets - SET num_views = num_views + 1 - WHERE tweet_id = p_tweet_id - RETURNING num_views INTO v_new_count; - - RETURN COALESCE(v_new_count, 0); - END; - $$ LANGUAGE plpgsql; - `); - - // Create a function that increments multiple tweet views at once - await query_runner.query(` - CREATE OR REPLACE FUNCTION increment_tweet_views_batch(p_tweet_ids UUID[]) - RETURNS VOID AS $$ - BEGIN - UPDATE tweets - SET num_views = num_views + 1 - WHERE tweet_id = ANY(p_tweet_ids); - END; - $$ LANGUAGE plpgsql; - `); - - // Create an index on tweet_id if it doesn't exist for better performance - await query_runner.query(` - CREATE INDEX IF NOT EXISTS idx_tweets_tweet_id ON tweets(tweet_id); - `); - } - - public async down(query_runner: QueryRunner): Promise { - // Drop the functions - await query_runner.query(`DROP FUNCTION IF EXISTS increment_tweet_view(UUID);`); - await query_runner.query(`DROP FUNCTION IF EXISTS increment_tweet_views_batch(UUID[]);`); - - // Drop the index - await query_runner.query(`DROP INDEX IF EXISTS idx_tweets_tweet_id;`); - } -} diff --git a/src/migrations/1765447556136-mentions.ts b/src/migrations/1765447556136-mentions.ts deleted file mode 100644 index f38a66e..0000000 --- a/src/migrations/1765447556136-mentions.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class Mentions1765447556136 implements MigrationInterface { - name = 'Mentions1765447556136'; - - public async up(query_runner: QueryRunner): Promise { - // Check if the column already exists - const table = await query_runner.getTable('tweets'); - const mentions_column = table?.columns.find((col) => col.name === 'mentions'); - - if (!mentions_column) { - await query_runner.query( - `ALTER TABLE "tweets" ADD "mentions" text array NOT NULL DEFAULT '{}'` - ); - } - } - - public async down(query_runner: QueryRunner): Promise { - // Check if the column exists before dropping - const table = await query_runner.getTable('tweets'); - const mentions_column = table?.columns.find((col) => col.name === 'mentions'); - - if (mentions_column) { - await query_runner.query(`ALTER TABLE "tweets" DROP COLUMN "mentions"`); - } - } -} diff --git a/src/migrations/1765539117542-view_bookmarks.ts b/src/migrations/1765539117542-view_bookmarks.ts deleted file mode 100644 index 78c8cb0..0000000 --- a/src/migrations/1765539117542-view_bookmarks.ts +++ /dev/null @@ -1,191 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class ViewBookmarks1765539117542 implements MigrationInterface { - name = 'ViewBookmarks1765539117542'; - - public async up(query_runner: QueryRunner): Promise { - await query_runner.query( - `DELETE FROM "typeorm_metadata" WHERE "type" = $1 AND "name" = $2 AND "schema" = $3`, - ['VIEW', 'user_posts_view', 'public'] - ); - await query_runner.query(`DROP VIEW "user_posts_view"`); - await query_runner.query(`CREATE VIEW "user_posts_view" AS - SELECT - t.tweet_id::text AS id, - t.user_id AS profile_user_id, - t.user_id AS tweet_author_id, - t.tweet_id, - NULL::uuid AS repost_id, - 'tweet' AS post_type, - t.created_at AS post_date, - t.type::text AS type, - t.content, - t.images, - t.videos, - t.num_likes, - t.num_reposts, - t.num_views, - t.num_quotes, - t.num_replies, - t.num_bookmarks, - t.created_at, - t.updated_at, - u.username, - u.name, - u.followers, - u.following, - u.avatar_url, - u.cover_url, - u.verified, - u.bio, - NULL::text AS reposted_by_name, - COALESCE(tq.original_tweet_id, trep.original_tweet_id) AS parent_id, - trep.conversation_id AS conversation_id - FROM tweets t - INNER JOIN "user" u ON t.user_id = u.id - LEFT JOIN tweet_quotes tq ON t.tweet_id = tq.quote_tweet_id - LEFT JOIN tweet_replies trep ON t.tweet_id = trep.reply_tweet_id - - UNION ALL - - SELECT - (tr.tweet_id::text || '_' || tr.user_id::text) AS id, - tr.user_id AS profile_user_id, - t.user_id AS tweet_author_id, - tr.tweet_id, - tr.tweet_id AS repost_id, - t.type::text AS post_type, - tr.created_at AS post_date, - 'repost' AS type, - t.content, - t.images, - t.videos, - t.num_likes, - t.num_reposts, - t.num_views, - t.num_quotes, - t.num_replies, - t.num_bookmarks, - t.created_at, - t.updated_at, - u.username, - u.name, - u.followers, - u.following, - u.avatar_url, - u.cover_url, - u.verified, - u.bio, - reposter.name AS reposted_by_name, - COALESCE(tq.original_tweet_id, trep.original_tweet_id) AS parent_id, - trep.conversation_id AS conversation_id - - FROM tweet_reposts tr - INNER JOIN tweets t ON tr.tweet_id = t.tweet_id - INNER JOIN "user" u ON t.user_id = u.id - INNER JOIN "user" reposter ON tr.user_id = reposter.id - LEFT JOIN tweet_quotes tq ON t.tweet_id = tq.quote_tweet_id - LEFT JOIN tweet_replies trep ON t.tweet_id = trep.reply_tweet_id - `); - await query_runner.query( - `INSERT INTO "typeorm_metadata"("database", "schema", "table", "type", "name", "value") VALUES (DEFAULT, $1, DEFAULT, $2, $3, $4)`, - [ - 'public', - 'VIEW', - 'user_posts_view', - 'SELECT \n t.tweet_id::text AS id,\n t.user_id AS profile_user_id,\n t.user_id AS tweet_author_id,\n t.tweet_id,\n NULL::uuid AS repost_id,\n \'tweet\' AS post_type,\n t.created_at AS post_date,\n t.type::text AS type,\n t.content,\n t.images,\n t.videos,\n t.num_likes,\n t.num_reposts,\n t.num_views,\n t.num_quotes,\n t.num_replies,\n t.num_bookmarks,\n t.created_at,\n t.updated_at,\n u.username,\n u.name,\n u.followers,\n u.following,\n u.avatar_url,\n u.cover_url,\n u.verified,\n u.bio,\n NULL::text AS reposted_by_name,\n COALESCE(tq.original_tweet_id, trep.original_tweet_id) AS parent_id,\n trep.conversation_id AS conversation_id\n FROM tweets t\n INNER JOIN "user" u ON t.user_id = u.id\n LEFT JOIN tweet_quotes tq ON t.tweet_id = tq.quote_tweet_id\n LEFT JOIN tweet_replies trep ON t.tweet_id = trep.reply_tweet_id\n \n UNION ALL\n \n SELECT \n (tr.tweet_id::text || \'_\' || tr.user_id::text) AS id,\n tr.user_id AS profile_user_id,\n t.user_id AS tweet_author_id,\n tr.tweet_id,\n tr.tweet_id AS repost_id,\n t.type::text AS post_type,\n tr.created_at AS post_date,\n \'repost\' AS type,\n t.content,\n t.images,\n t.videos,\n t.num_likes,\n t.num_reposts,\n t.num_views,\n t.num_quotes,\n t.num_replies,\n t.num_bookmarks,\n t.created_at,\n t.updated_at,\n u.username,\n u.name,\n u.followers,\n u.following,\n u.avatar_url,\n u.cover_url,\n u.verified,\n u.bio,\n reposter.name AS reposted_by_name,\n COALESCE(tq.original_tweet_id, trep.original_tweet_id) AS parent_id,\n trep.conversation_id AS conversation_id\n\n FROM tweet_reposts tr\n INNER JOIN tweets t ON tr.tweet_id = t.tweet_id\n INNER JOIN "user" u ON t.user_id = u.id\n INNER JOIN "user" reposter ON tr.user_id = reposter.id\n LEFT JOIN tweet_quotes tq ON t.tweet_id = tq.quote_tweet_id\n LEFT JOIN tweet_replies trep ON t.tweet_id = trep.reply_tweet_id', - ] - ); - } - - public async down(query_runner: QueryRunner): Promise { - await query_runner.query( - `DELETE FROM "typeorm_metadata" WHERE "type" = $1 AND "name" = $2 AND "schema" = $3`, - ['VIEW', 'user_posts_view', 'public'] - ); - await query_runner.query(`DROP VIEW "user_posts_view"`); - await query_runner.query(`CREATE VIEW "user_posts_view" AS SELECT - t.tweet_id::text AS id, - t.user_id AS profile_user_id, - t.user_id AS tweet_author_id, - t.tweet_id, - NULL::uuid AS repost_id, - 'tweet' AS post_type, - t.created_at AS post_date, - t.type::text AS type, - t.content, - t.images, - t.videos, - t.num_likes, - t.num_reposts, - t.num_views, - t.num_quotes, - t.num_replies, - t.created_at, - t.updated_at, - u.username, - u.name, - u.followers, - u.following, - u.avatar_url, - u.cover_url, - u.verified, - u.bio, - NULL::text AS reposted_by_name, - COALESCE(tq.original_tweet_id, trep.original_tweet_id) AS parent_id, - trep.conversation_id AS conversation_id - FROM tweets t - INNER JOIN "user" u ON t.user_id = u.id - LEFT JOIN tweet_quotes tq ON t.tweet_id = tq.quote_tweet_id - LEFT JOIN tweet_replies trep ON t.tweet_id = trep.reply_tweet_id - - UNION ALL - - SELECT - (tr.tweet_id::text || '_' || tr.user_id::text) AS id, - tr.user_id AS profile_user_id, - t.user_id AS tweet_author_id, - tr.tweet_id, - tr.tweet_id AS repost_id, - t.type::text AS post_type, - tr.created_at AS post_date, - 'repost' AS type, - t.content, - t.images, - t.videos, - t.num_likes, - t.num_reposts, - t.num_views, - t.num_quotes, - t.num_replies, - t.created_at, - t.updated_at, - u.username, - u.name, - u.followers, - u.following, - u.avatar_url, - u.cover_url, - u.verified, - u.bio, - reposter.name AS reposted_by_name, - COALESCE(tq.original_tweet_id, trep.original_tweet_id) AS parent_id, - trep.conversation_id AS conversation_id - - FROM tweet_reposts tr - INNER JOIN tweets t ON tr.tweet_id = t.tweet_id - INNER JOIN "user" u ON t.user_id = u.id - INNER JOIN "user" reposter ON tr.user_id = reposter.id - LEFT JOIN tweet_quotes tq ON t.tweet_id = tq.quote_tweet_id - LEFT JOIN tweet_replies trep ON t.tweet_id = trep.reply_tweet_id`); - await query_runner.query( - `INSERT INTO "typeorm_metadata"("database", "schema", "table", "type", "name", "value") VALUES (DEFAULT, $1, DEFAULT, $2, $3, $4)`, - [ - 'public', - 'VIEW', - 'user_posts_view', - 'SELECT \n t.tweet_id::text AS id,\n t.user_id AS profile_user_id,\n t.user_id AS tweet_author_id,\n t.tweet_id,\n NULL::uuid AS repost_id,\n \'tweet\' AS post_type,\n t.created_at AS post_date,\n t.type::text AS type,\n t.content,\n t.images,\n t.videos,\n t.num_likes,\n t.num_reposts,\n t.num_views,\n t.num_quotes,\n t.num_replies,\n t.created_at,\n t.updated_at,\n u.username,\n u.name,\n u.followers,\n u.following,\n u.avatar_url,\n u.cover_url,\n u.verified,\n u.bio,\n NULL::text AS reposted_by_name,\n COALESCE(tq.original_tweet_id, trep.original_tweet_id) AS parent_id,\n trep.conversation_id AS conversation_id\n FROM tweets t\n INNER JOIN "user" u ON t.user_id = u.id\n LEFT JOIN tweet_quotes tq ON t.tweet_id = tq.quote_tweet_id\n LEFT JOIN tweet_replies trep ON t.tweet_id = trep.reply_tweet_id\n \n UNION ALL\n \n SELECT \n (tr.tweet_id::text || \'_\' || tr.user_id::text) AS id,\n tr.user_id AS profile_user_id,\n t.user_id AS tweet_author_id,\n tr.tweet_id,\n tr.tweet_id AS repost_id,\n t.type::text AS post_type,\n tr.created_at AS post_date,\n \'repost\' AS type,\n t.content,\n t.images,\n t.videos,\n t.num_likes,\n t.num_reposts,\n t.num_views,\n t.num_quotes,\n t.num_replies,\n t.created_at,\n t.updated_at,\n u.username,\n u.name,\n u.followers,\n u.following,\n u.avatar_url,\n u.cover_url,\n u.verified,\n u.bio,\n reposter.name AS reposted_by_name,\n COALESCE(tq.original_tweet_id, trep.original_tweet_id) AS parent_id,\n trep.conversation_id AS conversation_id\n\n FROM tweet_reposts tr\n INNER JOIN tweets t ON tr.tweet_id = t.tweet_id\n INNER JOIN "user" u ON t.user_id = u.id\n INNER JOIN "user" reposter ON tr.user_id = reposter.id\n LEFT JOIN tweet_quotes tq ON t.tweet_id = tq.quote_tweet_id\n LEFT JOIN tweet_replies trep ON t.tweet_id = trep.reply_tweet_id', - ] - ); - } -} diff --git a/src/migrations/1765539749754-view_mentions.ts b/src/migrations/1765539749754-view_mentions.ts deleted file mode 100644 index 7213059..0000000 --- a/src/migrations/1765539749754-view_mentions.ts +++ /dev/null @@ -1,195 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class ViewMentions1765539749754 implements MigrationInterface { - name = 'ViewMentions1765539749754'; - - public async up(query_runner: QueryRunner): Promise { - await query_runner.query( - `DELETE FROM "typeorm_metadata" WHERE "type" = $1 AND "name" = $2 AND "schema" = $3`, - ['VIEW', 'user_posts_view', 'public'] - ); - await query_runner.query(`DROP VIEW "user_posts_view"`); - await query_runner.query(`CREATE VIEW "user_posts_view" AS - SELECT - t.tweet_id::text AS id, - t.user_id AS profile_user_id, - t.user_id AS tweet_author_id, - t.tweet_id, - NULL::uuid AS repost_id, - 'tweet' AS post_type, - t.created_at AS post_date, - t.type::text AS type, - t.content, - t.images, - t.videos, - t.num_likes, - t.num_reposts, - t.num_views, - t.num_quotes, - t.num_replies, - t.num_bookmarks, - t.mentions, - t.created_at, - t.updated_at, - u.username, - u.name, - u.followers, - u.following, - u.avatar_url, - u.cover_url, - u.verified, - u.bio, - NULL::text AS reposted_by_name, - COALESCE(tq.original_tweet_id, trep.original_tweet_id) AS parent_id, - trep.conversation_id AS conversation_id - FROM tweets t - INNER JOIN "user" u ON t.user_id = u.id - LEFT JOIN tweet_quotes tq ON t.tweet_id = tq.quote_tweet_id - LEFT JOIN tweet_replies trep ON t.tweet_id = trep.reply_tweet_id - - UNION ALL - - SELECT - (tr.tweet_id::text || '_' || tr.user_id::text) AS id, - tr.user_id AS profile_user_id, - t.user_id AS tweet_author_id, - tr.tweet_id, - tr.tweet_id AS repost_id, - t.type::text AS post_type, - tr.created_at AS post_date, - 'repost' AS type, - t.content, - t.images, - t.videos, - t.num_likes, - t.num_reposts, - t.num_views, - t.num_quotes, - t.num_replies, - t.num_bookmarks, - t.mentions, - t.created_at, - t.updated_at, - u.username, - u.name, - u.followers, - u.following, - u.avatar_url, - u.cover_url, - u.verified, - u.bio, - reposter.name AS reposted_by_name, - COALESCE(tq.original_tweet_id, trep.original_tweet_id) AS parent_id, - trep.conversation_id AS conversation_id - - FROM tweet_reposts tr - INNER JOIN tweets t ON tr.tweet_id = t.tweet_id - INNER JOIN "user" u ON t.user_id = u.id - INNER JOIN "user" reposter ON tr.user_id = reposter.id - LEFT JOIN tweet_quotes tq ON t.tweet_id = tq.quote_tweet_id - LEFT JOIN tweet_replies trep ON t.tweet_id = trep.reply_tweet_id - `); - await query_runner.query( - `INSERT INTO "typeorm_metadata"("database", "schema", "table", "type", "name", "value") VALUES (DEFAULT, $1, DEFAULT, $2, $3, $4)`, - [ - 'public', - 'VIEW', - 'user_posts_view', - 'SELECT \n t.tweet_id::text AS id,\n t.user_id AS profile_user_id,\n t.user_id AS tweet_author_id,\n t.tweet_id,\n NULL::uuid AS repost_id,\n \'tweet\' AS post_type,\n t.created_at AS post_date,\n t.type::text AS type,\n t.content,\n t.images,\n t.videos,\n t.num_likes,\n t.num_reposts,\n t.num_views,\n t.num_quotes,\n t.num_replies,\n t.num_bookmarks,\n t.mentions,\n t.created_at,\n t.updated_at,\n u.username,\n u.name,\n u.followers,\n u.following,\n u.avatar_url,\n u.cover_url,\n u.verified,\n u.bio,\n NULL::text AS reposted_by_name,\n COALESCE(tq.original_tweet_id, trep.original_tweet_id) AS parent_id,\n trep.conversation_id AS conversation_id\n FROM tweets t\n INNER JOIN "user" u ON t.user_id = u.id\n LEFT JOIN tweet_quotes tq ON t.tweet_id = tq.quote_tweet_id\n LEFT JOIN tweet_replies trep ON t.tweet_id = trep.reply_tweet_id\n \n UNION ALL\n \n SELECT \n (tr.tweet_id::text || \'_\' || tr.user_id::text) AS id,\n tr.user_id AS profile_user_id,\n t.user_id AS tweet_author_id,\n tr.tweet_id,\n tr.tweet_id AS repost_id,\n t.type::text AS post_type,\n tr.created_at AS post_date,\n \'repost\' AS type,\n t.content,\n t.images,\n t.videos,\n t.num_likes,\n t.num_reposts,\n t.num_views,\n t.num_quotes,\n t.num_replies,\n t.num_bookmarks,\n t.mentions,\n t.created_at,\n t.updated_at,\n u.username,\n u.name,\n u.followers,\n u.following,\n u.avatar_url,\n u.cover_url,\n u.verified,\n u.bio,\n reposter.name AS reposted_by_name,\n COALESCE(tq.original_tweet_id, trep.original_tweet_id) AS parent_id,\n trep.conversation_id AS conversation_id\n\n FROM tweet_reposts tr\n INNER JOIN tweets t ON tr.tweet_id = t.tweet_id\n INNER JOIN "user" u ON t.user_id = u.id\n INNER JOIN "user" reposter ON tr.user_id = reposter.id\n LEFT JOIN tweet_quotes tq ON t.tweet_id = tq.quote_tweet_id\n LEFT JOIN tweet_replies trep ON t.tweet_id = trep.reply_tweet_id', - ] - ); - } - - public async down(query_runner: QueryRunner): Promise { - await query_runner.query( - `DELETE FROM "typeorm_metadata" WHERE "type" = $1 AND "name" = $2 AND "schema" = $3`, - ['VIEW', 'user_posts_view', 'public'] - ); - await query_runner.query(`DROP VIEW "user_posts_view"`); - await query_runner.query(`CREATE VIEW "user_posts_view" AS SELECT - t.tweet_id::text AS id, - t.user_id AS profile_user_id, - t.user_id AS tweet_author_id, - t.tweet_id, - NULL::uuid AS repost_id, - 'tweet' AS post_type, - t.created_at AS post_date, - t.type::text AS type, - t.content, - t.images, - t.videos, - t.num_likes, - t.num_reposts, - t.num_views, - t.num_quotes, - t.num_replies, - t.num_bookmarks, - t.created_at, - t.updated_at, - u.username, - u.name, - u.followers, - u.following, - u.avatar_url, - u.cover_url, - u.verified, - u.bio, - NULL::text AS reposted_by_name, - COALESCE(tq.original_tweet_id, trep.original_tweet_id) AS parent_id, - trep.conversation_id AS conversation_id - FROM tweets t - INNER JOIN "user" u ON t.user_id = u.id - LEFT JOIN tweet_quotes tq ON t.tweet_id = tq.quote_tweet_id - LEFT JOIN tweet_replies trep ON t.tweet_id = trep.reply_tweet_id - - UNION ALL - - SELECT - (tr.tweet_id::text || '_' || tr.user_id::text) AS id, - tr.user_id AS profile_user_id, - t.user_id AS tweet_author_id, - tr.tweet_id, - tr.tweet_id AS repost_id, - t.type::text AS post_type, - tr.created_at AS post_date, - 'repost' AS type, - t.content, - t.images, - t.videos, - t.num_likes, - t.num_reposts, - t.num_views, - t.num_quotes, - t.num_replies, - t.num_bookmarks, - t.created_at, - t.updated_at, - u.username, - u.name, - u.followers, - u.following, - u.avatar_url, - u.cover_url, - u.verified, - u.bio, - reposter.name AS reposted_by_name, - COALESCE(tq.original_tweet_id, trep.original_tweet_id) AS parent_id, - trep.conversation_id AS conversation_id - - FROM tweet_reposts tr - INNER JOIN tweets t ON tr.tweet_id = t.tweet_id - INNER JOIN "user" u ON t.user_id = u.id - INNER JOIN "user" reposter ON tr.user_id = reposter.id - LEFT JOIN tweet_quotes tq ON t.tweet_id = tq.quote_tweet_id - LEFT JOIN tweet_replies trep ON t.tweet_id = trep.reply_tweet_id`); - await query_runner.query( - `INSERT INTO "typeorm_metadata"("database", "schema", "table", "type", "name", "value") VALUES (DEFAULT, $1, DEFAULT, $2, $3, $4)`, - [ - 'public', - 'VIEW', - 'user_posts_view', - 'SELECT \n t.tweet_id::text AS id,\n t.user_id AS profile_user_id,\n t.user_id AS tweet_author_id,\n t.tweet_id,\n NULL::uuid AS repost_id,\n \'tweet\' AS post_type,\n t.created_at AS post_date,\n t.type::text AS type,\n t.content,\n t.images,\n t.videos,\n t.num_likes,\n t.num_reposts,\n t.num_views,\n t.num_quotes,\n t.num_replies,\n t.num_bookmarks,\n t.created_at,\n t.updated_at,\n u.username,\n u.name,\n u.followers,\n u.following,\n u.avatar_url,\n u.cover_url,\n u.verified,\n u.bio,\n NULL::text AS reposted_by_name,\n COALESCE(tq.original_tweet_id, trep.original_tweet_id) AS parent_id,\n trep.conversation_id AS conversation_id\n FROM tweets t\n INNER JOIN "user" u ON t.user_id = u.id\n LEFT JOIN tweet_quotes tq ON t.tweet_id = tq.quote_tweet_id\n LEFT JOIN tweet_replies trep ON t.tweet_id = trep.reply_tweet_id\n \n UNION ALL\n \n SELECT \n (tr.tweet_id::text || \'_\' || tr.user_id::text) AS id,\n tr.user_id AS profile_user_id,\n t.user_id AS tweet_author_id,\n tr.tweet_id,\n tr.tweet_id AS repost_id,\n t.type::text AS post_type,\n tr.created_at AS post_date,\n \'repost\' AS type,\n t.content,\n t.images,\n t.videos,\n t.num_likes,\n t.num_reposts,\n t.num_views,\n t.num_quotes,\n t.num_replies,\n t.num_bookmarks,\n t.created_at,\n t.updated_at,\n u.username,\n u.name,\n u.followers,\n u.following,\n u.avatar_url,\n u.cover_url,\n u.verified,\n u.bio,\n reposter.name AS reposted_by_name,\n COALESCE(tq.original_tweet_id, trep.original_tweet_id) AS parent_id,\n trep.conversation_id AS conversation_id\n\n FROM tweet_reposts tr\n INNER JOIN tweets t ON tr.tweet_id = t.tweet_id\n INNER JOIN "user" u ON t.user_id = u.id\n INNER JOIN "user" reposter ON tr.user_id = reposter.id\n LEFT JOIN tweet_quotes tq ON t.tweet_id = tq.quote_tweet_id\n LEFT JOIN tweet_replies trep ON t.tweet_id = trep.reply_tweet_id', - ] - ); - } -} diff --git a/src/tweets/queries/get-posts-profile-view.query.ts b/src/tweets/queries/get-posts-profile-view.query.ts index 83b5046..2b96806 100644 --- a/src/tweets/queries/get-posts-profile-view.query.ts +++ b/src/tweets/queries/get-posts-profile-view.query.ts @@ -1,6 +1,6 @@ import { SelectQueryBuilder } from 'typeorm'; -export function getPostsByUserIdAlyaaQuery( +export function getPostsByUserIdProfileQuery( query: SelectQueryBuilder, user_id: string ): SelectQueryBuilder { @@ -40,7 +40,7 @@ export function getPostsByUserIdAlyaaQuery( .where('tweet.profile_user_id = :user_id', { user_id }); } -export function getPostsByUserIdAlyaaQueryWithoutView( +export function getPostsByUserIdProfileQueryWithoutView( query: SelectQueryBuilder, user_id: string ): SelectQueryBuilder { diff --git a/src/tweets/tweets.repository.ts b/src/tweets/tweets.repository.ts index 751040b..82e69b1 100644 --- a/src/tweets/tweets.repository.ts +++ b/src/tweets/tweets.repository.ts @@ -17,8 +17,8 @@ import { UserPostsView } from './entities/user-posts-view.entity'; import { TweetCategory } from './entities/tweet-category.entity'; import { tweet_fields_slect } from './queries/tweet-fields-select.query'; import { - getPostsByUserIdAlyaaQuery, - getPostsByUserIdAlyaaQueryWithoutView, + getPostsByUserIdProfileQuery, + getPostsByUserIdProfileQueryWithoutView, } from './queries/get-posts-profile-view.query'; @Injectable() @@ -257,7 +257,7 @@ export class TweetsRepository extends Repository { try { let query = this.user_posts_view_repository.createQueryBuilder('tweet'); - query = getPostsByUserIdAlyaaQuery(query, user_id); + query = getPostsByUserIdProfileQuery(query, user_id); query = query .andWhere('tweet.type != :type', { type: 'reply' }) @@ -267,6 +267,8 @@ export class TweetsRepository extends Repository { query = this.attachQuotedTweetQuery(query); + query = this.attachRepostInfo(query, 'tweet'); + query = this.attachUserInteractionBooleanFlags( query, current_user_id, @@ -330,7 +332,7 @@ export class TweetsRepository extends Repository { try { let query = this.user_posts_view_repository.createQueryBuilder('tweet'); - query = getPostsByUserIdAlyaaQuery(query, user_id); + query = getPostsByUserIdProfileQuery(query, user_id); query = query .andWhere('tweet.type = :type', { type: 'reply' }) @@ -403,7 +405,7 @@ export class TweetsRepository extends Repository { try { let query = this.user_posts_view_repository.createQueryBuilder('tweet'); - query = getPostsByUserIdAlyaaQuery(query, user_id); + query = getPostsByUserIdProfileQuery(query, user_id); query = query .andWhere( @@ -485,7 +487,7 @@ export class TweetsRepository extends Repository { { user_id } ); - query = getPostsByUserIdAlyaaQueryWithoutView(query, user_id); + query = getPostsByUserIdProfileQueryWithoutView(query, user_id); query = query .where('tweet.type != :type', { type: 'repost' }) @@ -1084,7 +1086,7 @@ export class TweetsRepository extends Repository { return query; } - /**************************** Alyaa ****************************/ + /**************************** Profile ****************************/ /** * Fetches a reply tweet along with its entire parent chain using a single recursive query.