from sqlalchemy import Column, Integer, String, Float, DateTime, ForeignKey, Text from sqlalchemy.orm import relationship from sqlalchemy.ext.declarative import as_declarative, declared_attr from sqlalchemy.sql import func from pydantic import BaseModel from typing import Optional @as_declarative() class Base: @declared_attr def __tablename__(cls): return cls.__name__.lower() # Automatically apply nullable=False to ForeignKey columns unless explicitly set @staticmethod def Column(*args, **kwargs): if any(isinstance(arg, ForeignKey) for arg in args) and 'nullable' not in kwargs: kwargs['nullable'] = False return Column(*args, **kwargs) # Enum for User Role from sqlalchemy import Enum from enum import Enum as PyEnum class UserRole(PyEnum): PRIVATE = "PRIVATE" BUSINESS = "BUSINESS" # User model class User(Base): __tablename__ = 'users' id = Column(Integer, primary_key=True, autoincrement=True) name = Column(String, nullable=False) company = Column(String, nullable=True) address = Column(String, nullable=False) postcode = Column(Integer, nullable=False) city = Column(String, nullable=False) latitude = Column(String, nullable=True) longitude = Column(String, nullable=True) phone = Column(String, nullable=False) privatePhone = Column(String, nullable=True) email = Column(String, unique=True, nullable=False) cvr = Column(String, nullable=True) password = Column(String, nullable=False) role = Column(Enum(UserRole), default=UserRole.PRIVATE) updatedAt = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now()) createdAt = Column(DateTime(timezone=True), server_default=func.now()) auctions = relationship('Auction', back_populates='user') accounts = relationship('Account', back_populates='user') sessions = relationship('Session', back_populates='user') bids = relationship('Bid', back_populates='user') # Vehicle model class Vehicle(Base): __tablename__ = 'vehicles' id = Column(Integer, primary_key=True, autoincrement=True) brand = Column(String, nullable=False) model = Column(String, nullable=False) variant = Column(String, nullable=True) year = Column(Integer, nullable=False) kilometers = Column(Integer, nullable=False) condition = Column(String, nullable=False) location = Column(String, nullable=False) latitude = Column(String, nullable=True) longitude = Column(String, nullable=True) gasType = Column(String, nullable=False) images = Column(Text, nullable=False) # Store image paths or references description = Column(String, nullable=False) service = Column(String, nullable=False) inspectedAt = Column(DateTime(timezone=True), nullable=True) updatedAt = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now()) createdAt = Column(DateTime(timezone=True), server_default=func.now()) auctions = relationship('Auction', back_populates='vehicle') equipment = relationship('VehicleEquipment', back_populates='vehicle') # Equipment model class Equipment(Base): __tablename__ = 'equipment' id = Column(Integer, primary_key=True, autoincrement=True) name = Column(String, nullable=False) vehicles = relationship('VehicleEquipment', back_populates='equipment') # Vehicle-Equipment association table class VehicleEquipment(Base): __tablename__ = 'vehicle_equipment' vehicle_id = Column(Integer, ForeignKey('vehicles.id'), primary_key=True) equipment_id = Column(Integer, ForeignKey('equipment.id'), primary_key=True) vehicle = relationship('Vehicle', back_populates='equipment') equipment = relationship('Equipment', back_populates='vehicles') # Auction model class Auction(Base): __tablename__ = 'auctions' id = Column(Integer, primary_key=True, autoincrement=True) vehicleId = Column(Integer, ForeignKey('vehicles.id'), nullable=False) userId = Column(Integer, ForeignKey('users.id'), nullable=False) askingPrice = Column(Float, nullable=False) description = Column(String, nullable=True) updatedAt = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now()) createdAt = Column(DateTime(timezone=True), server_default=func.now()) user = relationship('User', back_populates='auctions') vehicle = relationship('Vehicle', back_populates='auctions') bids = relationship('Bid', back_populates='auction') # Bid model class Bid(Base): __tablename__ = 'bids' id = Column(Integer, primary_key=True, autoincrement=True) auctionId = Column(Integer, ForeignKey('auctions.id'), nullable=False) userId = Column(Integer, ForeignKey('users.id'), nullable=False) bid = Column(Float, nullable=False) updatedAt = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now()) createdAt = Column(DateTime(timezone=True), server_default=func.now()) auction = relationship('Auction', back_populates='bids') user = relationship('User', back_populates='bids') # Account model class Account(Base): __tablename__ = 'accounts' id = Column(Integer, primary_key=True, autoincrement=True) userId = Column(Integer, ForeignKey('users.id'), nullable=False) type = Column(String, nullable=False) provider = Column(String, nullable=False) providerAccountId = Column(String, nullable=False) refresh_token = Column(String, nullable=True) access_token = Column(String, nullable=True) expires_at = Column(Integer, nullable=True) user = relationship('User', back_populates='accounts') # Session model class Session(Base): __tablename__ = 'sessions' id = Column(Integer, primary_key=True, autoincrement=True) sessionToken = Column(String, unique=True, nullable=False) userId = Column(Integer, ForeignKey('users.id')) expires = Column(DateTime, nullable=False) user = relationship('User', back_populates='sessions') # VerificationToken model class VerificationToken(Base): __tablename__ = 'verification_tokens' identifier = Column(String, primary_key=True) token = Column(String, unique=True, nullable=False) expires = Column(DateTime, nullable=False) # Pydantic model for user registration class UserCreate(BaseModel): email: str password: str name: str phone: str address: str postcode: int city: str role: str company: Optional[str] = None privatePhone: Optional[str] = None cvr: Optional[str] = None class UserLogin(BaseModel): email: str password: str