Skip to content

sqlseed Architecture

English | 中文

This document uses Mermaid diagrams to visualize sqlseed's overall architecture and internal module structures.


1. System Architecture

This page describes the five-package implementation on main; see migration for installation and differences from published packages. Core does not depend on entry-point plugins. DataStream belongs to Core; Web runtime and maintenance processes are covered in section 12.

graph TB
    subgraph User["👤 User Entry Points"]
        CLI["CLI<br/>click commands"]
        API["Python API<br/>fill / connect / preview"]
        YAML["YAML/JSON<br/>config files"]
        MCP["MCP Server<br/>AI assistant integration"]
    end

    subgraph Core["🧠 Core Orchestration (core/)"]
        Orch["DataOrchestrator<br/>main orchestrator"]
        Mapper["ColumnMapper<br/>9-level strategy chain"]
        Schema["SchemaInferrer<br/>schema inference"]
        Relation["RelationResolver<br/>FK resolution"]
        Pool["SharedPool<br/>cross-table value pool"]
        DAG["ColumnDAG<br/>column dependency graph"]
        Expr["ExpressionEngine<br/>expression evaluation"]
        Constraint["ConstraintSolver<br/>constraint backtracking"]
        Transform["TransformLoader<br/>script loading"]
        Result["GenerationResult<br/>result statistics"]
        Stream["DataStream<br/>streaming generation"]
        CheckParser["check_parser.py<br/>CHECK constraint parsing"]
        SchemaFallback["schema_fallback.py<br/>schema-only fallback generator"]
        Features["features.py<br/>normalized structural features"]
    end

    subgraph Gen["⚡ Generator Layer (generators/)"]
        Protocol["DataProvider<br/>Protocol"]
        Registry["ProviderRegistry<br/>registry"]
        Base["BaseProvider<br/>built-in"]
        Faker["FakerProvider<br/>Faker"]
        Mimesis["MimesisProvider<br/>Mimesis"]
    end

    subgraph DB["💾 Database Layer (database/)"]
        DBProto["DatabaseAdapter<br/>Protocol"]
        SU["SQLAlchemyAdapter<br/>required (SQLite/PostgreSQL)"]
        Raw["RawSQLiteAdapter<br/>test-only"]
        Pragma["PragmaOptimizer<br/>3-tier optimization"]
        Dialect["_dialect.py<br/>dialect abstraction"]
        TypeNorm["_type_normalizer.py<br/>type normalization"]
        BulkOpt["_bulk_optimizer.py<br/>bulk write optimization"]
        BaseAdapt["_base_adapter.py<br/>shared base"]
        Helpers["_helpers.py<br/>batch insert helpers"]
    end

    subgraph Plugin["🧩 Plugin Layer (plugins/)"]
        HookSpec["SqlseedHookSpec<br/>12 hooks"]
        PM["PluginManager<br/>pluggy"]
    end

    subgraph Config["⚙️ Config Layer (config/)"]
        Models["Pydantic Models<br/>GeneratorConfig"]
        Loader["Loader<br/>YAML/JSON"]
        Snapshot["SnapshotManager<br/>snapshot save/load"]
    end

    subgraph AI["🤖 AI Plugin (sqlseed-ai)"]
        Analyzer["SchemaAnalyzer<br/>LLM analysis"]
        Refiner["AiConfigRefiner<br/>self-correction loop"]
        Examples["Few-shot<br/>example library"]
        Errors["ErrorSummary<br/>error classification"]
        GemmaModel["GemmaModel<br/>Gemma 4 model adapter"]
        AIBackend["AIBackend<br/>multi-backend router"]
        GemmaTools["GEMMA_TOOLS<br/>Native Function Calling"]
    end

    subgraph Utils["🔧 Utilities (_utils/)"]
        SQL["sql_safe<br/>SQL injection protection"]
        Metrics["MetricsCollector<br/>performance metrics"]
        Progress["Progress<br/>multi-backend: Rich/tqdm/Null"]
        Paths["Paths<br/>platform cache dirs"]
        Logger["Logger<br/>structlog"]
    end

    CLI --> Orch
    API --> Orch
    YAML --> Loader --> Orch
    MCP --> Orch

    Orch --> Schema
    Orch --> Mapper
    Orch --> Relation
    Orch --> DAG
    Orch --> Stream
    Orch --> Pool
    Orch --> Result
    Orch --> PM

    DAG --> Expr
    DAG --> Constraint
    Stream --> Expr
    Stream --> Constraint
    Stream --> Transform
    Stream --> Protocol

    Mapper --> DBProto
    Schema --> DBProto
    Relation --> DBProto
    Relation --> Pool

    Registry --> Base
    Registry --> Faker
    Registry --> Mimesis
    Registry --> Protocol

    DBProto --> SU
    DBProto --> Raw
    SU --> Pragma
    Raw --> Pragma
    SU --> Dialect
    SU --> TypeNorm
    SU --> BulkOpt
    SU --> BaseAdapt
    SU --> Helpers
    Raw --> BaseAdapt
    Raw --> Helpers

    PM --> HookSpec
    PM --> AI

    Analyzer --> Refiner
    Refiner --> Errors
    Analyzer --> Examples
    AIBackend --> GemmaModel
    AIBackend --> Analyzer
    GemmaModel --> GemmaTools

    Orch --> Config

    Orch -.-> SQL
    Orch -.-> Metrics
    Orch -.-> Progress
    Orch -.-> Logger
    SU -.-> SQL
    Raw -.-> SQL
    SU -.-> Helpers
    Raw -.-> Helpers

2. Core Orchestration Flow (fill_table)

This diagram summarizes the normal execution path. Schema support preflight precedes clearing and writing. Ordinary Core batch execution can retain earlier committed batches after a later failure; check both errors and count as described in failure semantics.

sequenceDiagram
    participant U as User
    participant O as DataOrchestrator
    participant ST as DataStream (core)
    participant PM as PluginMediator
    participant DB as DatabaseAdapter
    participant P as RelationResolver / SharedPool

    U->>O: fill_table(table, count)
    O->>O: Connect, validate arguments, preflight schema support
    opt Database optimization enabled
        O->>DB: optimize_for_bulk_write(count)
    end
    O->>O: _prepare_specs (schema, CHECK, FK, rules, optional AI)
    O->>ST: _build_stream (seed, expressions, constraints)
    loop Streaming batches
        O->>ST: generate(count, batch_size)
        ST-->>O: batch
        O->>PM: apply_batch_transforms(table, batch)
        PM-->>O: Last non-None result or original batch
        O->>DB: batch_insert(table, batch)
        DB-->>O: Actual inserted count
        O->>O: Record completed batches
    end
    O->>DB: restore_settings (finally)
    O->>P: register_shared_pool(table, specs)
    O->>O: Supported self-referencing FK post-processing
    O-->>U: GenerationResult (count / errors)

3. ColumnMapper 9-Level Strategy Chain

flowchart TD
    Start["map_column(column_info, user_config)"] --> L1{"L1: Computed or explicit autoincrement PK?"}
    L1 -->|Yes| Skip["Skip generation"]
    L1 -->|No| L2{"L2: Explicit user config?"}
    L2 -->|Yes| Done["Return rule"]
    L2 -->|No| Rowid{"SQLite rowid alias?"}
    Rowid -->|Yes| Skip
    Rowid -->|No| IntegerPK{"Other integer primary key?"}
    IntegerPK -->|Yes| L9["L9: SQL type fallback"]
    IntegerPK -->|No| L3{"L3: Custom then built-in exact match<br/><!-- BEGIN:AUTO-GENERATED:exact-match-rule-count -->75<!-- END:AUTO-GENERATED:exact-match-rule-count --> built-in rules"}
    L3 -->|Yes| Done
    L3 -->|No| L4{"L4: Default value handling"}
    L4 -->|Yes| Done
    L4 -->|No| L5{"L5: Custom then built-in pattern match<br/><!-- BEGIN:AUTO-GENERATED:pattern-match-rule-count -->29<!-- END:AUTO-GENERATED:pattern-match-rule-count --> built-in patterns"}
    L5 -->|Yes| Done
    L5 -->|No| L6{"L6: CamelCase to snake_case exact retry"}
    L6 -->|Yes| Done
    L6 -->|No| L7{"L7: snake_case pattern retry"}
    L7 -->|Yes| Done
    L7 -->|No| L8{"L8: Nullable fallback"}
    L8 -->|Yes| Done
    L8 -->|No| L9
    L9 --> Done

Default and nullable handling returns skip, enrichment, or type fallback according to enrich / force_type_infer. Adapters identify SQLite rowid aliases explicitly; unknown legacy hand-built ColumnInfo metadata retains compatibility handling. Parameter inheritance and BLOB type guards remain part of mapper.py beyond this priority diagram.


4. Providers and Core Streaming

Providers and dispatch live in generators/. The DataStream, expression, and constraint consumers shown here belong to core/; generators do not import Core.

classDiagram
    class DataProvider {
        <<Protocol>>
        +name: str
        +set_locale(locale: str)
        +set_seed(seed: int)
        +generate(type_name: str, **params) Any
        ... dispatches via GENERATOR_MAP to 36 internal methods
    }

    class BaseProvider {
        -_rng: Random
        -_locale: str
        +name = "base"
        built-in synthesized values
    }

    class FakerProvider {
        -_faker: Faker
        +name = "faker"
        required core dependency
    }

    class MimesisProvider {
        -_generic: Generic
        +name = "mimesis"
        optional, high-performance
    }

    class ProviderRegistry {
        -_providers: dict
        -_default_name: str
        +register(provider)
        +get(name) DataProvider
        +ensure_provider(name)
        +register_from_entry_points()
    }

    class DataStream {
        -_nodes: list~ColumnNode~
        -_provider: DataProvider
        -_expr_engine: ExpressionEngine
        -_constraint_solver: ConstraintSolver
        -_rng: Random
        +generate(count, batch_size) Iterator
        -_generate_row() dict
        -_apply_generator(spec) Any
    }

    DataProvider <|.. BaseProvider
    DataProvider <|.. FakerProvider
    DataProvider <|.. MimesisProvider
    ProviderRegistry o-- DataProvider
    DataStream --> DataProvider
    DataStream --> ExpressionEngine
    DataStream --> ConstraintSolver

5. Database Layer Architecture

classDiagram
    class DatabaseAdapter {
        <<Protocol>>
        +connect(db_path: str)
        +close()
        +get_table_names() list~str~
        +get_column_info(table) list~ColumnInfo~
        +get_primary_keys(table) list~str~
        +get_foreign_keys(table) list~ForeignKeyInfo~
        +get_row_count(table) int
        +get_column_values(table, col, limit) list
        +get_index_info(table) list~IndexInfo~
        +get_unique_constraints(table) list~IndexInfo~
        +get_check_constraints(table) list~CheckConstraintInfo~
        +get_sample_rows(table, limit) list~dict~
        +batch_insert(table, data, batch_size) int
        +clear_table(table)
        +optimize_for_bulk_write(expected_rows)
        +restore_settings()
        +execute(sql, params) Any
    }

    class ColumnInfo {
        <<frozen dataclass>>
        +name: str
        +type: str
        +nullable: bool
        +default: Any
        +is_primary_key: bool
        +is_autoincrement: bool
        +is_computed: bool
        +is_rowid_alias: bool | None
    }

    class ForeignKeyInfo {
        <<frozen dataclass>>
        +column: str
        +ref_table: str
        +ref_column: str
        +constraint_id: int | None
        +ref_schema: str | None
    }

    class IndexInfo {
        <<frozen dataclass>>
        +name: str
        +table: str
        +columns: tuple~str~
        +unique: bool
        +is_partial: bool
        +predicate: str | None
    }

    class CheckConstraintInfo {
        <<frozen dataclass>>
        +name: str
        +table: str
        +columns: tuple~str~
        +expression: str
    }

    class SQLAlchemyAdapter {
        -_db: Database
        -_optimizer: PragmaOptimizer
        required core dependency
        uses SQLAlchemy
    }

    class RawSQLiteAdapter {
        -_conn: Connection
        -_optimizer: PragmaOptimizer
        test-only fallback
        uses sqlite3
    }

    class PragmaOptimizer {
        -_original: PragmaProfile
        +preserve()
        +optimize(expected_rows)
        +restore()
        -_apply_light()
        -_apply_moderate()
        -_apply_aggressive()
    }

    DatabaseAdapter <|.. SQLAlchemyAdapter
    DatabaseAdapter <|.. RawSQLiteAdapter
    SQLAlchemyAdapter --> PragmaOptimizer
    RawSQLiteAdapter --> PragmaOptimizer
    DatabaseAdapter --> ColumnInfo
    DatabaseAdapter --> ForeignKeyInfo
    DatabaseAdapter --> IndexInfo
    DatabaseAdapter --> CheckConstraintInfo

ColumnInfo.is_rowid_alias is explicit for adapter metadata; its None default preserves legacy constructors. SQLite detects real rowid aliases separately from explicit AUTOINCREMENT and preserves ordinary nullable primary keys. IndexInfo.is_partial prevents treating conditional uniqueness as unconditional. SQLAlchemy retains the reflected WHERE SQL in predicate; raw SQLite metadata may omit its text. The database evaluates predicates during writes. FK metadata retains per-table constraint identity and reflected parent schema.

6. Column Dependency DAG & Constraint Backtracking

flowchart LR
    subgraph DAG["ColumnDAG Topological Sort"]
        project_no["project_no<br/>pattern: PRJ-\\d{6}<br/>unique: true"]
        short_code_node["short_code<br/>derive_from: project_no<br/>expression: value[-6:]<br/>unique: true"]
        region_code["region_code<br/>derive_from: project_no<br/>expression: value[-4:]"]
        member_no["member_no<br/>pattern: M-\\d{4}<br/>unique: true"]
    end

    project_no --> short_code_node
    project_no --> region_code

    subgraph Backtrack["Constraint Solving (Backtracking)"]
        direction TB
        Gen1["Generate project_no = PRJ-004231"]
        Derive1["Compute short_code = 004231"]
        Check1{"short_code<br/>unique?"}
        Success["✅ Registered"]
        Fail["❌ Already exists"]
        BT["🔄 Backtrack: undo project_no<br/>regenerate"]

        Gen1 --> Derive1 --> Check1
        Check1 -->|Yes| Success
        Check1 -->|No| Fail --> BT --> Gen1
    end

7. AI Plugin Architecture

The AI plugin retains distinct entry points. Single-table ai-suggest uses SchemaAnalyzer and AiConfigRefiner; ai-analyze defaults to AutoHealOrchestrator, while auto-heal repairs an existing configuration. sqlseed_ai.runtime constructs configuration, clients, and heal orchestrators; terminal output and exit codes remain in CLI. Web requests reviewable suggestions through Python services.

flowchart TB
    Suggest["ai-suggest / AI hooks / AI MCP"] --> Analyzer[SchemaAnalyzer]
    Analyzer --> Refiner["AiConfigRefiner: validation and bounded retries"]
    Analyze["ai-analyze / auto-heal"] --> Runtime[sqlseed_ai.runtime]
    Runtime --> AutoHeal[AutoHealOrchestrator]
    AutoHeal --> Contracts["Rule contracts, validation and repair"]
    Web["Web AI assistant"] --> Services["AI Python services"]
    Refiner --> Rules["YAML rules / analysis results"]
    Contracts --> Rules
    Services --> Review["User reviews suggestions"]
    Review --> Rules
    Rules --> Core["Offline Core: explicit preview or fill"]

ai-suggest --auto-heal selects the full healing path and processes all tables. The AI MCP tool sqlseed_gemma4_agent_fill is a separate analysis-and-execution entry point; ordinary analysis commands and Web suggestions do not automatically write to the database. Model connectivity, output quality, and supported schema features need separate verification.


8. Plugin Hook Lifecycle

flowchart TB
    Start(["DataOrchestrator starts"]) --> Connect

    Connect["_ensure_connected()"]
    Connect --> H1["🔌 sqlseed_register_providers"]
    Connect --> H2["🔌 sqlseed_register_column_mappers"]

    H1 --> Fill["fill_table()"]
    H2 --> Fill

    Fill --> Mapping["Column mapping"]
    Mapping --> Mediation["sqlseed_apply_ai_suggestions<br/>(firstresult, optional AI plugin)"]
    Mediation --> H3["🤖 sqlseed_ai_analyze_table<br/>(firstresult)"]

    H3 --> Template["Template pool"]
    Template --> H4["🤖 sqlseed_pre_generate_templates<br/>(firstresult)"]

    H4 --> H5["📢 sqlseed_before_generate"]

    H5 --> BatchLoop

    subgraph BatchLoop["Batch Loop"]
        direction TB
        GenBatch["DataStream generates a batch"]
        H7["🔄 sqlseed_transform_batch<br/>(same batch; last non-None result)"]
        H8["📢 sqlseed_before_insert"]
        Insert["batch_insert()"]
        H9["📢 sqlseed_after_insert"]

        GenBatch --> H7 --> H8 --> Insert --> H9
    end

    BatchLoop --> H10["📢 sqlseed_after_generate"]

    H10 --> RegisterPool["RelationResolver.register_shared_pool()"]
    RegisterPool --> H11["📢 sqlseed_shared_pool_loaded"]

    H11 --> Done(["Return GenerationResult"])

    style H3 fill:#FF9800,color:#fff
    style H4 fill:#FF9800,color:#fff

sqlseed_transform_row is declared and can have plugin implementations, but normal Core generation does not dispatch it. The batch hook shown here is invoked. A YAML transform script and its transform_row(row, ctx) function use a separate implemented configuration path, not this pluggy hook.


9. Config Model Hierarchy

For source columns, params accepts a mapping; omitted or null values retain the empty-parameter behavior. Strings, lists, and other non-mapping values are rejected during configuration loading instead of silently discarding the rules. Top-level generator arguments still override keys in nested params.

classDiagram
    class GeneratorConfig {
        +db_path: str | None
        +url: str | None
        +provider: ProviderType = MIMESIS
        +locale: str = "en_US"
        +tables: list~TableConfig~
        +associations: list~ColumnAssociation~
        +custom_column_mappings: CustomColumnMappings | None
        +optimize_pragma: bool = True
        +snapshot_dir: str | None
        +log_level: str | None (deprecated)
    }

    class TableConfig {
        +name: str
        +count: int = 1000
        +batch_size: int = 5000
        +columns: list~ColumnConfig~
        +clear_before: bool = False
        +seed: int | None
        +transform: str | None
        +enrich: bool = False
    }

    class ColumnConfig {
        +name: str
        --- Source mode ---
        +generator: str | None
        +provider: ProviderType | None
        +params: dict
        +null_ratio: float = 0.0
        --- Derived mode ---
        +derive_from: str | list~str~ | None
        +expression: str | None
        --- Constraints ---
        +constraints: ColumnConstraintsConfig | None
        --- Native method overrides ---
        +faker_method: str | None
        +mimesis_method: str | None
        +native_params: dict
        +validate_column_mode() ⚠️ mutually exclusive
    }

    class ColumnConstraintsConfig {
        +unique: bool = False
        +min_value: number | None
        +max_value: number | None
        +regex: str | None
        +max_retries: int = 100 (ge=0)
    }

    class ColumnAssociation {
        +column_name: str
        +source_table: str
        +source_column: str | None = None
        +target_tables: list~str~
        +strategy: Literal["shared_pool", "random"] = "shared_pool"
    }

    class ProviderType {
        <<enum>>
        BASE
        FAKER
        MIMESIS
        CUSTOM
    }

    GeneratorConfig o-- TableConfig
    GeneratorConfig o-- ColumnAssociation
    GeneratorConfig --> ProviderType
    TableConfig o-- ColumnConfig
    ColumnConfig o-- ColumnConstraintsConfig
    ColumnConfig --> ProviderType

10. MCP Server Architecture

flowchart LR
    subgraph Client["AI Assistant (Claude/Cursor/...)"]
        Request["MCP Request"]
    end

    subgraph MCPServer["mcp-server-sqlseed (FastMCP) — core, rule-driven, no LLM"]
        Tool2["🤖 sqlseed_generate_yaml<br/>Rule-driven via ColumnMapper → YAML"]
        Tool3["⚡ sqlseed_execute_fill<br/>Execute data generation"]
    end

    subgraph AIMCP["sqlseed-ai[mcp] (FastMCP) — AI, LLM-driven"]
        ToolAI["🤖 sqlseed_ai_generate_yaml<br/>AI analysis → self-correction → YAML"]
        Tool4["💎 sqlseed_gemma4_analyze<br/>Gemma 4 native function calling analysis"]
        Tool5["💎 sqlseed_gemma4_agent_fill<br/>Gemma 4 agent-driven data fill"]
        Tool6["💎 sqlseed_list_gemma_models<br/>List registered Gemma 4 variants"]
    end

    subgraph SQLSeed["sqlseed Core"]
        Orchestrator["DataOrchestrator"]
        SchemaCtx["get_schema_context()"]
        Mapper["ColumnMapper"]
    end

    subgraph AIPlugin["sqlseed-ai"]
        SA["SchemaAnalyzer"]
        ACR["AiConfigRefiner"]
    end

    Request --> Tool2
    Request --> Tool3
    Request --> ToolAI
    Request --> Tool4
    Request --> Tool5
    Request --> Tool6

    Tool2 --> Mapper
    Tool3 --> Orchestrator
    ToolAI --> SA --> ACR
    Tool4 --> SA
    Tool5 --> Orchestrator
    Tool6 --> SA

    SchemaCtx --> Orchestrator

11. Gemma 4 Tool-Calling Protocol

This is the structured-response path in SchemaAnalyzer. AIConfig resolves gemma4, openai, or none against the active backend. Tool-call arguments are parsed and validated locally; this path does not register arbitrary Core tools or execute a multi-turn loop that injects tool_result messages.

flowchart TD
    Context["Schema context and generation prompt"] --> Protocol[resolve_tool_calling_protocol]
    Protocol -->|gemma4 / openai| Request["GEMMA_TOOLS + tool_choice auto"]
    Request --> Response["analyze_schema arguments or text response"]
    Response --> Parse["JSON parsing and local validation"]
    Request -->|unsupported tool calling| Fallback["Cloud JSON mode / local text mode"]
    Protocol -->|none| Fallback
    Fallback --> Parse
    Parse --> Result["Analysis result or explicit error"]

See Gemma 4 integration for protocol/backend limits. Model availability depends on the actual service; the project model registry is not a guarantee that an endpoint hosts a particular model.

12. Web workbench and component lifecycle

The project contains five distributions: Core, CLI, AI, MCP and Web. Web calls offline core directly; optional AI Python services produce user-requested suggestions, and accepted rules can run offline. The supervisor coordinates business and maintenance workers during component changes. Availability requires both distribution metadata and successful imports; removing a component preserves configuration and explains affected features. See the Web guide and support scope.

flowchart LR
    Browser[Browser workbench] --> HTTP[FastAPI / Web state]
    HTTP --> Runtime[Web runtime]
    Runtime --> Core[Offline Python core]
    HTTP -. optional suggestions .-> AI[AI Python services]
    Supervisor[Supervisor] --> HTTP
    Supervisor --> Maintenance[Package maintenance worker]