Changes between Version 1 and Version 2 of DatabaseProgramming


Ignore:
Timestamp:
06/16/26 00:49:02 (5 days ago)
Author:
231073
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • DatabaseProgramming

    v1 v2  
    44=== ФУНКЦИИ
    55* has_active_membership: Проверува дали даден член има активна и важечка членарина.
     6{{{
     7CREATE OR REPLACE FUNCTION has_active_membership(p_user_id INT)
     8RETURNS BOOLEAN AS $$
     9BEGIN
     10    RETURN EXISTS (
     11        SELECT 1
     12        FROM membership
     13        WHERE member_user_id = p_user_id
     14          AND status = 'active'
     15          AND end_date >= CURRENT_DATE
     16    );
     17END;
     18$$ LANGUAGE plpgsql;
     19}}}
    620* get_available_copies: Го враќа бројот на достапни копии за одредена книга.
     21{{{
     22CREATE OR REPLACE FUNCTION get_available_copies(p_barcode VARCHAR)
     23RETURNS INT AS $$
     24DECLARE
     25    v_count INT;
     26BEGIN
     27    SELECT COUNT(*)
     28    INTO v_count
     29    FROM book_copy
     30    WHERE barcode = p_barcode
     31      AND status = 'available';
     32
     33    RETURN v_count;
     34END;
     35$$ LANGUAGE plpgsql;
     36
     37}}}
    738* calculate_fine: Ја пресметува казната за задоцнето враќање на книга според бројот на денови доцнење.
     39{{{
     40CREATE OR REPLACE FUNCTION calculate_fine(p_loan_id INTEGER)
     41RETURNS INTEGER AS $$
     42DECLARE
     43    v_due_date DATE;
     44    v_return_date DATE;
     45    v_days_late INT;
     46    v_fine INT;
     47BEGIN
     48    SELECT due_date, return_date
     49    INTO v_due_date, v_return_date
     50    FROM loan_history
     51    WHERE loan_id = p_loan_id;
     52
     53    IF v_return_date IS NULL THEN
     54        RETURN 0;
     55    END IF;
     56
     57    v_days_late := v_return_date - v_due_date;
     58
     59    IF v_days_late <= 0 THEN
     60        RETURN 0;
     61    END IF;
     62
     63    v_fine := v_days_late * 20;
     64
     65    RETURN v_fine;
     66END;
     67$$ LANGUAGE plpgsql;
     68}}}
    869=== ПРОЦЕДУРИ
    970* borrow_book: Овозможува позајмување книга со проверки за членство, библиотекар и достапна копија.
     71{{{
     72CREATE OR REPLACE PROCEDURE borrow_book(
     73    p_user_id INT,
     74    p_barcode VARCHAR,
     75    p_librarian_id INT
     76) AS $$
     77DECLARE
     78    v_copy_id INT;
     79BEGIN
     80    IF NOT EXISTS (
     81        SELECT 1
     82        FROM member
     83        WHERE user_id = p_user_id
     84    ) THEN
     85        RAISE EXCEPTION 'User is not a member.';
     86    END IF;
     87
     88    IF NOT EXISTS (
     89        SELECT 1
     90        FROM librarian
     91        WHERE user_id = p_librarian_id
     92    ) THEN
     93        RAISE EXCEPTION 'User is not a librarian.';
     94    END IF;
     95
     96    IF NOT has_active_membership(p_user_id) THEN
     97        RAISE EXCEPTION 'Member does not have an active membership.';
     98    END IF;
     99
     100    SELECT copy_id
     101    INTO v_copy_id
     102    FROM book_copy
     103    WHERE barcode = p_barcode
     104      AND status = 'available'
     105    LIMIT 1
     106    FOR UPDATE;
     107
     108    IF v_copy_id IS NULL THEN
     109        RAISE EXCEPTION 'No available copies for this book.';
     110    END IF;
     111
     112    INSERT INTO loan_history (
     113        member_user_id,
     114        copy_id,
     115        librarian_user_id,
     116        borrow_date,
     117        due_date,
     118        status
     119    )
     120    VALUES (
     121        p_user_id,
     122        v_copy_id,
     123        p_librarian_id,
     124        CURRENT_DATE,
     125        CURRENT_DATE + INTERVAL '14 days',
     126        'borrowed'
     127    );
     128
     129    UPDATE book_copy
     130    SET status = 'borrowed'
     131    WHERE copy_id = v_copy_id;
     132
     133    RAISE NOTICE 'Book borrowed successfully. Copy ID: %', v_copy_id;
     134END;
     135$$ LANGUAGE plpgsql;
     136}}}
    10137* return_book: Евидентира враќање на книга и ја прави копијата повторно достапна.
     138{{{
     139CREATE OR REPLACE PROCEDURE return_book(
     140    IN p_copy_id INTEGER,
     141    IN p_is_damaged BOOLEAN
     142)
     143LANGUAGE plpgsql
     144AS $$
     145DECLARE
     146    v_loan_id INTEGER;
     147BEGIN
     148    UPDATE loan_history
     149    SET return_date = CURRENT_DATE,
     150        status = 'returned'
     151    WHERE copy_id = p_copy_id
     152      AND status = 'borrowed'
     153    RETURNING loan_id INTO v_loan_id;
     154
     155    IF v_loan_id IS NULL THEN
     156        RAISE NOTICE 'No active borrowed loan found for copy %.', p_copy_id;
     157        RETURN;
     158    END IF;
     159
     160    IF p_is_damaged = TRUE THEN
     161        UPDATE book_copy
     162        SET status = 'damaged'
     163        WHERE copy_id = p_copy_id;
     164    ELSE
     165        UPDATE book_copy
     166        SET status = 'available'
     167        WHERE copy_id = p_copy_id;
     168    END IF;
     169
     170    RAISE NOTICE 'Book copy % returned successfully.', p_copy_id;
     171END;
     172$$;
     173}}}
    11174* reserve_event: Креира резервација за настан и го намалува бројот на слободни места.
     175{{{
     176CREATE OR REPLACE PROCEDURE reserve_event(
     177    p_event_id INT,
     178    p_member_id INT,
     179    p_seats INT
     180)
     181LANGUAGE plpgsql
     182AS $$
     183DECLARE
     184    v_available_seats INT;
     185BEGIN
     186    SELECT available_seats
     187    INTO v_available_seats
     188    FROM event
     189    WHERE event_id = p_event_id;
     190
     191    IF NOT FOUND THEN
     192        RAISE EXCEPTION 'Event with ID % does not exist.', p_event_id;
     193    END IF;
     194
     195    IF v_available_seats < p_seats THEN
     196        RAISE EXCEPTION 'Not enough available seats.';
     197    END IF;
     198
     199    INSERT INTO event_reservation(
     200        event_id,
     201        member_user_id,
     202        seats_reserved,
     203        status
     204    )
     205    VALUES(
     206        p_event_id,
     207        p_member_id,
     208        p_seats,
     209        'reserved'
     210    );
     211
     212    UPDATE event
     213    SET available_seats = available_seats - p_seats
     214    WHERE event_id = p_event_id;
     215END;
     216$$;
     217}}}
     218
    12219* cancel_event_reservation: Откажува резервација и ги враќа резервираните места.
     220{{{
     221CREATE OR REPLACE PROCEDURE cancel_event_reservation(
     222    p_event_reservation_id INT
     223)
     224LANGUAGE plpgsql
     225AS $$
     226DECLARE
     227    v_event_id INT;
     228    v_seats INT;
     229    v_current_status event_reservation_status;
     230BEGIN
     231    SELECT event_id, seats_reserved, status
     232    INTO v_event_id, v_seats, v_current_status
     233    FROM event_reservation
     234    WHERE event_reservation_id = p_event_reservation_id;
     235
     236    IF NOT FOUND THEN
     237        RAISE EXCEPTION 'Reservation with ID % does not exist!', p_event_reservation_id;
     238    END IF;
     239
     240    IF v_current_status = 'cancelled' THEN
     241        RAISE EXCEPTION 'Reservation is already cancelled!';
     242    END IF;
     243
     244    UPDATE event_reservation
     245    SET status = 'cancelled'
     246    WHERE event_reservation_id = p_event_reservation_id;
     247
     248    UPDATE event
     249    SET available_seats = available_seats + v_seats
     250    WHERE event_id = v_event_id;
     251END;
     252$$;
     253}}}
    13254* create_event: Креира нов настан по проверка на библиотекарот, времето и бројот на места.
     255{{{
     256CREATE OR REPLACE PROCEDURE create_event(
     257    p_title VARCHAR,
     258    p_description TEXT,
     259    p_event_date DATE,
     260    p_start_time TIME,
     261    p_end_time TIME,
     262    p_location VARCHAR,
     263    p_max_seats INT,
     264    p_created_by INT
     265)
     266LANGUAGE plpgsql
     267AS $$
     268BEGIN
     269
     270    IF NOT EXISTS (
     271        SELECT 1
     272        FROM librarian
     273        WHERE user_id = p_created_by
     274    ) THEN
     275        RAISE EXCEPTION 'Librarian with ID % does not exist!', p_created_by;
     276    END IF;
     277
     278
     279    IF p_end_time <= p_start_time THEN
     280        RAISE EXCEPTION 'End time must be greater than start time!';
     281    END IF;
     282
     283
     284    IF p_max_seats <= 0 THEN
     285        RAISE EXCEPTION 'Max seats must be greater than 0!';
     286    END IF;
     287
     288
     289    INSERT INTO event (
     290        title,
     291        description,
     292        event_date,
     293        start_time,
     294        end_time,
     295        location,
     296        max_seats,
     297        available_seats,
     298        created_by
     299    )
     300    VALUES (
     301        p_title,
     302        p_description,
     303        p_event_date,
     304        p_start_time,
     305        p_end_time,
     306        p_location,
     307        p_max_seats,
     308        p_max_seats,
     309        p_created_by
     310    );
     311
     312END;
     313$$;
     314}}}
    14315=== ТРИГЕРИ
    15316* trigger_update_copy_status: Автоматски го ажурира статусот на копијата при позајмување или враќање.
     317{{{
     318CREATE OR REPLACE FUNCTION fn_update_copy_status()
     319RETURNS TRIGGER AS $$
     320BEGIN
     321    IF (TG_OP = 'INSERT') THEN
     322        UPDATE book_copy
     323        SET status = 'borrowed'
     324        WHERE copy_id = NEW.copy_id;
     325
     326    ELSIF (NEW.status = 'returned') THEN
     327        UPDATE book_copy
     328        SET status = 'available'
     329        WHERE copy_id = NEW.copy_id;
     330    END IF;
     331
     332    RETURN NEW;
     333END;
     334$$ LANGUAGE plpgsql;
     335}}}
     336{{{
     337CREATE TRIGGER trigger_update_copy_status
     338AFTER INSERT OR UPDATE ON loan_history
     339FOR EACH ROW
     340EXECUTE FUNCTION fn_update_copy_status();
     341}}}
    16342* trigger_create_fine: Автоматски креира казна кога книгата е вратена по рокот.
     343{{{
     344CREATE OR REPLACE FUNCTION trigger_create_fine_function()
     345RETURNS TRIGGER AS $$
     346DECLARE
     347    v_amount INT;
     348BEGIN
     349    IF NEW.return_date IS NOT NULL
     350       AND NEW.return_date > NEW.due_date THEN
     351
     352        v_amount := calculate_fine(NEW.loan_id);
     353
     354        IF v_amount > 0 THEN
     355            INSERT INTO fines(
     356                loan_id,
     357                amount,
     358                payment_due_date,
     359                status
     360            )
     361            VALUES(
     362                NEW.loan_id,
     363                v_amount,
     364                CURRENT_DATE + INTERVAL '7 days',
     365                'unpaid'
     366            );
     367        END IF;
     368    END IF;
     369
     370    RETURN NEW;
     371END;
     372$$ LANGUAGE plpgsql;
     373}}}
     374{{{
     375CREATE TRIGGER trigger_create_fine
     376AFTER UPDATE OF return_date ON loan_history
     377FOR EACH ROW
     378EXECUTE FUNCTION trigger_create_fine_function();
     379}}}
    17380* trigger_notification_on_fine: Испраќа нотификација до членот при креирање казна.
     381{{{
     382CREATE OR REPLACE FUNCTION trigger_notification_on_fine_function()
     383RETURNS TRIGGER AS $$
     384DECLARE
     385    v_member_id INT;
     386    v_notification_id INT;
     387BEGIN
     388    SELECT member_user_id
     389    INTO v_member_id
     390    FROM loan_history
     391    WHERE loan_id = NEW.loan_id;
     392
     393    INSERT INTO notification(
     394        member_user_id,
     395        notification_type,
     396        title,
     397        message,
     398        status
     399    )
     400    VALUES(
     401        v_member_id,
     402        'fine',
     403        'New Fine Created',
     404        'You have received a fine for returning a book late.',
     405        'pending'
     406    )
     407    RETURNING notification_id INTO v_notification_id;
     408
     409    INSERT INTO fines_notification(
     410        fine_id,
     411        notification_id
     412    )
     413    VALUES(
     414        NEW.fine_id,
     415        v_notification_id
     416    );
     417
     418    RETURN NEW;
     419END;
     420$$ LANGUAGE plpgsql;
     421
     422}}}
     423
     424{{{
     425CREATE TRIGGER trigger_notification_on_fine
     426AFTER INSERT ON fines
     427FOR EACH ROW
     428EXECUTE FUNCTION trigger_notification_on_fine_function();
     429}}}
    18430* trigger_activate_reservation: Активира резервација и испраќа известување кога книгата станува достапна.
     431{{{
     432CREATE OR REPLACE FUNCTION trigger_activate_reservation_function()
     433RETURNS TRIGGER AS $$
     434DECLARE
     435    v_barcode VARCHAR(13);
     436    v_reservation_id INT;
     437    v_member_id INT;
     438BEGIN
     439    SELECT barcode
     440    INTO v_barcode
     441    FROM book_copy
     442    WHERE copy_id = NEW.copy_id;
     443
     444    SELECT reservation_id, member_user_id
     445    INTO v_reservation_id, v_member_id
     446    FROM reservation
     447    WHERE barcode = v_barcode
     448      AND status = 'pending'
     449    ORDER BY reservation_timestamp
     450    LIMIT 1;
     451
     452    IF v_reservation_id IS NOT NULL THEN
     453
     454        UPDATE reservation
     455        SET status = 'active',
     456            notified_at = CURRENT_TIMESTAMP
     457        WHERE reservation_id = v_reservation_id;
     458
     459        INSERT INTO notification(
     460            member_user_id,
     461            notification_type,
     462            title,
     463            message,
     464            status
     465        )
     466        VALUES(
     467            v_member_id,
     468            'reservation',
     469            'Reserved Book Available',
     470            'The book you reserved is now available.',
     471            'pending'
     472        );
     473
     474    END IF;
     475
     476    RETURN NEW;
     477END;
     478$$ LANGUAGE plpgsql;
     479}}}
     480
     481{{{
     482CREATE TRIGGER trigger_activate_reservation
     483AFTER UPDATE OF status ON book_copy
     484FOR EACH ROW
     485WHEN (NEW.status = 'available')
     486EXECUTE FUNCTION trigger_activate_reservation_function();
     487}}}