"""Pricing query specifications — Phase 10.4.""" from __future__ import annotations from dataclasses import dataclass from uuid import UUID from sqlalchemy import Select, asc, desc, or_ from sqlalchemy.sql import ColumnElement from app.models.pricing import CapabilityBundle, CapabilityDefinition, PricingRule from app.models.types import CapabilityBundleStatus, CapabilityStatus, PricingRuleStatus RULE_SORT = frozenset({"created_at", "updated_at", "code", "name", "status"}) CAP_SORT = frozenset({"created_at", "updated_at", "code", "name", "status"}) BUNDLE_SORT = frozenset({"created_at", "updated_at", "code", "name", "status"}) @dataclass(frozen=True, slots=True) class PricingRuleListSpec: status: PricingRuleStatus | None = None organization_id: UUID | None = None q: str | None = None sort_by: str = "created_at" sort_dir: str = "desc" def filter_clauses(self) -> list[ColumnElement]: clauses: list[ColumnElement] = [] if self.status is not None: clauses.append(PricingRule.status == self.status) if self.organization_id is not None: clauses.append(PricingRule.organization_id == self.organization_id) if self.q: term = f"%{self.q.strip()}%" clauses.append( or_(PricingRule.code.ilike(term), PricingRule.name.ilike(term)) ) return clauses def apply(self, stmt: Select) -> Select: clauses = self.filter_clauses() if clauses: stmt = stmt.where(*clauses) sort_key = self.sort_by if self.sort_by in RULE_SORT else "created_at" column = getattr(PricingRule, sort_key) order = desc(column) if self.sort_dir.lower() != "asc" else asc(column) return stmt.order_by(order) @dataclass(frozen=True, slots=True) class CapabilityListSpec: status: CapabilityStatus | None = None q: str | None = None sort_by: str = "created_at" sort_dir: str = "desc" def filter_clauses(self) -> list[ColumnElement]: clauses: list[ColumnElement] = [] if self.status is not None: clauses.append(CapabilityDefinition.status == self.status) if self.q: term = f"%{self.q.strip()}%" clauses.append( or_( CapabilityDefinition.code.ilike(term), CapabilityDefinition.name.ilike(term), ) ) return clauses def apply(self, stmt: Select) -> Select: clauses = self.filter_clauses() if clauses: stmt = stmt.where(*clauses) sort_key = self.sort_by if self.sort_by in CAP_SORT else "created_at" column = getattr(CapabilityDefinition, sort_key) order = desc(column) if self.sort_dir.lower() != "asc" else asc(column) return stmt.order_by(order) @dataclass(frozen=True, slots=True) class BundleListSpec: status: CapabilityBundleStatus | None = None q: str | None = None sort_by: str = "created_at" sort_dir: str = "desc" def filter_clauses(self) -> list[ColumnElement]: clauses: list[ColumnElement] = [] if self.status is not None: clauses.append(CapabilityBundle.status == self.status) if self.q: term = f"%{self.q.strip()}%" clauses.append( or_( CapabilityBundle.code.ilike(term), CapabilityBundle.name.ilike(term), ) ) return clauses def apply(self, stmt: Select) -> Select: clauses = self.filter_clauses() if clauses: stmt = stmt.where(*clauses) sort_key = self.sort_by if self.sort_by in BUNDLE_SORT else "created_at" column = getattr(CapabilityBundle, sort_key) order = desc(column) if self.sort_dir.lower() != "asc" else asc(column) return stmt.order_by(order)