Schema Adaptation

Schema adaptation is the step that makes the tool general: given a database it has never seen, it decides what each table represents and how its columns should be populated. This chapter describes how that inference works and, just as important, where it is fallible.

Reflection first

Adaptation starts from facts, not guesses. Through SQLAlchemy’s inspector the analyzer reads the concrete structure of the database: tables, columns and their types, primary keys, and foreign-key constraints. None of this is inferred; it is read directly from the schema. Everything the tool decides is built on top of this factual layer.

Entity classification

On top of structure, the analyzer assigns each table an entity type (user, customer, product, order, review, category, and a handful of others, with unknown as the explicit fallback). Classification scores the table’s name against sets of patterns associated with each type and takes the best match.

This is a heuristic, and heuristics have edges. The design accepts that classification will sometimes be wrong and makes wrongness cheap through the The Fallback Ladder and through generated code you can edit. It does not pretend the classifier is authoritative.

A worked limitation

A concrete example of the edge, preserved because it is instructive: substring matching does not always align with human intuition about word membership. A table named categories is not matched by the pattern category, because categories decomposes as categori + es, and category is not a substring of it. The result is that a plainly-named table can land in the unknown bucket.

This is documented rather than papered over for a reason. It is exactly the kind of case where the ladder earns its place: an unknown table still generates, one rung lower, from its column names and types. The classifier being imperfect is survivable by design.

Relationship and rule detection

Two further inferences ride on the structural layer:

  • Relationships. Foreign keys are turned into explicit relationships, which the Generator Factory uses to order table generation so that referenced rows exist before the rows that reference them.

  • Business rules. Recurring structural shapes become candidate rules: a non-null unique email, a numeric column that is always positive. These are reported with a confidence and inform generation where they apply.

Known fidelity gaps

A few limits are worth stating so they are not mistaken for bugs:

  • Loosely typed columns with non-obvious names. A column whose name signals a date or timestamp (created_at, *_date) is generated as a date even when it is declared TEXT. A loosely typed column whose name gives no such signal is generated from its declared type, so a TEXT column holding, say, encoded JSON becomes text. Correcting it is a one-line edit in the generated code.

  • Arbitrary unique and composite constraints. Uniqueness is enforced for well-known columns such as email, and primary keys are generated as contiguous sequential integers across every template. General unique constraints and composite keys are not yet enforced during generation.

These are on the roadmap under constraint fidelity, and they are the kind of gap the “generated code is the product” principle is designed to make trivial to close in the meantime. The post-generation constraint check (see Architecture) reports any that a given dataset violates.