Changes between Initial Version and Version 1 of P7


Ignore:
Timestamp:
04/25/26 22:54:02 (7 days ago)
Author:
211099
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • P7

    v1 v1  
     1= Advanced Database Development (SQL DDL)
     2
     3== Custom Domains
     4{{{
     5-- Check email format
     6CREATE DOMAIN valid_email AS VARCHAR(255)
     7CHECK (VALUE ~* '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$');
     8
     9-- Check rating range from 0 to 5
     10CREATE DOMAIN story_rating AS DECIMAL(3,2)
     11CHECK (VALUE >= 0.00 AND VALUE <= 5.00);
     12
     13-- Status of accepted values
     14CREATE DOMAIN story_status AS VARCHAR(50)
     15CHECK (VALUE IN ('draft', 'published', 'archived'));
     16
     17-- Permission level from 1 to 5
     18CREATE DOMAIN permission_lvl AS INTEGER
     19CHECK (VALUE >= 1 AND VALUE <= 5);
     20
     21-- URL / image path
     22CREATE DOMAIN valid_url AS VARCHAR(2048)
     23CHECK (VALUE ~* '^https?://.+');
     24}}}
     25
     26== Views
     27{{{
     28-- Detailed view for each story with statistic
     29CREATE OR REPLACE VIEW story_details_view AS
     30SELECT
     31    s.story_id,
     32    s.short_description,
     33    s.mature_content,
     34    s.image,
     35    s.story_created_at,
     36    u.username AS writer,
     37    u.user_name,
     38    u.surname,
     39    st.status,
     40    COUNT(DISTINCT ch.chapter_id) AS total_chapters,
     41    COALESCE(SUM(ch.view_count), 0) AS total_views,
     42    ROUND(AVG(ch.rating), 2) AS avg_rating,
     43    COUNT(DISTINCT l.user_id) AS total_likes,
     44    COUNT(DISTINCT c.comment_id) AS total_comments,
     45    COUNT(DISTINCT hg.genre_id) AS total_genres,
     46    COUNT(DISTINCT col.user_id) AS total_collaborators
     47FROM story s
     48JOIN writer w   ON s.user_id    = w.user_id
     49JOIN users u   ON w.user_id    = u.user_id
     50JOIN "status" st  ON s.story_id   = st.story_id
     51LEFT JOIN chapter ch  ON s.story_id   = ch.story_id
     52LEFT JOIN likes l   ON s.story_id   = l.story_id
     53LEFT JOIN "comment" c   ON s.story_id   = c.story_id
     54LEFT JOIN has_genre hg  ON s.story_id   = hg.story_id
     55LEFT JOIN collaboration col ON s.story_id   = col.story_id
     56GROUP BY
     57    s.story_id, s.short_description, s.mature_content,
     58    s.image, s.story_created_at,
     59    u.username, u.user_name, u.surname, st.status;
     60-- Top 10 most popular stories by likes count =
     61CREATE MATERIALIZED VIEW top_stories_by_likes AS
     62SELECT
     63    s.story_id,
     64    s.short_description,
     65    u.username AS writer,
     66    st.status,
     67    COUNT(DISTINCT l.user_id)  AS total_likes,
     68    COUNT(DISTINCT c.comment_id) AS total_comments,
     69    ROUND(AVG(ch.rating), 2) AS avg_rating
     70FROM story s
     71JOIN writer w   ON s.user_id    = w.user_id
     72JOIN users u   ON w.user_id    = u.user_id
     73JOIN "status" st  ON s.story_id   = st.story_id
     74AND st.status   = 'published'
     75LEFT JOIN likes l   ON s.story_id   = l.story_id
     76LEFT JOIN "comment" c   ON s.story_id   = c.story_id
     77LEFT JOIN chapter  ch  ON s.story_id   = ch.story_id
     78GROUP BY
     79    s.story_id, s.short_description,
     80    u.username, st.status
     81ORDER BY total_likes DESC
     82LIMIT 10;
     83
     84-- View for user profile with all his stories
     85CREATE OR REPLACE VIEW writer_profile_view AS
     86SELECT
     87    u.user_id,
     88    u.username,
     89    u.user_name,
     90    u.surname,
     91    u.user_created_at,
     92    COUNT(DISTINCT s.story_id)AS total_stories,
     93    COUNT(DISTINCT ch.chapter_id) AS total_chapters,
     94    COALESCE(SUM(ch.view_count), 0) AS total_views,
     95    COUNT(DISTINCT l.user_id) AS total_likes,
     96    COUNT(DISTINCT c.comment_id) AS total_comments,
     97    ROUND(AVG(ch.rating), 2) AS avg_rating
     98FROM users u
     99JOIN writer w   ON u.user_id    = w.user_id
     100LEFT JOIN story s   ON w.user_id    = s.user_id
     101LEFT JOIN chapter ch  ON s.story_id   = ch.story_id
     102LEFT JOIN likes l   ON s.story_id   = l.story_id
     103LEFT JOIN comment  c   ON s.story_id   = c.story_id
     104GROUP BY
     105    u.user_id, u.username, u.user_name,
     106    u.surname, u.user_created_at;
     107}}}
     108
     109== Stored Procedures / Functions
     110-- Table for daily top story
     111CREATE TABLE daily_top_stories (
     112    day         DATE PRIMARY KEY,
     113    story_id    INTEGER NULL REFERENCES story(story_id),
     114    total_likes BIGINT
     115);
     116
     117-- Procedure: saves the most liked story of the previous day
     118CREATE OR REPLACE PROCEDURE get_daily_top_story()
     119LANGUAGE plpgsql
     120AS $$
     121DECLARE
     122    yesterday TIMESTAMP;
     123BEGIN
     124    yesterday := CURRENT_DATE - 1;
     125
     126    IF EXISTS (
     127        SELECT 1 FROM likes
     128        WHERE like_created_at BETWEEN yesterday AND CURRENT_DATE
     129    ) THEN
     130        INSERT INTO daily_top_stories (day, story_id, total_likes)
     131        SELECT
     132            CURRENT_DATE - 1,
     133            s.story_id,
     134            COUNT(l.user_id) AS total_likes
     135        FROM story          s
     136        JOIN likes          l ON s.story_id = l.story_id
     137        WHERE l.like_created_at BETWEEN yesterday AND CURRENT_DATE
     138        GROUP BY s.story_id
     139        ORDER BY total_likes DESC
     140        LIMIT 1;
     141    ELSE
     142        INSERT INTO daily_top_stories (day, story_id, total_likes)
     143        VALUES (CURRENT_DATE - 1, NULL, 0);
     144    END IF;
     145END;
     146$$;
     147
     148-- Procedure: sends a notification to all collaborators of a story
     149CREATE OR REPLACE PROCEDURE notify_collaborators(
     150    p_story_id  INTEGER,
     151    p_message   TEXT,
     152    p_type      VARCHAR(50),
     153    p_link      VARCHAR(500)
     154)
     155LANGUAGE plpgsql
     156AS $$
     157DECLARE
     158    collab RECORD;
     159BEGIN
     160    FOR collab IN
     161        SELECT c.user_id
     162        FROM collaboration c
     163        WHERE c.story_id = p_story_id
     164    LOOP
     165        INSERT INTO notification (
     166            notification_content,
     167            is_read,
     168            recipient_user_id,
     169            type,
     170            link,
     171            notification_created_at
     172        )
     173        VALUES (
     174            p_message,
     175            FALSE,
     176            collab.user_id,
     177            p_type,
     178            p_link,
     179            CURRENT_TIMESTAMP
     180        );
     181    END LOOP;
     182END;
     183$$;
     184
     185-- Function: calculates the engagement score for a given story
     186CREATE OR REPLACE FUNCTION calculate_engagement_score(p_story_id INTEGER)
     187RETURNS DECIMAL
     188LANGUAGE sql
     189AS $$
     190    SELECT ROUND(
     191        (COUNT(DISTINCT l.user_id) + COUNT(DISTINCT c.comment_id))::DECIMAL
     192        / NULLIF(COALESCE(SUM(ch.view_count), 0), 0) * 100, 2
     193    )
     194    FROM story s
     195    LEFT JOIN likes l   ON s.story_id = l.story_id
     196    LEFT JOIN "comment" c   ON s.story_id = c.story_id
     197    LEFT JOIN chapter ch  ON s.story_id = ch.story_id
     198    WHERE s.story_id = p_story_id;
     199$$;