Files
fc56726c-3e3f-41e4-a921-51e…/src/lib/database/carDatabase.ts

334 lines
7.9 KiB
TypeScript

/**
* Car Database Service
* Handles all car data operations and queries
*/
import { Car, CarFilter, CarComparison, CarInventory } from './carTypes';
export class CarDatabase {
private cars: Car[] = [];
/**
* Initialize database with sample data
*/
initialize(cars: Car[]): void {
this.cars = cars;
}
/**
* Get all cars
*/
getAllCars(): Car[] {
return this.cars;
}
/**
* Get car by ID
*/
getCarById(id: string): Car | undefined {
return this.cars.find((car) => car.id === id);
}
/**
* Search cars by filter criteria
*/
filterCars(filter: CarFilter): Car[] {
return this.cars.filter((car) => {
// Make filter
if (filter.make && !filter.make.includes(car.make)) {
return false;
}
// Model filter
if (filter.model && !filter.model.includes(car.model)) {
return false;
}
// Year range filter
if (filter.yearRange) {
const [minYear, maxYear] = filter.yearRange;
if (car.year < minYear || car.year > maxYear) {
return false;
}
}
// Price range filter
if (filter.priceRange) {
const [minPrice, maxPrice] = filter.priceRange;
if (car.price < minPrice || car.price > maxPrice) {
return false;
}
}
// Transmission filter
if (filter.transmission && !filter.transmission.includes(car.transmission)) {
return false;
}
// Fuel filter
if (filter.fuel && !filter.fuel.includes(car.fuel)) {
return false;
}
// Body type filter
if (filter.bodyType && !filter.bodyType.includes(car.bodyType || '')) {
return false;
}
// Drive type filter
if (filter.driveType && !filter.driveType.includes(car.driveType || '')) {
return false;
}
// Seating filter
if (filter.seatCount && car.seating) {
const [minSeats, maxSeats] = filter.seatCount;
if (car.seating < minSeats || car.seating > maxSeats) {
return false;
}
}
// Safety rating filter
if (filter.safetyRating && car.safetyRating && car.safetyRating < filter.safetyRating) {
return false;
}
// Keyword search
if (filter.keyword) {
const keyword = filter.keyword.toLowerCase();
const searchableFields = [
car.make,
car.model,
car.bodyType,
car.color,
car.description,
].filter(Boolean);
const matches = searchableFields.some(
(field) => field && field.toString().toLowerCase().includes(keyword)
);
if (!matches) {
return false;
}
}
return true;
});
}
/**
* Search cars by keyword
*/
searchCars(keyword: string): Car[] {
return this.filterCars({ keyword });
}
/**
* Get cars by make
*/
getCarsByMake(make: string): Car[] {
return this.cars.filter((car) => car.make.toLowerCase() === make.toLowerCase());
}
/**
* Get cars by fuel type
*/
getCarsByFuel(fuel: string): Car[] {
return this.cars.filter((car) => car.fuel === fuel);
}
/**
* Get cars by body type
*/
getCarsByBodyType(bodyType: string): Car[] {
return this.cars.filter((car) => car.bodyType === bodyType);
}
/**
* Get cars within price range
*/
getCarsByPriceRange(minPrice: number, maxPrice: number): Car[] {
return this.cars.filter((car) => car.price >= minPrice && car.price <= maxPrice);
}
/**
* Sort cars by field
*/
sortCars(cars: Car[], sortBy: keyof Car, ascending: boolean = true): Car[] {
const sorted = [...cars].sort((a, b) => {
const aValue = a[sortBy];
const bValue = b[sortBy];
if (typeof aValue === 'number' && typeof bValue === 'number') {
return ascending ? aValue - bValue : bValue - aValue;
}
if (typeof aValue === 'string' && typeof bValue === 'string') {
return ascending ? aValue.localeCompare(bValue) : bValue.localeCompare(aValue);
}
return 0;
});
return sorted;
}
/**
* Get unique makes
*/
getUniqueMakes(): string[] {
const makes = new Set(this.cars.map((car) => car.make));
return Array.from(makes).sort();
}
/**
* Get unique models for a make
*/
getUniqueModels(make: string): string[] {
const models = new Set(
this.cars.filter((car) => car.make === make).map((car) => car.model)
);
return Array.from(models).sort();
}
/**
* Get unique fuel types
*/
getUniqueFuelTypes(): string[] {
const fuels = new Set(this.cars.map((car) => car.fuel));
return Array.from(fuels).sort();
}
/**
* Get unique body types
*/
getUniqueBodyTypes(): string[] {
const bodyTypes = new Set(this.cars.filter((car) => car.bodyType).map((car) => car.bodyType));
return Array.from(bodyTypes).sort();
}
/**
* Compare two or more cars
*/
compareCars(carIds: string[]): Car[] {
return carIds
.map((id) => this.getCarById(id))
.filter((car) => car !== undefined) as Car[];
}
/**
* Get similar cars based on specifications
*/
getSimilarCars(carId: string, count: number = 3): Car[] {
const car = this.getCarById(carId);
if (!car) return [];
const similar = this.cars
.filter((c) => c.id !== carId && c.make === car.make)
.slice(0, count);
return similar.length >= count
? similar
: this.cars.filter((c) => c.id !== carId && c.bodyType === car.bodyType).slice(0, count);
}
/**
* Get top rated cars
*/
getTopRatedCars(count: number = 5): Car[] {
return [...this.cars]
.sort((a, b) => (b.userRating || 0) - (a.userRating || 0))
.slice(0, count);
}
/**
* Get most viewed cars
*/
getMostViewedCars(count: number = 5): Car[] {
return [...this.cars]
.sort((a, b) => (b.viewCount || 0) - (a.viewCount || 0))
.slice(0, count);
}
/**
* Get featured cars
*/
getFeaturedCars(count: number = 5): Car[] {
return this.cars.filter((car) => car.isFavorite).slice(0, count);
}
/**
* Calculate average specifications for a make or body type
*/
calculateAverageSpecs(
cars: Car[]
): Partial<Car> {
if (cars.length === 0) return {};
const specs: Partial<Car> = {
price:
cars.reduce((sum, car) => sum + car.price, 0) / cars.length,
horsepower:
cars.reduce((sum, car) => sum + (car.horsepower || 0), 0) / cars.length,
mpg: cars.reduce((sum, car) => sum + (car.mpg || 0), 0) / cars.length,
seating:
Math.round(cars.reduce((sum, car) => sum + (car.seating || 0), 0) / cars.length),
};
return specs;
}
/**
* Add a new car to database
*/
addCar(car: Car): void {
this.cars.push(car);
}
/**
* Update a car
*/
updateCar(id: string, updates: Partial<Car>): Car | undefined {
const index = this.cars.findIndex((car) => car.id === id);
if (index !== -1) {
this.cars[index] = { ...this.cars[index], ...updates, updatedAt: new Date() };
return this.cars[index];
}
return undefined;
}
/**
* Delete a car
*/
deleteCar(id: string): boolean {
const index = this.cars.findIndex((car) => car.id === id);
if (index !== -1) {
this.cars.splice(index, 1);
return true;
}
return false;
}
/**
* Get database statistics
*/
getStatistics() {
return {
totalCars: this.cars.length,
averagePrice: this.cars.reduce((sum, car) => sum + car.price, 0) / this.cars.length,
makes: this.getUniqueMakes().length,
models: this.cars.length,
fuelTypes: this.getUniqueFuelTypes().length,
bodyTypes: this.getUniqueBodyTypes().length,
averageHorsepower:
this.cars.reduce((sum, car) => sum + (car.horsepower || 0), 0) / this.cars.length,
averageMpg:
this.cars.reduce((sum, car) => sum + (car.mpg || 0), 0) / this.cars.length,
};
}
}
// Export singleton instance
export const carDatabase = new CarDatabase();