Changes between Version 4 and Version 5 of DatabaseProgramming


Ignore:
Timestamp:
05/20/26 15:46:32 (6 days ago)
Author:
231035
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • DatabaseProgramming

    v4 v5  
    11= Database Programming
     2== Create a booking
     3{{{
     4create or replace procedure book_room(
     5    p_room_id        bigint,
     6    p_guest_id       bigint,
     7    p_check_in_date  date,
     8    p_check_out_date date,
     9    p_guests_count   int
     10)
     11as $$
     12    declare
     13        v_total_price numeric;
     14    begin
     15        if p_check_out_date <= p_check_in_date then
     16            raise exception 'Check-out date must be after check-in date';
     17        end if;
     18
     19        if fn_is_room_available(
     20            p_room_id,
     21            p_check_in_date,
     22            p_check_out_date
     23        ) = false then
     24            raise exception 'Room % is not available for selected dates', p_room_id;
     25        end if;
     26
     27        if exists (
     28            select 1
     29            from bookings b
     30            where b.room_id = p_room_id
     31              and b.booking_status in ('PENDING', 'CONFIRMED')
     32              and daterange(b.check_in_date, b.check_out_date, '[)')
     33                  && daterange(p_check_in_date, p_check_out_date, '[)')
     34        ) then
     35            raise exception 'Room % is already booked for selected dates', p_room_id;
     36        end if;
     37
     38        v_total_price := fn_calculate_booking_price(
     39            p_room_id,
     40            p_check_in_date,
     41            p_check_out_date,
     42            p_guests_count
     43        );
     44
     45        insert into bookings (
     46            room_id,
     47            guest_id,
     48            check_in_date,
     49            check_out_date,
     50            guests_count,
     51            total_price,
     52            booking_status
     53        )
     54        values (
     55            p_room_id,
     56            p_guest_id,
     57            p_check_in_date,
     58            p_check_out_date,
     59            p_guests_count,
     60            v_total_price,
     61            'PENDING'
     62        );
     63
     64        update availability_windows aw
     65        set status = 'BOOKED'
     66        where aw.room_id = p_room_id
     67          and aw.available_date >= p_check_in_date
     68          and aw.available_date < p_check_out_date;
     69
     70        raise notice 'Booking created successfully. Total price: %', v_total_price;
     71    end;
     72    $$ language plpgsql;
     73}}}
    274== Prevention of double booking the same room
    375{{{
     
    2294    $$ language plpgsql;
    2395
    24 create trigger prevent_double_booking
     96create or replace trigger prevent_double_booking
    2597    before insert on bookings for each row execute function trg_prevent_double_booking();
    2698}}}
    2799== Validate the dates of a booking
    28100{{{
    29 
    30101create or replace function trg_validate_booking_dates()
    31102returns trigger as $$
     
    41112    $$ language plpgsql;
    42113
    43 create trigger validate_booking_dates
     114create or replace trigger validate_booking_dates
    44115    before insert or update on bookings for each row
    45116    execute function trg_validate_booking_dates();
     
    47118== A review can be made only for a complete booking
    48119{{{
    49 create or replace function trg_review_only_completed_booking()
    50 returns trigger
    51 as $$
    52     declare v_status varchar;
    53     begin
    54         select booking_status
    55         into v_status
    56             from bookings
    57         where booking_id = new.booking_id;
     120create or replace procedure review_booking(r_booking_id bigint,rating int,comment varchar)
     121as $$
     122    declare
     123            v_status varchar;
     124        guest_id bigint;
     125        property bigint;
     126    begin
     127        select b.booking_status,b.guest_id,r.property_id
     128        into v_status,guest_id,property
     129        from bookings b
     130        join rooms r on b.room_id = r.room_id
     131        where booking_id = r_booking_id;
     132
     133
    58134
    59135        if v_status <> 'COMPLETED' then
    60             raise exception 'Can only review completed bookings';
    61         end if;
    62         return new;
     136            raise exception  'Can only review completed bookings';
     137        end if;
     138        insert into reviews(booking_id, guest_id, property_id, rating, comment) values
     139                                                                                    (r_booking_id,guest_id,
     140                                                                                    property, review_booking.rating,review_booking.comment);
     141
    63142    end;
    64143    $$ language plpgsql;
    65 
    66 create trigger review_only_completed_booking
    67     before insert or update on reviews for each row
    68     execute function trg_review_only_completed_booking();
    69144}}}
    70145== Check if a room is available
     
    101176    end;
    102177    $$;
     178}}}
     179== Create timestamp
     180{{{
     181create or replace function fn_planora_make_timestamp(p_date date,p_time time)
     182returns timestamp
     183language plpgsql
     184as $$
     185    begin
     186        return p_date::timestamp + p_time;
     187    end;
     188    $$;
     189}}}
     190== Check if room is available
     191{{{
     192
     193CREATE OR REPLACE FUNCTION fn_is_room_available(
     194    p_room_id BIGINT,
     195    p_check_in_date DATE,
     196    p_check_out_date DATE
     197)
     198RETURNS BOOLEAN
     199LANGUAGE plpgsql
     200AS $$
     201DECLARE
     202    v_needed_days INT;
     203    v_available_days INT;
     204BEGIN
     205    IF p_check_in_date >= p_check_out_date THEN
     206        RETURN FALSE;
     207    END IF;
     208
     209    IF NOT EXISTS (
     210        SELECT 1
     211        FROM rooms r
     212        WHERE r.room_id = p_room_id
     213          AND r.status = 'ACTIVE'
     214    ) THEN
     215        RETURN FALSE;
     216    END IF;
     217
     218    v_needed_days := fn_calculate_nights(p_check_in_date := p_check_in_date,p_check_out_date := p_check_out_date );
     219
     220    SELECT COUNT(*)
     221    INTO v_available_days
     222    FROM availability_windows aw
     223    WHERE aw.room_id = p_room_id
     224      AND aw.available_date >= p_check_in_date
     225      AND aw.available_date < p_check_out_date
     226      AND aw.status = 'AVAILABLE';
     227
     228    IF v_available_days = v_needed_days THEN
     229        RETURN TRUE;
     230    ELSE
     231        RETURN FALSE;
     232    END IF;
     233END;
     234$$;
    103235}}}
    104236== Calculate the number of nights stayed
     
    219351}}}
    220352
    221 == Create a booking
    222 {{{
    223 CREATE OR REPLACE PROCEDURE book_room(
    224     p_room_id        BIGINT,
    225     p_guest_id       BIGINT,
    226     p_check_in_date  DATE,
    227     p_check_out_date DATE,
    228     p_guests_count   INT,
    229     p_total_price    NUMERIC
     353== Flush availability_window dates that are in the past
     354{{{
     355CREATE OR REPLACE PROCEDURE refresh_availability_windows(
     356    p_days_ahead INT DEFAULT 30
    230357)
    231358LANGUAGE plpgsql
    232359AS $$
    233360BEGIN
    234     IF p_check_out_date <= p_check_in_date THEN
    235         RAISE EXCEPTION 'Check-out date must be after check-in date';
    236     END IF;
    237 
    238     IF EXISTS (
    239         SELECT 1
    240         FROM bookings b
    241         WHERE b.room_id = p_room_id
    242           AND b.booking_status IN ('PENDING', 'CONFIRMED')
    243           AND daterange(b.check_in_date, b.check_out_date, '[)')
    244               && daterange(p_check_in_date, p_check_out_date, '[)')
    245     ) THEN
    246         RAISE EXCEPTION 'Room % is already booked for selected dates', p_room_id;
    247     END IF;
    248 
    249     INSERT INTO bookings (
    250         room_id,
    251         guest_id,
    252         check_in_date,
    253         check_out_date,
    254         guests_count,
    255         total_price,
    256         booking_status
    257     )
    258     VALUES (
    259         p_room_id,
    260         p_guest_id,
    261         p_check_in_date,
    262         p_check_out_date,
    263         p_guests_count,
    264         p_total_price,
    265         'PENDING'
    266     );
    267 
    268     RAISE NOTICE 'Booking created successfully';
     361    DELETE FROM availability_windows
     362    WHERE available_date < CURRENT_DATE;
     363
     364    INSERT INTO availability_windows (room_id,available_date,status)
     365    SELECT
     366        r.room_id,
     367        d.available_day::date,
     368        'AVAILABLE'
     369    FROM rooms r
     370    CROSS JOIN generate_series(
     371        CURRENT_DATE,
     372        CURRENT_DATE + p_days_ahead,
     373        INTERVAL '1 day'
     374    ) AS d(available_day)
     375    WHERE r.status = 'ACTIVE'
     376      AND NOT EXISTS (
     377          SELECT 1
     378          FROM bookings b
     379          WHERE b.room_id = r.room_id
     380            AND b.booking_status IN ('PENDING', 'CONFIRMED')
     381            AND daterange(b.check_in_date, b.check_out_date, '[)')
     382                && daterange(d.available_day::date, d.available_day::date + 1, '[)')
     383      )
     384      AND NOT EXISTS (
     385          SELECT 1
     386          FROM availability_windows aw
     387          WHERE aw.room_id = r.room_id
     388            AND aw.available_date = d.available_day::date
     389      );
     390
     391    RAISE NOTICE 'Availability windows refreshed for % days ahead', p_days_ahead;
    269392END;
    270393$$;
    271 }}}
     394
     395}}}
     396== Get user favorite listings
     397{{{
     398
     399CREATE OR REPLACE FUNCTION get_user_favorite_listings(
     400    p_user_id BIGINT
     401)
     402RETURNS TABLE (
     403    property_id BIGINT,
     404    property_title VARCHAR,
     405    property_status VARCHAR,
     406    created_at TIMESTAMP,
     407    description TEXT,
     408    city VARCHAR,
     409    country VARCHAR
     410)
     411LANGUAGE plpgsql
     412AS $$
     413BEGIN
     414    RETURN QUERY
     415    SELECT
     416        p.property_id,
     417        p.title::VARCHAR,
     418        p.status::VARCHAR,
     419        p.created_at,
     420        p.description::text,
     421        a.city::VARCHAR,
     422        c.country_name::VARCHAR
     423    FROM favorite_listings f
     424    LEFT JOIN properties p
     425        ON p.property_id = f.property_id
     426    LEFT JOIN addresses a
     427        ON a.address_id = p.address_id
     428    LEFT JOIN countries c
     429        ON c.country_id = a.country_id
     430    WHERE f.user_id = p_user_id;
     431END;
     432$$;
     433}}}
     434== Confirm a booking
     435{{{
     436create or replace procedure sp_confirm_booking(p_booking_id bigint)
     437as $$
     438    declare
     439        v_status varchar;
     440    begin
     441        select b.booking_status
     442        into v_status
     443        from bookings b
     444        where b.booking_id = p_booking_id;
     445
     446        if v_status is null then
     447            raise exception 'Booking does not exist';
     448        end if;
     449
     450        if v_status = 'CONFIRMED' then
     451            raise exception 'Booking is already confirmed';
     452        end if;
     453
     454        if v_status = 'CANCELLED' then
     455            raise exception 'Cancelled booking cannot be confirmed';
     456        end if;
     457
     458        if v_status = 'COMPLETED' then
     459            raise exception 'Completed booking cannot be confirmed';
     460        end if;
     461
     462        update bookings
     463        set booking_status = 'CONFIRMED'
     464        where booking_id = p_booking_id;
     465
     466        raise notice 'Booking % confirmed successfully', p_booking_id;
     467    end;
     468    $$ language plpgsql;
     469}}}