Skip to content

Instantly share code, notes, and snippets.

@baran
Last active April 17, 2026 17:17
Show Gist options
  • Select an option

  • Save baran/f63c9ba5dce7ed279c5875a377ae4c69 to your computer and use it in GitHub Desktop.

Select an option

Save baran/f63c9ba5dce7ed279c5875a377ae4c69 to your computer and use it in GitHub Desktop.
BLP104 Sample Database

Kullanım

  1. Kodu bir dosyaya kaydedin: setup.py

  2. Çalıştırın: python3 setup.py

  3. Otomatik olarak rentacar-db/ klasörü oluşturulur

  4. İçinde: init/ , seed_data/ , docker-compose.yml

  5. docker-compose up -d ile veritabanı başlar

Tüm veriler deterministiktir (seed=42), her çalıştırmada aynı 350 müşteri, 3000 araç, 300 şube oluşur.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Rent A Car Database - Complete Setup
Tek dosya çalıştırma ile tüm yapıyı oluşturur
"""
import os
import random
from datetime import datetime, timedelta
from faker import Faker
# DETERMINISTIC SEED - Sabit kalacak
RANDOM_SEED = 42
random.seed(RANDOM_SEED)
Faker.seed(RANDOM_SEED)
fake = Faker(['en_US', 'de_DE', 'tr_TR', 'fr_FR', 'es_ES', 'it_IT', 'nl_NL'])
# Yapılandırma
CONFIG = {
'total_customers': 350,
'total_vehicles': 3000,
'total_branches': 300,
'output_dir': 'rentacar-db'
}
# Veri setleri
EUROPEAN_COUNTRIES = [
('DE', 'Germany', '+49', 'EUR', 0.30), ('FR', 'France', '+33', 'EUR', 0.20),
('IT', 'Italy', '+39', 'EUR', 0.15), ('ES', 'Spain', '+34', 'EUR', 0.15),
('NL', 'Netherlands', '+31', 'EUR', 0.10), ('TR', 'Turkey', '+90', 'TRY', 0.05),
('BE', 'Belgium', '+32', 'EUR', 0.02), ('AT', 'Austria', '+43', 'EUR', 0.02),
('CH', 'Switzerland', '+41', 'CHF', 0.01)
]
CITIES_BY_COUNTRY = {
'DE': ['Berlin', 'Munich', 'Hamburg', 'Frankfurt', 'Cologne', 'Stuttgart', 'Düsseldorf'],
'FR': ['Paris', 'Lyon', 'Marseille', 'Toulouse', 'Nice', 'Bordeaux', 'Strasbourg'],
'IT': ['Rome', 'Milan', 'Naples', 'Turin', 'Palermo', 'Florence', 'Bologna'],
'ES': ['Madrid', 'Barcelona', 'Valencia', 'Seville', 'Zaragoza', 'Málaga'],
'NL': ['Amsterdam', 'Rotterdam', 'The Hague', 'Utrecht', 'Eindhoven'],
'TR': ['Istanbul', 'Ankara', 'Izmir', 'Antalya', 'Bursa', 'Adana', 'Gaziantep'],
'BE': ['Brussels', 'Antwerp', 'Ghent', 'Charleroi'],
'AT': ['Vienna', 'Graz', 'Linz', 'Salzburg'],
'CH': ['Zurich', 'Geneva', 'Basel', 'Bern']
}
BRANCH_PREFIXES = ['Central', 'Airport', 'Downtown', 'West', 'East', 'North', 'South', 'Main']
VEHICLE_BRANDS = [('Toyota', 'JP'), ('Volkswagen', 'DE'), ('BMW', 'DE'), ('Mercedes-Benz', 'DE'), ('Audi', 'DE'), ('Ford', 'US'), ('Peugeot', 'FR'), ('Renault', 'FR'), ('Fiat', 'IT'), ('Volvo', 'SE'), ('Skoda', 'CZ'), ('Seat', 'ES'), ('Hyundai', 'KR'), ('Kia', 'KR'), ('Tesla', 'US'), ('Nissan', 'JP'), ('Honda', 'JP'), ('Citroen', 'FR'), ('Opel', 'DE'), ('Dacia', 'RO')]
MODELS = {
'SUV': [('Tiguan', 'VW', 45, 65), ('Q5', 'Audi', 80, 120), ('X5', 'BMW', 90, 140), ('GLC', 'Mercedes', 85, 130), ('RAV4', 'Toyota', 50, 75), ('Sportage', 'Kia', 40, 60), ('Tucson', 'Hyundai', 42, 62), ('Kuga', 'Ford', 40, 58), ('Captur', 'Renault', 35, 50), ('Duster', 'Dacia', 30, 45), ('XC60', 'Volvo', 70, 100), ('Model Y', 'Tesla', 75, 110)],
'Sedan': [('Passat', 'VW', 40, 60), ('A4', 'Audi', 60, 90), ('3 Series', 'BMW', 55, 85), ('C-Class', 'Mercedes', 60, 95), ('Camry', 'Toyota', 45, 70), ('Model 3', 'Tesla', 65, 95), ('Octavia', 'Skoda', 35, 50), ('508', 'Peugeot', 40, 60), ('Taliant', 'Renault', 30, 45), ('Egea', 'Fiat', 28, 42)],
'Hatchback': [('Golf', 'VW', 35, 50), ('A3', 'Audi', 50, 75), ('1 Series', 'BMW', 45, 68), ('A-Class', 'Mercedes', 48, 72), ('Corolla', 'Toyota', 32, 48), ('Clio', 'Renault', 25, 38), ('208', 'Peugeot', 26, 40), ('i20', 'Hyundai', 24, 36), ('Fabia', 'Skoda', 22, 34)]
}
COLORS = ['White', 'Black', 'Silver', 'Gray', 'Blue', 'Red', 'Green', 'Yellow', 'Brown', 'Orange']
TRANSMISSIONS = ['Automatic', 'Manual']
def create_directories():
base = CONFIG['output_dir']
dirs = [base, f"{base}/init", f"{base}/seed_data"]
for d in dirs:
os.makedirs(d, exist_ok=True)
print(f"📁 Created: {d}")
def write_file(path, content):
with open(os.path.join(CONFIG['output_dir'], path), 'w', encoding='utf-8') as f:
f.write(content)
print(f"📝 Created: {path}")
def generate_countries():
return [(i+1, code, name, prefix, currency) for i, (code, name, prefix, currency, _) in enumerate(EUROPEAN_COUNTRIES)]
def generate_cities():
cities = []
city_id = 1
for country_id, (code, _, _, _, _) in enumerate(EUROPEAN_COUNTRIES, 1):
for city_name in CITIES_BY_COUNTRY[code]:
cities.append((city_id, country_id, city_name, 'Europe/' + code))
city_id += 1
return cities
def escape_sql(val):
return str(val).replace("'", "''")
def main():
print("🚀 Rent A Car Database Setup Başlatılıyor...")
create_directories()
countries = generate_countries()
cities = generate_cities()
# 1. Schema
schema = """-- Complete Database Schema
CREATE TABLE IF NOT EXISTS countries (country_id SERIAL PRIMARY KEY, country_code CHAR(2) UNIQUE NOT NULL, country_name VARCHAR(100) NOT NULL, phone_prefix VARCHAR(5), currency_code CHAR(3));
CREATE TABLE IF NOT EXISTS cities (city_id SERIAL PRIMARY KEY, country_id INTEGER REFERENCES countries(country_id), city_name VARCHAR(100) NOT NULL, timezone VARCHAR(50));
CREATE TABLE IF NOT EXISTS branches (branch_id SERIAL PRIMARY KEY, branch_code VARCHAR(10) UNIQUE NOT NULL, branch_name VARCHAR(100) NOT NULL, city_id INTEGER REFERENCES cities(city_id), address TEXT, phone VARCHAR(20), email VARCHAR(100), opening_date DATE, is_active BOOLEAN DEFAULT true, capacity INTEGER);
CREATE TABLE IF NOT EXISTS vehicle_categories (category_id SERIAL PRIMARY KEY, category_name VARCHAR(50) NOT NULL, description TEXT);
CREATE TABLE IF NOT EXISTS fuel_types (fuel_type_id SERIAL PRIMARY KEY, fuel_type_name VARCHAR(50) NOT NULL, is_fossil BOOLEAN DEFAULT true);
CREATE TABLE IF NOT EXISTS vehicle_brands (brand_id SERIAL PRIMARY KEY, brand_name VARCHAR(50) NOT NULL, country_id INTEGER REFERENCES countries(country_id));
CREATE TABLE IF NOT EXISTS vehicle_models (model_id SERIAL PRIMARY KEY, brand_id INTEGER REFERENCES vehicle_brands(brand_id), model_name VARCHAR(50) NOT NULL, category_id INTEGER REFERENCES vehicle_categories(category_id), fuel_type_id INTEGER REFERENCES fuel_types(fuel_type_id), seat_count INTEGER DEFAULT 5, transmission_type VARCHAR(20), daily_rate_min DECIMAL(10,2), daily_rate_max DECIMAL(10,2));
CREATE TABLE IF NOT EXISTS vehicles (vehicle_id SERIAL PRIMARY KEY, license_plate VARCHAR(20) UNIQUE NOT NULL, model_id INTEGER REFERENCES vehicle_models(model_id), branch_id INTEGER REFERENCES branches(branch_id), manufacture_year INTEGER, color VARCHAR(30), mileage INTEGER DEFAULT 0, status VARCHAR(20) DEFAULT 'available', purchase_date DATE, daily_rate DECIMAL(10,2) NOT NULL, last_maintenance_date DATE, next_maintenance_date DATE);
CREATE TABLE IF NOT EXISTS customers (customer_id SERIAL PRIMARY KEY, first_name VARCHAR(50) NOT NULL, last_name VARCHAR(50) NOT NULL, email VARCHAR(100) UNIQUE NOT NULL, phone VARCHAR(20), date_of_birth DATE, country_id INTEGER REFERENCES countries(country_id), city_id INTEGER REFERENCES cities(city_id), address TEXT, driver_license_number VARCHAR(50), license_issue_date DATE, license_class VARCHAR(10), registration_date DATE DEFAULT CURRENT_DATE, is_verified BOOLEAN DEFAULT false, credit_score INTEGER CHECK (credit_score BETWEEN 0 AND 1000));
CREATE TABLE IF NOT EXISTS rentals (rental_id SERIAL PRIMARY KEY, rental_code VARCHAR(20) UNIQUE NOT NULL, customer_id INTEGER REFERENCES customers(customer_id), vehicle_id INTEGER REFERENCES vehicles(vehicle_id), pickup_branch_id INTEGER REFERENCES branches(branch_id), return_branch_id INTEGER REFERENCES branches(branch_id), pickup_date TIMESTAMP NOT NULL, return_date TIMESTAMP NOT NULL, actual_return_date TIMESTAMP, status VARCHAR(20) DEFAULT 'confirmed', daily_rate DECIMAL(10,2) NOT NULL, total_days INTEGER GENERATED ALWAYS AS (EXTRACT(DAY FROM (return_date - pickup_date))) STORED, subtotal DECIMAL(10,2), discount_amount DECIMAL(10,2) DEFAULT 0, tax_amount DECIMAL(10,2), total_amount DECIMAL(10,2), mileage_start INTEGER, mileage_end INTEGER, fuel_level_start VARCHAR(20), fuel_level_end VARCHAR(20), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP);
CREATE TABLE IF NOT EXISTS payments (payment_id SERIAL PRIMARY KEY, rental_id INTEGER REFERENCES rentals(rental_id), payment_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP, amount DECIMAL(10,2) NOT NULL, payment_method VARCHAR(30), transaction_id VARCHAR(100), status VARCHAR(20) DEFAULT 'completed', currency_code CHAR(3) DEFAULT 'EUR');
CREATE TABLE IF NOT EXISTS insurance_policies (policy_id SERIAL PRIMARY KEY, policy_name VARCHAR(100), coverage_type VARCHAR(50), daily_cost DECIMAL(10,2), max_coverage_amount DECIMAL(12,2));
CREATE TABLE IF NOT EXISTS rental_insurances (rental_id INTEGER REFERENCES rentals(rental_id), policy_id INTEGER REFERENCES insurance_policies(policy_id), PRIMARY KEY (rental_id, policy_id));
CREATE INDEX idx_vehicles_branch ON vehicles(branch_id); CREATE INDEX idx_vehicles_status ON vehicles(status); CREATE INDEX idx_customers_country ON customers(country_id); CREATE INDEX idx_rentals_customer ON rentals(customer_id); CREATE INDEX idx_rentals_dates ON rentals(pickup_date, return_date);"""
write_file("init/01-schema.sql", schema)
# 2. Countries
vals = [f"({c[0]}, '{c[1]}', '{c[2]}', '{c[3]}', '{c[4]}')" for c in countries]
write_file("seed_data/01_countries.sql", "INSERT INTO countries (country_id, country_code, country_name, phone_prefix, currency_code) VALUES\n" + ",\n".join(vals) + ";\n")
# 3. Cities
vals = [f"({c[0]}, {c[1]}, '{c[2]}', '{c[3]}')" for c in cities]
write_file("seed_data/02_cities.sql", "INSERT INTO cities (city_id, country_id, city_name, timezone) VALUES\n" + ",\n".join(vals) + ";\n")
# 4. Branches (300)
print("🏢 300 şube oluşturuluyor...")
branches = []
used_names = set()
for i in range(1, 301):
city = random.choice(cities)
prefix = random.choice(BRANCH_PREFIXES)
name = f"{prefix} {city[2]}"
counter = 1
while name in used_names:
name = f"{prefix} {city[2]} {counter}"
counter += 1
used_names.add(name)
code = f"BR{str(i).zfill(4)}"
address = escape_sql(fake.street_address())
phone = f"+{random.randint(1,99)} {random.randint(100000000, 999999999)}"
email = f"{name.lower().replace(' ', '.')}@rentacar.com"
opening = fake.date_between(start_date='-10y', end_date='-1y')
capacity = random.randint(20, 100)
branches.append(f"({i}, '{code}', '{escape_sql(name)}', {city[0]}, '{address}', '{phone}', '{email}', '{opening}', true, {capacity})")
write_file("seed_data/03_branches.sql", "INSERT INTO branches (branch_id, branch_code, branch_name, city_id, address, phone, email, opening_date, is_active, capacity) VALUES\n" + ",\n".join(branches) + ";\n")
# 5. Fuel Types & Categories
write_file("seed_data/04_fuel_types.sql", "INSERT INTO fuel_types (fuel_type_id, fuel_type_name, is_fossil) VALUES (1, 'Gasoline', true), (2, 'Diesel', true), (3, 'Electric', false), (4, 'Hybrid', false);\n")
write_file("seed_data/05_categories.sql", "INSERT INTO vehicle_categories (category_id, category_name) VALUES (1, 'SUV'), (2, 'Sedan'), (3, 'Hatchback');\n")
# 6. Brands
country_map = {code: i+1 for i, (code, _, _, _, _) in enumerate(EUROPEAN_COUNTRIES)}
country_map.update({'JP': 11, 'US': 12, 'KR': 13, 'SE': 14, 'CZ': 15, 'RO': 16})
brands = [(i, name, country_map.get(cc, 1)) for i, (name, cc) in enumerate(VEHICLE_BRANDS, 1)]
vals = [f"({b[0]}, '{b[1]}', {b[2]})" for b in brands]
write_file("seed_data/06_brands.sql", "INSERT INTO vehicle_brands (brand_id, brand_name, country_id) VALUES\n" + ",\n".join(vals) + ";\n")
# 7. Models
print("🚗 Araç modelleri oluşturuluyor...")
models = []
model_id = 1
brand_map = {name: i for i, (name, _) in enumerate(VEHICLE_BRANDS, 1)}
cat_map = {'SUV': 1, 'Sedan': 2, 'Hatchback': 3}
for cat, mlist in MODELS.items():
for mname, bname, minr, maxr in mlist:
bid = brand_map.get(bname, 1)
cid = cat_map[cat]
fid = 3 if 'Tesla' in bname else (1 if random.random() < 0.6 else 2)
seats = 5 if cat != 'SUV' else random.choice([5, 7])
trans = random.choice(TRANSMISSIONS)
models.append(f"({model_id}, {bid}, '{mname}', {cid}, {fid}, {seats}, '{trans}', {minr}, {maxr})")
model_id += 1
write_file("seed_data/07_models.sql", "INSERT INTO vehicle_models (model_id, brand_id, model_name, category_id, fuel_type_id, seat_count, transmission_type, daily_rate_min, daily_rate_max) VALUES\n" + ",\n".join(models) + ";\n")
# 8. Vehicles (3000) - Batch olarak
print(f"🚙 {CONFIG['total_vehicles']} araç oluşturuluyor...")
model_list = list(range(1, model_id))
used_plates = set()
batch_size = 500
for batch in range(0, CONFIG['total_vehicles'], batch_size):
vehicles = []
for i in range(batch + 1, min(batch + batch_size, CONFIG['total_vehicles']) + 1):
mid = random.choice(model_list)
bid = random.randint(1, 300)
plate = f"{random.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZ')}{random.randint(10000, 99999)}"
while plate in used_plates:
plate = f"{random.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZ')}{random.randint(10000, 99999)}"
used_plates.add(plate)
year = random.randint(2019, 2024)
color = random.choice(COLORS)
mile = random.randint(0, 150000)
status = random.choices(['available', 'rented', 'maintenance', 'retired'], weights=[70, 20, 8, 2])[0]
purch = fake.date_between(start_date=f'-{2024-year+1}y', end_date=f'-{2024-year}y')
rate = round(random.uniform(20, 150), 2)
last = fake.date_between(start_date='-1y', end_date='today')
next_m = last + timedelta(days=180)
vehicles.append(f"({i}, '{plate}', {mid}, {bid}, {year}, '{color}', {mile}, '{status}', '{purch}', {rate}, '{last}', '{next_m}')")
write_file(f"seed_data/08_vehicles_{batch//batch_size + 1}.sql", f"INSERT INTO vehicles (vehicle_id, license_plate, model_id, branch_id, manufacture_year, color, mileage, status, purchase_date, daily_rate, last_maintenance_date, next_maintenance_date) VALUES\n" + ",\n".join(vehicles) + ";\n")
# 9. Customers (350)
print(f"👥 {CONFIG['total_customers']} müşteri oluşturuluyor...")
tr_cities = [c for c in cities if c[1] == 6]
other_cities = [c for c in cities if c[1] != 6]
customers = []
for i in range(1, CONFIG['total_customers'] + 1):
city = random.choice(tr_cities) if random.random() < 0.15 else random.choice(other_cities)
fname = escape_sql(fake.first_name())
lname = escape_sql(fake.last_name())
email = f"{fname.lower()}.{lname.lower()}{random.randint(1,999)}@example.com"
phone = f"+{random.randint(1,99)}-{random.randint(100000000, 999999999)}"
dob = fake.date_of_birth(minimum_age=21, maximum_age=70)
addr = escape_sql(fake.street_address())
lic = f"DL{random.randint(10000000, 99999999)}"
lic_date = fake.date_between(start_date=dob + timedelta(days=365*18), end_date='-1y')
lic_class = random.choice(['B', 'B1', 'BE'])
reg = fake.date_between(start_date='-5y', end_date='today')
verified = random.random() < 0.9
score = random.randint(300, 850) if verified else random.randint(100, 500)
customers.append(f"({i}, '{fname}', '{lname}', '{email}', '{phone}', '{dob}', {city[1]}, {city[0]}, '{addr}', '{lic}', '{lic_date}', '{lic_class}', '{reg}', {verified}, {score})")
write_file("seed_data/09_customers.sql", "INSERT INTO customers (customer_id, first_name, last_name, email, phone, date_of_birth, country_id, city_id, address, driver_license_number, license_issue_date, license_class, registration_date, is_verified, credit_score) VALUES\n" + ",\n".join(customers) + ";\n")
# 10. Loader
loader = """\\i /seed_data/01_countries.sql
\\i /seed_data/02_cities.sql
\\i /seed_data/03_branches.sql
\\i /seed_data/04_fuel_types.sql
\\i /seed_data/05_categories.sql
\\i /seed_data/06_brands.sql
\\i /seed_data/07_models.sql
\\i /seed_data/08_vehicles_1.sql
\\i /seed_data/08_vehicles_2.sql
\\i /seed_data/08_vehicles_3.sql
\\i /seed_data/08_vehicles_4.sql
\\i /seed_data/08_vehicles_5.sql
\\i /seed_data/08_vehicles_6.sql
\\i /seed_data/09_customers.sql
INSERT INTO insurance_policies (policy_id, policy_name, coverage_type, daily_cost, max_coverage_amount) VALUES (1, 'Basic Coverage', 'basic', 15.00, 50000.00), (2, 'Full Protection', 'full', 35.00, 150000.00), (3, 'Premium Plus', 'premium', 55.00, 300000.00);"""
write_file("init/02-seed-loader.sql", loader)
# 11. Docker Compose
docker_compose = """version: '3.8'
services:
postgres:
image: postgres:15-alpine
container_name: rentacar_db
environment:
POSTGRES_DB: rentacar
POSTGRES_USER: admin
POSTGRES_PASSWORD: RentAcar2024!
PGDATA: /var/lib/postgresql/data/pgdata
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
- ./init:/docker-entrypoint-initdb.d
- ./seed_data:/seed_data
networks:
- rentacar_network
healthcheck:
test: ["CMD-SHELL", "pg_isready -U admin -d rentacar"]
interval: 10s
timeout: 5s
retries: 5
pgadmin:
image: dpage/pgadmin4:latest
container_name: rentacar_pgadmin
environment:
PGADMIN_DEFAULT_EMAIL: admin@rentacar.com
PGADMIN_DEFAULT_PASSWORD: admin123
PGADMIN_CONFIG_SERVER_MODE: 'False'
ports:
- "8080:80"
volumes:
- pgadmin_data:/var/lib/pgadmin
networks:
- rentacar_network
depends_on:
- postgres
networks:
rentacar_network:
driver: bridge
volumes:
postgres_data:
pgadmin_data:"""
write_file("docker-compose.yml", docker_compose)
# 12. how_to_use.md
how_to_use = """# Rent A Car Veritabanı - Kullanım Kılavuzu
## 🚀 Hızlı Başlangıç
```bash
# 1. Projeye git
cd rentacar-db
# 2. Docker ile başlat
docker-compose up -d
# 3. Veritabanının hazır olmasını bekle (10-15 saniye)
docker exec rentacar_db pg_isready -U admin -d rentacar
# 4. Bağlantı testi
docker exec -it rentacar_db psql -U admin -d rentacar -c "SELECT COUNT(*) FROM vehicles;"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment