From 6b0a2a60a820e35f95fca9eaa33f0f0b02980f1a Mon Sep 17 00:00:00 2001 From: Lilleman auf Larv Date: Fri, 18 Sep 2026 19:55:50 +0200 Subject: [PATCH] Record the audience, the id cardinality, the date ranges and why --list stays a plain path list --- CHANGELOG.md | 25 +++++++++++++++++-------- README.md | 40 +++++++++++++++++++++++++++++++++++----- todo.md | 10 +++++++--- 3 files changed, 59 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b381224..dd20ec2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,15 +34,24 @@ replacement, and each removed path, column or flag. `en_US.address` read those records, so `en_US.address.street` no longer carries `name` and `suffix`, and a locale folder loads only beside `geo`. - `{date(from,to,'layout')}` and `{time('layout')}`: a second between two days, or - within one, in a quoted Go layout. `sv_SE.date`, `en_US.date`, `sv_SE.time` and - `en_US.time` render through them, so `date.year`, `date.month`, `date.day` and - `time.hour` are no longer paths, and `misc.datetime` is an RFC 3339 instant. + within one, in a single-quoted Go layout, drawn in UTC; `from` may equal `to`. + `sv_SE.date`, `en_US.date`, `sv_SE.time` and `en_US.time` render through them, so + `date.year`, `date.month`, `date.day`, `time.hour`, `time.minute`, `time.minute.t`, + `time.sec` and `time.ampm` are no longer paths — a part of a date is now its own + `{date(…,'2006')}`. `misc.datetime` is an RFC 3339 instant. - `sex`, `first-name` and `last-name` tables in `sv_SE` and `en_US`, weighted by bearers from SCB, the SSA and the Census Bureau; `first-name` links to `sex`, and a name both sexes carry is a row under each. `person` reads them, so its columns are - `first`, `last`, `prefix` and `sex`, and `person.femalefirst` and - `person.malefirst` are no longer paths. + `first`, `last`, `prefix` and `sex`; `person.femalefirst` and `person.malefirst` are + no longer paths — draw `sex[f].first-name` and `sex[m].first-name` instead. + `en_US.title` links to `sex` as well, so `en_US.person.prefix` draws `Mr` or `Ms` + without contradicting the record's `sex`. - `sv_SE.personnummer` and `sv_SE.samordningsnummer`, Skatteverket's test series - from a `sv_SE.birth-number` table under `sex`, in place of `sv_SE.ssn`; `en_US.ssn` - in the ranges the SSA assigns, and `en_US.itin`. `en_US.person.prefix` no longer - draws `Mr`, `Mrs`, `Ms` or `Miss`, which could contradict the record's `sex`. + from a `sv_SE.birth-number` table under `sex`, in place of `sv_SE.ssn`, whose + `ssn.mmdd`, `ssn.mmdd.m` and `ssn.mmdd.d` go with it. `en_US.ssn` now draws the + ranges the SSA assigns and carries the columns `area`, `group` and `serial`, so + `--format csv en_US.ssn` writes a header where it used to fail; `en_US.itin` is new. +- An error names a spelling that runs: a layout is named single-quoted and free of + its own quotes, a row of a table with no key is named as the path that selects it, + `sv_SE.sex[f].first-name[Kim]`, and a category with no columns names the record + that gives it one. diff --git a/README.md b/README.md index 50b066f..e1f97d8 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ fejkdata 'geo.SE.locality[Lund].street' # Fjelievägen — a linked tabl fejkdata --data-path ./mydata sv_SE.word # layer a directory over the shipped data fejkdata --no-shipped-data -d ./mydata --list # only your data fejkdata 'name: {/sv_SE.person.last}' # name: — an inline template +fejkdata "{date(1990-01-01,2010-12-31,'2006-01-02')}" # 2003-11-27 — the argument in "…", the layout in '…' fejkdata '{"format":"name: {x}","x":["bosse","lina"]}' # name: bosse or name: lina ``` @@ -237,7 +238,16 @@ draws a woman's name, and a name both sexes carry is a row under each, so `person` reads one draw of the three, so its `first` and `sex` columns agree, and so does a `personnummer` in the same render: its birth number, `sv_SE.birth-number` under `sex`, is Skatteverket's test series, 238 for a woman and 239 for a man, which no -real person is ever given. +real person is ever given. `en_US.title` links to `sex` too, so a person's prefix +never contradicts it. + +A person of a chosen sex is assembled from the tables — `sex[f].first-name` beside +`last-name` — while a shipped `personnummer` agrees with the sex its own render +*drew*, not with one a path selects. That test series is also small: a personnummer +is one of about 70,000 values, a day in 1930–2025 against the two birth numbers, so a +fixture past a few hundred rows repeats one and a `UNIQUE` column needs a category of +your own. `sv_SE.date` and `en_US.date` are uniform over 1970-01-01 to 2029-12-31, +`misc.datetime` over 2000-01-01 to 2029-12-31. A `geo` folder holds one tree per country under its alpha-2 code: five [linked tables](#linked-tables) named alike, and an `address` record over one @@ -536,12 +546,14 @@ them a birthdate: Renders e.g. `811218-2389`. A layout is Go's: the reference time `Mon Jan 2 15:04:05 MST 2006` spelled as the output should look, quoted, since a layout may carry the comma that separates arguments, with English names. Every second -between the two days is reachable, so a layout with a clock draws the time too. +between the two days is reachable, so a layout with a clock draws the time too, and +`from` may equal `to`, which is that one day. The instant is UTC, so a zone in the +layout prints `UTC` or `Z`. The quotes delimit a layout outside a selector only, so `[O'Fallon]` in an argument stays a name. Rejected at `New`: a bound that is no calendar date, or not -before the other; an unquoted layout, naming the quoted one; a layout naming no field, which is text; -for `date` a layout naming no date field, naming `time`; and for `time` a layout -naming a date field, naming `date`. `{seq()}` spans `Fake` +before the other; an unquoted layout, naming the single-quoted one; a layout naming no field, which is +text, as is one day in a layout with no clock; for `date` a layout naming no date +field, naming `time`; and for `time` a layout naming a date field, naming `date`. `{seq()}` spans `Fake` calls and `repeat`, resets with a new generator, and is the natural primary key for the SQL example above. @@ -721,6 +733,15 @@ datatype and nullability, and each table's key, name, weight and parent columns; changes it or `data/` adds its `CHANGELOG.md` entry, which CI checks. A removed, renamed or retyped line is a major. +## Audience + +App developers writing tests and fixtures, in Go and at a shell: + +- a **bulk fixture author**, thousands of rows into CSV or SQL +- a **Go test author**, filling a struct with `FakeStruct` +- a **hand fixture author**, one value at a shell +- a **validator-facing author**, who needs a value a real checker accepts + ## Goals 1. **Valid by construction** — every value passes the check its real consumer @@ -1063,12 +1084,21 @@ renamed or retyped line is a major. bigger neighbour ship no address; counting the land outside every place too would drop a quarter of the places, whose codes straddle unincorporated land, for a postal city the USPS mostly names the same way. +- **`--list` stays a plain list of paths.** It is what a script reads, so every line + has to be a path that `Fake` takes; a marker for the tables a `[selector]` follows, + or a legend above them, would make the output something to parse before use. + `--help` names the selector spelling instead, and the Table section teaches it. - **A layout is always quoted.** A layout may carry the comma that separates arguments, `'January 2, 2006'`, and one spelling for every layout beats a rule about which ones need the quotes, so the bare spelling is refused naming the quoted one. The layout is Go's reference time because the library renders with it and a Go caller already knows it; its names are English, and a locale's own month and weekday names are data. +- **A title is a table under `sex`.** A prefix drawn apart would put `Mr` on a record + whose `sex` column says `female`, which is the disagreement the record exists to + prevent; the tables this set already has are what a title needs, so `en_US.title` + links to `sex` as `first-name` does. Swedish has no everyday sexed honorific, so + `sv_SE` keeps an unsexed `dr` and `prof`. - **No builtin reads the clock, so a date is bounded by days, never by an age.** An `age(min,max)` would make a seeded fixture change with the day it runs on, which is what a seed exists to prevent; a birthdate for someone 20 to 60 is diff --git a/todo.md b/todo.md index 79785db..33cc624 100644 --- a/todo.md +++ b/todo.md @@ -164,9 +164,13 @@ address, phone, national id, company and date names each. 1. Table node, key and name selection, parent links, consistent draws, the choice-of-rows fence, `DATA-LICENSES.md`, `data-import/` — done. 2. `geo/SE` and `geo/US`, and `address` in both locales on top of them — done. -3. Weighted person names and valid ids in both locales; `date()` — done. Middle - names wait for a draw group that shares its family's pins, so a second name - is drawn under the same sex. +3. Weighted person names and valid ids in both locales; `date()` — done. Left for + later: middle names, and drawing a shipped `personnummer` inside a *selected* + sex, both of which want a draw group that shares its family's pins — until then + the conflict error can name a rewrite that returns a different value when the + read it conflicts with sits inside another category. Give the national ids one + record shape in step 6, and report a struct column's draw conflict with the path + spelling a tag takes rather than the reference spelling. 4. `misc` conversions and the new `misc` tables. 5. The remaining locale categories: company, phone, finance, vehicle, words. 6. Records with building-block columns across the shipped set; shape re-pin.