Lesson 7 — Fetch and export

Continue in the SAME console after lesson 6, or start fresh in this folder:
    exec(open("start-here.py").read())
    exec(open("console.py").read())
    exec(open("checks.py").read())
Requires Python 3.11+ and asqueel[migration]==0.6.0.
The bootstrap rebuilds lessons 1–6, including the report query; all CSVs are included.

fetch returns named rows; dict(row) produces a plain dictionary.
fetchAsDict(key="city") needs unique keys; duplicate keys keep the last row.
fetchGrouped(key="city") keeps lists of detail rows, without SQL aggregation.
fetchRecord reads one row; an explicit order can select the first ordered row.
fetchPkeys reads primary keys. fetchAsJson returns text, not a file.
iterfetch yields batches; the final empty batch is skipped in this example.

fetch("sales-by-city.csv") and fetch("sales-by-city.json") write report files
and return the number of rows written. Existing destinations are replaced.
Expected exports are included under expected-exports/ for comparison.
The model and database remain in memory; the input CSVs are unchanged.
Commands and results were executed in a real Python REPL; timing is edited.
