Formatting is layout, not validation
A SQL formatter re-indents clauses and can normalise keyword case. Measured: select a,b from t
where a=1 becomes SELECT a, / b / FROM t /
WHERE a = 1. The tokens are the same; only whitespace and case changed. That means a
formatted query can still be invalid, can still be slow, and can still be dangerous — the formatter
does not parse semantics or check that a table exists.
Dialects are the other limit. Quoting rules, LIMIT versus TOP, and
dialect-specific functions differ; a formatter that handles SELECT/JOIN/subqueries is not a SQL
validator. Format for readability, then run the query against the real engine (or EXPLAIN)
to learn whether it works.
Seeded test data
A seeded generator is deterministic: the same seed and the same columns produce the same rows. That is the property that makes fake data useful in tests — a failure on a generated name or date can be reproduced by keeping the seed, instead of photographing the output. The generator here also keeps identity fields consistent within a row: the email belongs to the name beside it, because columns are not independent when they describe one person.
| Field | What it is | What it is not |
|---|---|---|
| Name / email | Invented, repeatable from a seed | A real person or a valid inbox |
| Address | A plausible-looking street and city | A postal address that validates |
| UUID | A random v4 identifier | A durable key for production |
| Date | An ISO date in a fixed range | “Today” or a business date |
Formatting in a migration
A formatted query is easier to review, but the diff of a reformatted file can hide a semantic change in a wall of whitespace. Keep formatting commits separate from behaviour changes, or reviewers will scroll past the one line that matters. The same applies to generated SQL in an application: format it for logs and humans, but do not let a formatter rewrite a query whose quoting or dialect-specific syntax it does not fully understand.
Test data has a similar review problem. A fixture that is regenerated on every run produces a noisy diff; a fixture generated once from a seed is stable and reviewable. Commit the seed and the generator version, not the output alone, so the data can be reproduced when a test fails.
Generated data and privacy
Fake rows are not anonymised rows. A generated record has no relationship to a real person, which is what makes it safe for a demo and useless for privacy engineering: you cannot “swap the name” on a real record and call it anonymous, because the remaining fields can still identify someone. Generate into a test database, never into production, and keep the seed with the test so a failing case can be reproduced without storing the output.
Importing fixtures safely
CSV output quotes values that contain commas, quotes or newlines, so a standard importer reads it without a custom parser. Dates are ISO, which every importer reads unambiguously. The remaining risks are not formatting: a fixture loaded into a production database, a fake email that a test actually sends to, and a generated value that a uniqueness constraint rejects because the word lists are small. Keep the seed in the test, point the import at a test database, and do not treat generated rows as anonymised real data.
For a foreign key, a generator cannot invent a valid parent. Use a fixture factory that creates the parent first, then the child referencing it; the generator is for columns, not for referential integrity.