using Npgsql; namespace practiceApplicaiton; /// /// Все операции с БД. Использует параметризованные запросы /// для защиты от SQL-инъекций. /// public static class Repository { // ── БРОНИРОВАНИЯ ──────────────────────────────────────────────── public static async Task> GetBookingsAsync(string search = "") { var list = new List(); await using var conn = Database.GetConnection(); await conn.OpenAsync(); var sql = """ SELECT b.booking_id, b.client_id, b.room_id, b.check_in_date, b.check_out_date, b.price_per_night, c.last_name || ' ' || c.first_name || ' ' || COALESCE(c.patronymic,'') AS full_name, r.room_number, rt.type_name FROM Booking b JOIN Client c ON c.client_id = b.client_id JOIN Room r ON r.room_id = b.room_id JOIN RoomType rt ON rt.room_type_id = r.room_type_id WHERE (@search = '' OR LOWER(c.last_name) LIKE LOWER(@search) OR CAST(r.room_number AS TEXT) LIKE @search) ORDER BY b.check_in_date DESC """; await using var cmd = new NpgsqlCommand(sql, conn); cmd.Parameters.AddWithValue("search", string.IsNullOrEmpty(search) ? "" : $"%{search}%"); await using var reader = await cmd.ExecuteReaderAsync(); while (await reader.ReadAsync()) { list.Add(new Booking { BookingId = reader.GetInt32(0), ClientId = reader.GetInt32(1), RoomId = reader.GetInt32(2), CheckInDate = reader.GetDateTime(3), CheckOutDate = reader.GetDateTime(4), PricePerNight = reader.GetDecimal(5), ClientFullName = reader.GetString(6).Trim(), RoomNumber = reader.GetInt32(7), RoomType = reader.GetString(8), }); } return list; } public static async Task CreateBookingAsync(int clientId, int roomId, DateTime checkIn, DateTime checkOut, decimal price) { await using var conn = Database.GetConnection(); await conn.OpenAsync(); // Вызываем хранимую процедуру await using var cmd = new NpgsqlCommand( "CALL create_booking(@cid, @rid, @ci, @co, @price)", conn); cmd.Parameters.AddWithValue("cid", clientId); cmd.Parameters.AddWithValue("rid", roomId); cmd.Parameters.AddWithValue("ci", checkIn); cmd.Parameters.AddWithValue("co", checkOut); cmd.Parameters.AddWithValue("price", price); await cmd.ExecuteNonQueryAsync(); } public static async Task UpdateBookingAsync(int bookingId, DateTime checkIn, DateTime checkOut, decimal price) { await using var conn = Database.GetConnection(); await conn.OpenAsync(); await using var cmd = new NpgsqlCommand(""" UPDATE Booking SET check_in_date=@ci, check_out_date=@co, price_per_night=@price WHERE booking_id=@id """, conn); cmd.Parameters.AddWithValue("ci", checkIn); cmd.Parameters.AddWithValue("co", checkOut); cmd.Parameters.AddWithValue("price", price); cmd.Parameters.AddWithValue("id", bookingId); await cmd.ExecuteNonQueryAsync(); } public static async Task DeleteBookingAsync(int bookingId) { await using var conn = Database.GetConnection(); await conn.OpenAsync(); await using var cmd = new NpgsqlCommand( "DELETE FROM Booking WHERE booking_id=@id", conn); cmd.Parameters.AddWithValue("id", bookingId); await cmd.ExecuteNonQueryAsync(); } // ── КЛИЕНТЫ ───────────────────────────────────────────────────── public static async Task> GetClientsAsync(string search = "") { var list = new List(); await using var conn = Database.GetConnection(); await conn.OpenAsync(); var sql = """ SELECT c.client_id, c.firm_id, c.last_name, c.first_name, COALESCE(c.patronymic,''), c.phone_number, tf.firm_name FROM Client c JOIN TourFirm tf ON tf.firm_id = c.firm_id WHERE (@s = '' OR LOWER(c.last_name) LIKE LOWER(@s) OR c.phone_number LIKE @s) ORDER BY c.last_name """; await using var cmd = new NpgsqlCommand(sql, conn); cmd.Parameters.AddWithValue("s", string.IsNullOrEmpty(search) ? "" : $"%{search}%"); await using var reader = await cmd.ExecuteReaderAsync(); while (await reader.ReadAsync()) list.Add(new Client { ClientId = reader.GetInt32(0), FirmId = reader.GetInt32(1), LastName = reader.GetString(2), FirstName = reader.GetString(3), Patronymic = reader.GetString(4), PhoneNumber = reader.GetString(5), FirmName = reader.GetString(6), }); return list; } public static async Task AddClientAsync(Client c) { await using var conn = Database.GetConnection(); await conn.OpenAsync(); await using var cmd = new NpgsqlCommand(""" INSERT INTO Client (firm_id,last_name,first_name,patronymic,phone_number) VALUES (@fid,@ln,@fn,@pat,@ph) """, conn); cmd.Parameters.AddWithValue("fid", c.FirmId); cmd.Parameters.AddWithValue("ln", c.LastName); cmd.Parameters.AddWithValue("fn", c.FirstName); cmd.Parameters.AddWithValue("pat", (object?)c.Patronymic ?? DBNull.Value); cmd.Parameters.AddWithValue("ph", c.PhoneNumber); await cmd.ExecuteNonQueryAsync(); } public static async Task UpdateClientAsync(Client c) { await using var conn = Database.GetConnection(); await conn.OpenAsync(); await using var cmd = new NpgsqlCommand(""" UPDATE Client SET firm_id=@fid, last_name=@ln, first_name=@fn, patronymic=@pat, phone_number=@ph WHERE client_id=@id """, conn); cmd.Parameters.AddWithValue("fid", c.FirmId); cmd.Parameters.AddWithValue("ln", c.LastName); cmd.Parameters.AddWithValue("fn", c.FirstName); cmd.Parameters.AddWithValue("pat", (object?)c.Patronymic ?? DBNull.Value); cmd.Parameters.AddWithValue("ph", c.PhoneNumber); cmd.Parameters.AddWithValue("id", c.ClientId); await cmd.ExecuteNonQueryAsync(); } public static async Task DeleteClientAsync(int clientId) { await using var conn = Database.GetConnection(); await conn.OpenAsync(); await using var cmd = new NpgsqlCommand( "DELETE FROM Client WHERE client_id=@id", conn); cmd.Parameters.AddWithValue("id", clientId); await cmd.ExecuteNonQueryAsync(); } // ── КОМНАТЫ ───────────────────────────────────────────────────── public static async Task> GetRoomsAsync() { var list = new List(); await using var conn = Database.GetConnection(); await conn.OpenAsync(); await using var cmd = new NpgsqlCommand(""" SELECT r.room_id, r.room_type_id, r.room_number, r.occupancy, r.rating, rt.type_name FROM Room r JOIN RoomType rt ON rt.room_type_id = r.room_type_id ORDER BY r.room_number """, conn); await using var reader = await cmd.ExecuteReaderAsync(); while (await reader.ReadAsync()) list.Add(new Room { RoomId = reader.GetInt32(0), RoomTypeId = reader.GetInt32(1), RoomNumber = reader.GetInt32(2), Occupancy = reader.GetInt32(3), Rating = reader.GetDecimal(4), TypeName = reader.GetString(5), }); return list; } public static async Task UpdateRoomRatingAsync(int roomId, decimal rating) { await using var conn = Database.GetConnection(); await conn.OpenAsync(); await using var cmd = new NpgsqlCommand( "UPDATE Room SET rating=@r WHERE room_id=@id", conn); cmd.Parameters.AddWithValue("r", rating); cmd.Parameters.AddWithValue("id", roomId); await cmd.ExecuteNonQueryAsync(); } // ── ВСПОМОГАТЕЛЬНЫЕ ───────────────────────────────────────────── public static async Task> GetFirmsAsync() { var list = new List(); await using var conn = Database.GetConnection(); await conn.OpenAsync(); await using var cmd = new NpgsqlCommand( "SELECT firm_id, firm_name, people_count FROM TourFirm ORDER BY firm_name", conn); await using var reader = await cmd.ExecuteReaderAsync(); while (await reader.ReadAsync()) list.Add(new TourFirm { FirmId = reader.GetInt32(0), FirmName = reader.GetString(1), PeopleCount = reader.GetInt32(2), }); return list; } // ── ОТЧЁТ — итоговая стоимость бронирований ───────────────────── public static async Task> GetBookingReportAsync( DateTime from, DateTime to) { var list = new List(); await using var conn = Database.GetConnection(); await conn.OpenAsync(); await using var cmd = new NpgsqlCommand(""" SELECT b.booking_id, b.client_id, b.room_id, b.check_in_date, b.check_out_date, b.price_per_night, c.last_name || ' ' || c.first_name AS full_name, r.room_number, rt.type_name FROM BookingCostView b JOIN Booking bk ON bk.booking_id = b.booking_id JOIN Client c ON c.client_id = bk.client_id JOIN Room r ON r.room_id = bk.room_id JOIN RoomType rt ON rt.room_type_id = r.room_type_id WHERE bk.check_in_date >= @from AND bk.check_out_date <= @to ORDER BY bk.check_in_date """, conn); // Проще использовать BookingCostView напрямую cmd.CommandText = """ SELECT booking_id, 0, 0, check_in_date, check_out_date, price_per_night, client_full_name, room_number, room_type FROM BookingCostView WHERE check_in_date >= @from AND check_out_date <= @to ORDER BY check_in_date """; cmd.Parameters.AddWithValue("from", from); cmd.Parameters.AddWithValue("to", to); await using var reader = await cmd.ExecuteReaderAsync(); while (await reader.ReadAsync()) list.Add(new Booking { BookingId = reader.GetInt32(0), CheckInDate = reader.GetDateTime(3), CheckOutDate = reader.GetDateTime(4), PricePerNight = reader.GetDecimal(5), ClientFullName = reader.GetString(6).Trim(), RoomNumber = reader.GetInt32(7), RoomType = reader.GetString(8), }); return list; } }