Changes between Version 5 and Version 6 of DatabaseProgramming


Ignore:
Timestamp:
05/27/26 00:29:05 (14 hours ago)
Author:
231088
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • DatabaseProgramming

    v5 v6  
    55
    66
     7= Функции, Процедури и Тригери =
    78Во оваа фаза беа имплементирани функции, процедури и тригери кои ја поддржуваат основната бизнис логика на системот за booking на артисти и бендови. Секоја компонента е одговорна за одредена операција — од пресметување статистики, преку управување со bookings, до автоматска заштита од грешки.
    89
     
    7879Функцијата {{{fn_check_artist_availability}}} проверува дали артист или бенд има слободен термин на одреден датум и враќа {{{TRUE}}} или {{{FALSE}}}.
    7980
    80 Наместо {{{COUNT(*)}}} кој ги брои сите редици, функцијата користи {{{EXISTS}}} кој застанува веднаш при првиот пронајден слободен слот — со што е значително поефикасна.
     81Пребарува во табелата {{{AvailabilitySlot}}} дали постои слот со статус {{{AVAILABLE}}} за дадениот артист на бараниот датум. Резултатот од {{{COUNT(*)}}} се споредува со {{{0}}} и се враќа соодветна булова вредност.
    8182{{{
    8283CREATE OR REPLACE FUNCTION fn_check_artist_availability(
    8384    p_bookable_id INT,
    84     p_date        DATE
     85    p_date DATE
    8586)
    8687RETURNS BOOLEAN
     
    8889$$
    8990DECLARE
    90     v_exists BOOLEAN;
    91 BEGIN
    92 
    93     SELECT EXISTS(
    94         SELECT 1
    95         FROM AvailabilitySlot
    96         WHERE bookable_id = p_bookable_id
    97           AND DATE(start_datetime) = p_date
    98           AND status = 'AVAILABLE'
    99     )
    100     INTO v_exists;
    101 
    102     RETURN v_exists;
     91    v_exists INT;
     92BEGIN
     93
     94    SELECT COUNT(*)
     95    INTO v_exists
     96    FROM AvailabilitySlot
     97    WHERE bookable_id = p_bookable_id
     98      AND DATE(start_datetime) = p_date
     99      AND status = 'AVAILABLE';
     100
     101    RETURN v_exists > 0;
    103102
    104103END;
     
    110109Функцијата {{{fn_total_client_bookings}}} го враќа вкупниот број на bookings направени од одреден клиент.
    111110
    112 Ги поврзува табелите {{{BookingRequest}}}, {{{Offer}}} и {{{Booking}}} за да го пресмета бројот на сите bookings поврзани со клиентот, без разлика на нивниот статус.
     111Ги поврзува табелите {{{BookingRequest}}}, {{{Offer}}} и {{{Booking}}} и го пресметува бројот на сите bookings поврзани со клиентот, без разлика на нивниот тековен статус.
    113112{{{
    114113CREATE OR REPLACE FUNCTION fn_total_client_bookings(
     
    139138
    140139== Процедури ==
    141 Процедурите се користат за извршување на акции врз базата — за разлика од функциите, тие не враќаат вредност туку вршат промени. Секоја процедура содржи валидација пред да изврши каква било промена, со цел да се спречат невалидни состојби во базата.
     140Процедурите се користат за извршување на акции врз базата — за разлика од функциите, тие не враќаат вредност туку вршат промени. Секоја процедура е одговорна за еден конкретен процес во системот.
    142141
    143142=== 1. sp_create_booking_request ===
    144143Процедурата {{{sp_create_booking_request}}} креира нов барање за booking од страна на клиент.
    145144
    146 Пред да го изврши вметнувањето, процедурата врши три валидации:
    147  * Проверува дали клиентот постои во табелата {{{ClientProfile}}}
    148  * Проверува дали локацијата постои во табелата {{{Location}}}
    149  * Проверува дали датумот на настанот е во иднина
    150 
    151 Ако некоја од валидациите не помине, се фрла исклучок со јасна порака за грешка.
     145Прима ги сите потребни параметри — ID на клиент, траење на настанот, тип на настан, датум и локација — и ги вметнува во табелата {{{BookingRequest}}}. Преку {{{FOREIGN KEY}}} ограничувањата во базата се обезбедува дека само валидни вредности можат да бидат вметнати.
    152146{{{
    153147CREATE OR REPLACE PROCEDURE sp_create_booking_request(
     
    162156$$
    163157BEGIN
    164 
    165     IF NOT EXISTS (
    166         SELECT 1 FROM ClientProfile WHERE client_id = p_client_id
    167     ) THEN
    168         RAISE EXCEPTION 'Client with ID % does not exist!', p_client_id;
    169     END IF;
    170 
    171     IF NOT EXISTS (
    172         SELECT 1 FROM Location WHERE location_id = p_location_id
    173     ) THEN
    174         RAISE EXCEPTION 'Location with ID % does not exist!', p_location_id;
    175     END IF;
    176 
    177     IF p_event_date <= CURRENT_DATE THEN
    178         RAISE EXCEPTION 'Event date must be in the future!';
    179     END IF;
    180158
    181159    INSERT INTO BookingRequest(
     
    201179Процедурата {{{sp_cancel_booking}}} го откажува постоечки booking со менување на неговиот статус во {{{CANCELLED}}}.
    202180
    203 Пред да го изврши откажувањето, процедурата врши три проверки:
    204  * Проверува дали booking со дадениот ID воопшто постои
    205  * Проверува дали booking не е веќе откажан
    206  * Проверува дали booking не е веќе завршен — завршените bookings не можат да се откажат
    207 
    208 Без овие проверки, повикот со непостоечки ID би поминал тивко без никаква промена или грешка.
     181Прима го ID на booking-от и врши {{{UPDATE}}} врз табелата {{{Booking}}}. Со промената на статусот системот го евидентира откажувањето, а тригерот {{{trg_booking_status_history}}} автоматски ја запишува промената во историјатот.
    209182{{{
    210183CREATE OR REPLACE PROCEDURE sp_cancel_booking(
     
    214187AS
    215188$$
    216 DECLARE
    217     v_current_status VARCHAR(30);
    218 BEGIN
    219 
    220     SELECT booking_status
    221     INTO v_current_status
    222     FROM Booking
    223     WHERE booking_id = p_booking_id;
    224 
    225     IF NOT FOUND THEN
    226         RAISE EXCEPTION 'Booking with ID % does not exist!', p_booking_id;
    227     END IF;
    228 
    229     IF v_current_status = 'CANCELLED' THEN
    230         RAISE EXCEPTION 'Booking % is already cancelled!', p_booking_id;
    231     END IF;
    232 
    233     IF v_current_status = 'COMPLETED' THEN
    234         RAISE EXCEPTION 'Booking % is already completed and cannot be cancelled!', p_booking_id;
    235     END IF;
     189BEGIN
    236190
    237191    UPDATE Booking
     
    246200Процедурата {{{sp_create_payment}}} креира ново плаќање поврзано со одреден booking.
    247201
    248 Клучна поправка во однос на оригиналната верзија е дека плаќањето се креира со статус {{{PENDING}}} наместо веднаш {{{PAID}}}. Ова одговара на реалниот тек — плаќањето прво се иницира, па дури потоа се потврдува.
    249 
    250 Процедурата врши три валидации:
    251  * Проверува дали booking постои
    252  * Проверува дали износот е позитивен број
    253  * Проверува дали веќе не постои плаќање за истиот booking
     202Прима го ID на booking-от и износот на плаќањето и ги вметнува во табелата {{{Payment}}}. Плаќањето се креира со статус {{{PAID}}}, со што се евидентира успешно извршена трансакција.
    254203{{{
    255204CREATE OR REPLACE PROCEDURE sp_create_payment(
    256205    p_booking_id INT,
    257     p_amount     NUMERIC(10,2)
     206    p_amount NUMERIC(10,2)
    258207)
    259208LANGUAGE plpgsql
     
    261210$$
    262211BEGIN
    263 
    264     IF NOT EXISTS (
    265         SELECT 1 FROM Booking WHERE booking_id = p_booking_id
    266     ) THEN
    267         RAISE EXCEPTION 'Booking with ID % does not exist!', p_booking_id;
    268     END IF;
    269 
    270     IF p_amount <= 0 THEN
    271         RAISE EXCEPTION 'Payment amount must be greater than 0!';
    272     END IF;
    273 
    274     IF EXISTS (
    275         SELECT 1 FROM Payment WHERE booking_id = p_booking_id
    276     ) THEN
    277         RAISE EXCEPTION 'Payment for booking % already exists!', p_booking_id;
    278     END IF;
    279212
    280213    INSERT INTO Payment(
     
    286219        p_booking_id,
    287220        p_amount,
    288         'PENDING'
     221        'PAID'
    289222    );
    290223
     
    296229Тригерите се специјални функции кои се извршуваат автоматски при одредени настани во базата — без потреба апликацијата да ги повикува рачно. Во системот се имплементирани три тригери кои обезбедуваат конзистентност и интегритет на податоците.
    297230
    298 === 1. trg_prevent_double_booking ===
     231=== 1. trg_update_slot_status ===
     232Тригерот {{{trg_update_slot_status}}} автоматски го означува слободниот термин на артистот како {{{BOOKED}}} во моментот кога се креира нов booking.
     233
     234Се извршува автоматски '''по''' секој нов запис во табелата {{{Booking}}} ({{{AFTER INSERT}}}). Го пронаоѓа соодветниот {{{AvailabilitySlot}}} според артистот и датумот на настанот преку subquery-и и го менува неговиот статус — со тоа се спречува двојна резервација на ист термин.
     235{{{
     236CREATE OR REPLACE FUNCTION fn_update_slot_status()
     237RETURNS TRIGGER
     238AS
     239$$
     240BEGIN
     241
     242    UPDATE AvailabilitySlot s
     243    SET status = 'BOOKED'
     244    WHERE s.bookable_id = (
     245              SELECT o.bookable_id
     246              FROM Offer o
     247              WHERE o.offer_id = NEW.offer_id
     248          )
     249      AND DATE(s.start_datetime) = (
     250              SELECT br.event_date
     251              FROM BookingRequest br
     252              JOIN Offer o2 ON o2.request_id = br.request_id
     253              WHERE o2.offer_id = NEW.offer_id
     254          );
     255
     256    RETURN NEW;
     257
     258END;
     259$$
     260LANGUAGE plpgsql;
     261
     262CREATE OR REPLACE TRIGGER trg_update_slot_status
     263AFTER INSERT ON Booking
     264FOR EACH ROW
     265EXECUTE FUNCTION fn_update_slot_status();
     266}}}
     267
     268=== 2. trg_prevent_double_booking ===
    299269Тригерот {{{trg_prevent_double_booking}}} спречува двоен booking — ситуација каде ист артист или бенд би бил потврден за два различни настани на ист датум.
    300270
    301 Се извршува автоматски '''пред''' секој нов запис во табелата {{{Booking}}} ({{{BEFORE INSERT}}}). Доколку за истиот артист веќе постои {{{CONFIRMED}}} booking на истиот датум, тригерот фрла исклучок и го спречува вметнувањето.
     271Се извршува автоматски '''пред''' секој нов запис во табелата {{{Booking}}} ({{{BEFORE INSERT}}}). Преку subquery-и го пронаоѓа артистот и датумот на новиот booking и проверува дали веќе постои {{{CONFIRMED}}} booking за истата комбинација. Доколку постои, тригерот фрла исклучок и го спречува вметнувањето.
    302272{{{
    303273CREATE OR REPLACE FUNCTION fn_prevent_double_booking()
     
    306276$$
    307277DECLARE
    308     v_count      INT;
    309     v_bookable   INT;
    310     v_event_date DATE;
    311 BEGIN
    312 
    313     SELECT o.bookable_id, br.event_date
    314     INTO v_bookable, v_event_date
    315     FROM Offer o
    316     JOIN BookingRequest br ON br.request_id = o.request_id
    317     WHERE o.offer_id = NEW.offer_id;
     278    v_count INT;
     279BEGIN
    318280
    319281    SELECT COUNT(*)
     
    321283    FROM Booking b
    322284    JOIN Offer o
    323         ON b.offer_id = o.offer_id
     285      ON b.offer_id = o.offer_id
    324286    JOIN BookingRequest br
    325         ON br.request_id = o.request_id
    326     WHERE o.bookable_id = v_bookable
    327       AND br.event_date = v_event_date
     287      ON br.request_id = o.request_id
     288    WHERE o.bookable_id = (
     289              SELECT bookable_id
     290              FROM Offer
     291              WHERE offer_id = NEW.offer_id
     292          )
     293      AND br.event_date = (
     294              SELECT br2.event_date
     295              FROM BookingRequest br2
     296              JOIN Offer o2 ON o2.request_id = br2.request_id
     297              WHERE o2.offer_id = NEW.offer_id
     298          )
    328299      AND b.booking_status = 'CONFIRMED';
    329300
    330301    IF v_count > 0 THEN
    331         RAISE EXCEPTION 'Artist/Band with ID % is already booked on %!',
    332             v_bookable, v_event_date;
     302        RAISE EXCEPTION 'Artist already booked on that date!';
    333303    END IF;
    334304
     
    343313FOR EACH ROW
    344314EXECUTE FUNCTION fn_prevent_double_booking();
    345 }}}
    346 
    347 === 2. trg_update_slot_status ===
    348 Тригерот {{{trg_update_slot_status}}} автоматски го означува слободниот термин на артистот како {{{BOOKED}}} во моментот кога се креира нов booking.
    349 
    350 Се извршува автоматски '''по''' секој нов запис во табелата {{{Booking}}} ({{{AFTER INSERT}}}). Го пронаоѓа соодветниот {{{AvailabilitySlot}}} според артистот и датумот на настанот и го менува неговиот статус — со тоа се спречува двојна резервација на ист термин.
    351 {{{
    352 CREATE OR REPLACE FUNCTION fn_update_slot_status()
    353 RETURNS TRIGGER
    354 AS
    355 $$
    356 DECLARE
    357     v_bookable   INT;
    358     v_event_date DATE;
    359 BEGIN
    360 
    361     SELECT o.bookable_id, br.event_date
    362     INTO v_bookable, v_event_date
    363     FROM Offer o
    364     JOIN BookingRequest br ON br.request_id = o.request_id
    365     WHERE o.offer_id = NEW.offer_id;
    366 
    367     UPDATE AvailabilitySlot
    368     SET status = 'BOOKED'
    369     WHERE bookable_id = v_bookable
    370       AND DATE(start_datetime) = v_event_date
    371       AND status = 'AVAILABLE';
    372 
    373     RETURN NEW;
    374 
    375 END;
    376 $$
    377 LANGUAGE plpgsql;
    378 
    379 CREATE OR REPLACE TRIGGER trg_update_slot_status
    380 AFTER INSERT ON Booking
    381 FOR EACH ROW
    382 EXECUTE FUNCTION fn_update_slot_status();
    383315}}}
    384316