@finbheara/archive-client 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +57 -2
- package/dist/chunks/{index-v8e0qe9f.js → index-8gna56w2.js} +271 -3
- package/dist/cli.js +136 -3
- package/dist/index.js +3 -1
- package/dist/types/cli.d.ts +3 -1
- package/dist/types/dancers.d.ts +33 -0
- package/dist/types/feises.d.ts +8 -0
- package/dist/types/index.d.ts +2 -1
- package/dist/types/results.d.ts +11 -0
- package/dist/types/stream.d.ts +71 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@ type declarations (`.d.ts`), so a TypeScript project needs Bun's types (`"types"
|
|
|
20
20
|
`bunx idq <verb>`.
|
|
21
21
|
|
|
22
22
|
The version is 0.x while the API settles: a minor bump may break, so pin a minor
|
|
23
|
-
(`"@finbheara/archive-client": "0.
|
|
23
|
+
(`"@finbheara/archive-client": "0.5.x"`).
|
|
24
24
|
|
|
25
25
|
## Configuration
|
|
26
26
|
|
|
@@ -85,6 +85,11 @@ c.features; // [{ feature: "dancers", state: "full" | "missing", missing: [...
|
|
|
85
85
|
| `staff` | `staff.teacher`, `staff.adjudicator` | 260 |
|
|
86
86
|
| `majors.order` | `majors.competitions` | 260 |
|
|
87
87
|
| `feises`, `comps` | `feises.find`, `feises.series`, `comps.*`, `registrations.resolve` | 265 |
|
|
88
|
+
| `results.stream`, `majors.stream` | `results.stream`, `results.entries` | 255 |
|
|
89
|
+
| `feises.dates` | `feises.dates` | 245 |
|
|
90
|
+
| `dancers.records` | `dancers.records` | 215 |
|
|
91
|
+
| `dancers.years` | `dancers.years` | 245 |
|
|
92
|
+
| `majors.tabs` | `majors.tabulated` | 215 |
|
|
88
93
|
| `teams` | `teams.results`, `teams.rosters`, `teams.resultRosters` | 260 |
|
|
89
94
|
| `events` | `events.years` | 260 |
|
|
90
95
|
|
|
@@ -276,6 +281,49 @@ A row carries the prints and the ids that stand for them: the address, the compe
|
|
|
276
281
|
and age, the place, the name and school as printed with the dancer and school ids. The majors are
|
|
277
282
|
read from `majors.sqlite`, fetched on first use.
|
|
278
283
|
|
|
284
|
+
## Every row, streamed
|
|
285
|
+
|
|
286
|
+
```ts
|
|
287
|
+
for await (const row of rel.results.stream({ scope: "majors" })) { ... }
|
|
288
|
+
for await (const row of rel.results.stream({
|
|
289
|
+
scope: "platform", // "majors" | "transcribed" | "platform" | "all"
|
|
290
|
+
primary: true, // only rows no other source stands in for
|
|
291
|
+
year: [2015, 2024], // a year or an inclusive range
|
|
292
|
+
feis_level: [600, 700], // also: event (one or several), tier, category, dancer_id, school_id
|
|
293
|
+
})) { ... }
|
|
294
|
+
for await (const entry of rel.results.entries({ scope: "all", event: "<event>" })) { ... }
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
A stream yields one row at a time and never holds the table in memory. A row carries its
|
|
298
|
+
competition beside its own fields: `competition`, `event`, `year`, `tier`, `comp_no`, `title`,
|
|
299
|
+
`category`, `age`, `age_printed`, `gender`, `competitors`, `feis_level`, `level_printed`,
|
|
300
|
+
`date_printed`, `source`, `round`, and at a feis its `feis_id`, `feis_date_lo` and
|
|
301
|
+
`feis_date_hi`. Its own: `address`, `section`, `card`, `place`, `place_printed`, `tie`,
|
|
302
|
+
`relative_place`, `atts`, `withdrawn`, `qualifier`, `name_printed`, `name`, `school_printed`,
|
|
303
|
+
`school_loc`, `school_id`, `dancer_id`, `dancer_scope`, `yob`, `yob_printed`, `points_printed`,
|
|
304
|
+
`platform_dancer_id`, `primary_source`. Rows come in the release's own order, a competition's
|
|
305
|
+
rows together.
|
|
306
|
+
|
|
307
|
+
The scopes: `majors` reads the majors (tiers T1 to T3), `transcribed` the transcribed rows of
|
|
308
|
+
every tier, `platform` every row a results platform published, `all` every row.
|
|
309
|
+
|
|
310
|
+
AN ENTRY is one row per address, the row the card stands for: a card printed in several sections
|
|
311
|
+
(a recall order, the final, a single round's solo placing, a qualifying heat) keeps the final's
|
|
312
|
+
row, then the sectionless page's, the recall order's, the standings', the unplaced row, a heat's
|
|
313
|
+
and last a solo round's (`entryRank`), and two rows of one rank keep the later. `recall_place` is
|
|
314
|
+
the place the address's recall row carries.
|
|
315
|
+
|
|
316
|
+
## Bulk reads
|
|
317
|
+
|
|
318
|
+
```ts
|
|
319
|
+
await rel.dancers.records(); // every dancer: display, appearances, birth_lo, birth_hi,
|
|
320
|
+
// birth_source, birth_conflict, genders, scope
|
|
321
|
+
await rel.dancers.records({ ids: [1001] });
|
|
322
|
+
await rel.dancers.years({ ids: [1001], year: 2025 }); // region, region_source, nationals, geohash
|
|
323
|
+
await rel.feises.dates(); // every feis id with its first and last day
|
|
324
|
+
await rel.majors.tabulated({ min_true_round: 3 }); // the majors addresses marked to round 3 or later
|
|
325
|
+
```
|
|
326
|
+
|
|
279
327
|
## Teams and event-years
|
|
280
328
|
|
|
281
329
|
```ts
|
|
@@ -426,6 +474,13 @@ and the competitions still resolve.
|
|
|
426
474
|
[--population girls|boys] [--rows]
|
|
427
475
|
idq results [--release <spec>] [--dancer <id>] [--feis <id>] [--comp <c>] [--school <s>] [--year <y>] [--limit <n>]
|
|
428
476
|
idq majors [--release <spec>] [--event <e>] [--year <y>] [--comp <c>] [--dancer <id>] [--rows]
|
|
477
|
+
idq stream [--release <spec>] --scope majors|transcribed|platform|all [--entries] [--event <e,...>]
|
|
478
|
+
[--year <y> | --year <from>..<to>] [--tier <t,...>] [--category <c,...>]
|
|
479
|
+
[--level <n,...>] [--dancer <id,...>] [--school <school_id>] [--primary]
|
|
480
|
+
idq records [--release <spec>] [--dancer <id,...>]
|
|
481
|
+
idq records --years [--release <spec>] [--dancer <id,...>] [--year <y>]
|
|
482
|
+
idq feis-dates [--release <spec>]
|
|
483
|
+
idq tabulated [--release <spec>] [--min-round <n>]
|
|
429
484
|
idq teams [--release <spec>] [--event <e>] [--year <y>] [--rosters | --joins]
|
|
430
485
|
idq events [--release <spec>] [--event <e>] [--year <y>]
|
|
431
486
|
idq teacher [--release <spec>] <name|TD number>
|
|
@@ -437,7 +492,7 @@ and the competitions still resolve.
|
|
|
437
492
|
idq resolve dancer [<name>] [--school s] [--comp <feis>/<code> | --yob y | --band b --year y]
|
|
438
493
|
idq resolve registrations
|
|
439
494
|
|
|
440
|
-
`dancer` prints the results of the one dancer where the answer is unique (every candidate's with
|
|
495
|
+
`stream` prints one JSON line per row (or entry), as it reads them. `dancer` prints the results of the one dancer where the answer is unique (every candidate's with
|
|
441
496
|
`--rows`). `--json` prints the call's answer as it is. `--cache` and `--repo` override the defaults.
|
|
442
497
|
|
|
443
498
|
`resolve` speaks JSON lines: one answer per line out, and with no positional question the
|
|
@@ -106,8 +106,149 @@ function nameLevel2(q, c) {
|
|
|
106
106
|
return null;
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
+
var ENTRY_RANK = new Map([
|
|
110
|
+
["final", 0],
|
|
111
|
+
["", 1],
|
|
112
|
+
["recall", 2],
|
|
113
|
+
["standings", 3],
|
|
114
|
+
["unplaced", 4],
|
|
115
|
+
["qual", 5],
|
|
116
|
+
["qual-a", 5],
|
|
117
|
+
["qual-b", 5]
|
|
118
|
+
]);
|
|
119
|
+
function entryRank2(section) {
|
|
120
|
+
const known = ENTRY_RANK.get(section);
|
|
121
|
+
if (known !== undefined)
|
|
122
|
+
return known;
|
|
123
|
+
if (/^solo(?:-r\d+)?$/.test(section))
|
|
124
|
+
return 6;
|
|
125
|
+
return 9;
|
|
126
|
+
}
|
|
127
|
+
var COLUMNS = `r.address AS address, r.competition AS competition, c.event AS event,
|
|
128
|
+
c.year AS year, c.tier AS tier, c.comp_no AS comp_no, c.title AS title, c.category AS category,
|
|
129
|
+
c.age AS age, c.age_printed AS age_printed, c.gender AS gender, c.competitors AS competitors,
|
|
130
|
+
c.feis_level AS feis_level, c.level_printed AS level_printed, c.date_printed AS date_printed,
|
|
131
|
+
c.source AS source, c.round AS round, r.section AS section, r.card AS card, r.place AS place,
|
|
132
|
+
r.place_printed AS place_printed, r.tie AS tie, r.relative_place AS relative_place,
|
|
133
|
+
r.atts AS atts, r.withdrawn AS withdrawn, r.qualifier AS qualifier,
|
|
134
|
+
r.name_printed AS name_printed, r.name AS name, r.school_printed AS school_printed,
|
|
135
|
+
r.school_loc AS school_loc, r.school_id AS school_id, r.dancer_id AS dancer_id, r.yob AS yob,
|
|
136
|
+
r.yob_printed AS yob_printed, r.points_printed AS points_printed,
|
|
137
|
+
r.platform_dancer_id AS platform_dancer_id, r.primary_source AS primary_source,
|
|
138
|
+
r.file AS file`;
|
|
139
|
+
var TRANSCRIBED = "('transcript', 'manifested')";
|
|
140
|
+
var scopeDb = (s) => s === "majors" ? "majors" : "results";
|
|
141
|
+
function streamSql(q) {
|
|
142
|
+
const where = [];
|
|
143
|
+
const args = [];
|
|
144
|
+
const list = (col, v, nocase = false) => {
|
|
145
|
+
if (v.length === 0) {
|
|
146
|
+
where.push("0");
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
where.push(`${col}${nocase ? " COLLATE NOCASE" : ""} IN (${v.map(() => "?").join(", ")})`);
|
|
150
|
+
args.push(...v);
|
|
151
|
+
};
|
|
152
|
+
if (q.scope === "transcribed")
|
|
153
|
+
where.push(`r.source IN ${TRANSCRIBED}`);
|
|
154
|
+
else if (q.scope === "platform")
|
|
155
|
+
where.push(`r.source NOT IN ${TRANSCRIBED}`);
|
|
156
|
+
else if (q.scope !== "majors" && q.scope !== "all")
|
|
157
|
+
throw new Error(`archive-client: no stream scope "${String(q.scope)}"`);
|
|
158
|
+
if (q.event !== undefined)
|
|
159
|
+
list("c.event", typeof q.event === "string" ? [q.event] : q.event, true);
|
|
160
|
+
if (typeof q.year === "number") {
|
|
161
|
+
where.push("c.year = ?");
|
|
162
|
+
args.push(q.year);
|
|
163
|
+
} else if (Array.isArray(q.year)) {
|
|
164
|
+
where.push("c.year BETWEEN ? AND ?");
|
|
165
|
+
args.push(q.year[0], q.year[1]);
|
|
166
|
+
}
|
|
167
|
+
if (q.tier !== undefined)
|
|
168
|
+
list("c.tier", q.tier);
|
|
169
|
+
if (q.category !== undefined)
|
|
170
|
+
list("c.category", q.category);
|
|
171
|
+
if (q.feis_level !== undefined)
|
|
172
|
+
list("c.feis_level", q.feis_level);
|
|
173
|
+
if (q.dancer_id !== undefined)
|
|
174
|
+
list("r.dancer_id", q.dancer_id);
|
|
175
|
+
if (q.school_id !== undefined) {
|
|
176
|
+
where.push("r.school_id = ?");
|
|
177
|
+
args.push(q.school_id);
|
|
178
|
+
}
|
|
179
|
+
if (q.primary === true)
|
|
180
|
+
where.push("(r.primary_source IS NULL OR r.primary_source = '')");
|
|
181
|
+
return {
|
|
182
|
+
sql: `SELECT ${COLUMNS} FROM results r JOIN competitions c ON c.file = r.file AND c.line = r.competition_line${where.length === 0 ? "" : ` WHERE ${where.join(" AND ")}`} ORDER BY r.file, r.line`,
|
|
183
|
+
args
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
function feisDates(db) {
|
|
187
|
+
const out = new Map;
|
|
188
|
+
for (const f of db.query("SELECT feis_id, min(date_lo) AS lo, max(date_hi) AS hi FROM feises GROUP BY feis_id").all())
|
|
189
|
+
out.set(f.feis_id, { lo: f.lo, hi: f.hi });
|
|
190
|
+
return out;
|
|
191
|
+
}
|
|
192
|
+
var text = (v) => v === null || v === "" ? null : v;
|
|
193
|
+
function rowOf(r, dates) {
|
|
194
|
+
const { file: _file, atts, withdrawn, ...rest } = r;
|
|
195
|
+
const d = dates.get(r.event);
|
|
196
|
+
return {
|
|
197
|
+
...rest,
|
|
198
|
+
feis_id: d === undefined ? null : r.event,
|
|
199
|
+
feis_date_lo: d?.lo ?? null,
|
|
200
|
+
feis_date_hi: d?.hi ?? null,
|
|
201
|
+
atts: atts === "" ? [] : atts.split(","),
|
|
202
|
+
withdrawn: text(withdrawn),
|
|
203
|
+
qualifier: text(rest.qualifier),
|
|
204
|
+
primary_source: text(rest.primary_source),
|
|
205
|
+
dancer_scope: r.dancer_id === null ? null : r.dancer_id >= FEIS_LOCAL_ID_FLOOR2 ? "per-release" : "stable"
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
async function* streamRows(db, q) {
|
|
209
|
+
const dates = feisDates(db);
|
|
210
|
+
const { sql, args } = streamSql(q);
|
|
211
|
+
const stmt = db.prepare(sql);
|
|
212
|
+
try {
|
|
213
|
+
for (const r of stmt.iterate(...args))
|
|
214
|
+
yield rowOf(r, dates);
|
|
215
|
+
} finally {
|
|
216
|
+
stmt.finalize();
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
async function* entryRows(db, q) {
|
|
220
|
+
const dates = feisDates(db);
|
|
221
|
+
const { sql, args } = streamSql(q);
|
|
222
|
+
const stmt = db.prepare(sql);
|
|
223
|
+
let file = null;
|
|
224
|
+
let held = new Map;
|
|
225
|
+
const flush = function* () {
|
|
226
|
+
for (const h of held.values())
|
|
227
|
+
yield { ...rowOf(h.raw, dates), recall_place: h.recall };
|
|
228
|
+
held = new Map;
|
|
229
|
+
};
|
|
230
|
+
try {
|
|
231
|
+
for (const r of stmt.iterate(...args)) {
|
|
232
|
+
if (r.file !== file) {
|
|
233
|
+
yield* flush();
|
|
234
|
+
file = r.file;
|
|
235
|
+
}
|
|
236
|
+
const rank = entryRank2(r.section);
|
|
237
|
+
const h = held.get(r.address);
|
|
238
|
+
const recall = r.section === "recall" ? r.place : h?.recall ?? null;
|
|
239
|
+
if (h === undefined || rank <= h.rank)
|
|
240
|
+
held.set(r.address, { raw: r, rank, recall });
|
|
241
|
+
else
|
|
242
|
+
h.recall = recall;
|
|
243
|
+
}
|
|
244
|
+
yield* flush();
|
|
245
|
+
} finally {
|
|
246
|
+
stmt.finalize();
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
109
250
|
var FEIS_LOCAL_ID_FLOOR2 = 17179869184;
|
|
110
|
-
var
|
|
251
|
+
var COLUMNS2 = `r.address AS address, r.competition AS competition, c.event AS event, c.year AS year,
|
|
111
252
|
c.tier AS tier, c.title AS title, c.age AS age, c.category AS category, c.gender AS gender,
|
|
112
253
|
c.feis_level AS feis_level, c.comp_no AS comp_no, r.place AS place,
|
|
113
254
|
r.place_printed AS place_printed, c.competitors AS competitors, r.name_printed AS name_printed,
|
|
@@ -139,7 +280,7 @@ function queryResults(rel, db, q) {
|
|
|
139
280
|
args.push(q.year);
|
|
140
281
|
}
|
|
141
282
|
const limit = q.limit ?? 500;
|
|
142
|
-
const all = rel.db(db).query(`SELECT ${
|
|
283
|
+
const all = rel.db(db).query(`SELECT ${COLUMNS2} FROM results r JOIN competitions c ON c.file = r.file AND c.line = r.competition_line
|
|
143
284
|
WHERE ${where.join(" AND ")}
|
|
144
285
|
ORDER BY c.year, c.event, r.competition, r.place IS NULL, r.place, r.address`).all(...args);
|
|
145
286
|
return {
|
|
@@ -164,6 +305,18 @@ class ResultFinder2 {
|
|
|
164
305
|
await this.rel.require("results.level");
|
|
165
306
|
return queryResults(this.rel, "results", q);
|
|
166
307
|
}
|
|
308
|
+
async streamDb(q) {
|
|
309
|
+
const db = scopeDb(q.scope);
|
|
310
|
+
await this.rel.fetch(db);
|
|
311
|
+
await this.rel.require(db === "majors" ? "majors.stream" : "results.stream");
|
|
312
|
+
return this.rel.db(db);
|
|
313
|
+
}
|
|
314
|
+
async* stream(q) {
|
|
315
|
+
yield* streamRows(await this.streamDb(q), q);
|
|
316
|
+
}
|
|
317
|
+
async* entries(q) {
|
|
318
|
+
yield* entryRows(await this.streamDb(q), q);
|
|
319
|
+
}
|
|
167
320
|
}
|
|
168
321
|
|
|
169
322
|
class MajorsFinder2 {
|
|
@@ -208,6 +361,13 @@ class MajorsFinder2 {
|
|
|
208
361
|
ORDER BY c.year, c.seq, c.competition`).all(...args).map((c) => ({ ...c, rows: rows.get(c.competition) ?? 0 }));
|
|
209
362
|
return { tag: this.rel.tag, competitions };
|
|
210
363
|
}
|
|
364
|
+
async tabulated(q = {}) {
|
|
365
|
+
const db = await this.db();
|
|
366
|
+
await this.rel.require("majors.tabs");
|
|
367
|
+
const min = q.min_true_round ?? 3;
|
|
368
|
+
const addresses = db.query("SELECT DISTINCT address FROM tabs WHERE true_round >= ? ORDER BY address").all(min).map((r) => r.address);
|
|
369
|
+
return { tag: this.rel.tag, min_true_round: min, addresses };
|
|
370
|
+
}
|
|
211
371
|
async results(q) {
|
|
212
372
|
await this.db();
|
|
213
373
|
await this.rel.require("results.level");
|
|
@@ -365,6 +525,12 @@ var SCHOOL_WEIGHT = {
|
|
|
365
525
|
unresolved: 0,
|
|
366
526
|
unasked: 0
|
|
367
527
|
};
|
|
528
|
+
function idChunks(ids) {
|
|
529
|
+
const out = [];
|
|
530
|
+
for (let i = 0;i < ids.length; i += 500)
|
|
531
|
+
out.push(ids.slice(i, i + 500));
|
|
532
|
+
return out;
|
|
533
|
+
}
|
|
368
534
|
|
|
369
535
|
class DancerResolver2 {
|
|
370
536
|
rel;
|
|
@@ -372,6 +538,34 @@ class DancerResolver2 {
|
|
|
372
538
|
constructor(rel) {
|
|
373
539
|
this.rel = rel;
|
|
374
540
|
}
|
|
541
|
+
async records(q = {}) {
|
|
542
|
+
await this.rel.fetch("results");
|
|
543
|
+
await this.rel.require("dancers.records");
|
|
544
|
+
const db = this.rel.db("results");
|
|
545
|
+
const sql = "SELECT dancer_id, display, appearances, birth_lo, birth_hi, birth_source, birth_conflict, genders FROM dancers";
|
|
546
|
+
const rows = q.ids === undefined ? db.query(`${sql} ORDER BY dancer_id`).all() : idChunks(q.ids).flatMap((c) => db.query(`${sql} WHERE dancer_id IN (${c.map(() => "?").join(",")})`).all(...c));
|
|
547
|
+
rows.sort((a, b) => a.dancer_id - b.dancer_id);
|
|
548
|
+
return {
|
|
549
|
+
tag: this.rel.tag,
|
|
550
|
+
records: rows.map((r) => ({
|
|
551
|
+
...r,
|
|
552
|
+
scope: r.dancer_id >= FEIS_LOCAL_ID_FLOOR2 ? "per-release" : "stable",
|
|
553
|
+
birth_conflict: r.birth_conflict === 1,
|
|
554
|
+
genders: r.genders === "" ? [] : r.genders.split(",")
|
|
555
|
+
}))
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
async years(q = {}) {
|
|
559
|
+
await this.rel.fetch("results");
|
|
560
|
+
await this.rel.require("dancers.years");
|
|
561
|
+
const db = this.rel.db("results");
|
|
562
|
+
const sql = "SELECT dancer_id, year, region, region_source, nationals, nationals_source, geohash FROM dancer_years";
|
|
563
|
+
const yearSql = q.year === undefined ? "" : " AND year = ?";
|
|
564
|
+
const yearArgs = q.year === undefined ? [] : [q.year];
|
|
565
|
+
const rows = q.ids === undefined ? db.query(`${sql} WHERE 1${yearSql} ORDER BY dancer_id, year`).all(...yearArgs) : idChunks(q.ids).flatMap((c) => db.query(`${sql} WHERE dancer_id IN (${c.map(() => "?").join(",")})${yearSql}`).all(...c, ...yearArgs));
|
|
566
|
+
rows.sort((a, b) => a.dancer_id - b.dancer_id || a.year - b.year);
|
|
567
|
+
return { tag: this.rel.tag, years: rows };
|
|
568
|
+
}
|
|
375
569
|
async resolve(q) {
|
|
376
570
|
const db = await this.rel.indexDb("dancers");
|
|
377
571
|
const asked = dancerName(q.name, q.order === "unknown" ? undefined : q.order);
|
|
@@ -1067,6 +1261,12 @@ class FeisFinder2 {
|
|
|
1067
1261
|
constructor(rel) {
|
|
1068
1262
|
this.rel = rel;
|
|
1069
1263
|
}
|
|
1264
|
+
async dates() {
|
|
1265
|
+
await this.rel.fetch("results");
|
|
1266
|
+
await this.rel.require("feises.dates");
|
|
1267
|
+
const dates = this.rel.db("results").query("SELECT feis_id, min(date_lo) AS date_lo, max(date_hi) AS date_hi FROM feises GROUP BY feis_id ORDER BY feis_id").all();
|
|
1268
|
+
return { tag: this.rel.tag, dates };
|
|
1269
|
+
}
|
|
1070
1270
|
async find(q) {
|
|
1071
1271
|
const db = await this.rel.indexDb("feises");
|
|
1072
1272
|
const where = [];
|
|
@@ -2298,6 +2498,74 @@ var FEATURES2 = [
|
|
|
2298
2498
|
since: 265,
|
|
2299
2499
|
calls: "comps.resolve, comps.syllabus, comps.syllabusFor, registrations.resolve (the comps index)"
|
|
2300
2500
|
},
|
|
2501
|
+
{
|
|
2502
|
+
feature: "results.stream",
|
|
2503
|
+
needs: [
|
|
2504
|
+
"results:competitions.round",
|
|
2505
|
+
"results:competitions.feis_level",
|
|
2506
|
+
"results:competitions.level_printed",
|
|
2507
|
+
"results:competitions.age_printed",
|
|
2508
|
+
"results:results.yob_printed",
|
|
2509
|
+
"results:results.primary_source",
|
|
2510
|
+
"results:results.platform_dancer_id",
|
|
2511
|
+
"results:results.relative_place",
|
|
2512
|
+
"results:feises.date_lo",
|
|
2513
|
+
"results:feises.date_hi"
|
|
2514
|
+
],
|
|
2515
|
+
since: 255,
|
|
2516
|
+
calls: "results.stream, results.entries (scopes transcribed, platform, all)"
|
|
2517
|
+
},
|
|
2518
|
+
{
|
|
2519
|
+
feature: "majors.stream",
|
|
2520
|
+
needs: [
|
|
2521
|
+
"majors:competitions.round",
|
|
2522
|
+
"majors:competitions.feis_level",
|
|
2523
|
+
"majors:results.yob_printed",
|
|
2524
|
+
"majors:results.primary_source",
|
|
2525
|
+
"majors:results.relative_place",
|
|
2526
|
+
"majors:feises.date_lo"
|
|
2527
|
+
],
|
|
2528
|
+
since: 255,
|
|
2529
|
+
calls: "results.stream, results.entries (scope majors)"
|
|
2530
|
+
},
|
|
2531
|
+
{
|
|
2532
|
+
feature: "majors.tabs",
|
|
2533
|
+
needs: ["majors:tabs.address", "majors:tabs.true_round"],
|
|
2534
|
+
since: 215,
|
|
2535
|
+
calls: "majors.tabulated"
|
|
2536
|
+
},
|
|
2537
|
+
{
|
|
2538
|
+
feature: "feises.dates",
|
|
2539
|
+
needs: ["results:feises.feis_id", "results:feises.date_lo", "results:feises.date_hi"],
|
|
2540
|
+
since: 245,
|
|
2541
|
+
calls: "feises.dates"
|
|
2542
|
+
},
|
|
2543
|
+
{
|
|
2544
|
+
feature: "dancers.records",
|
|
2545
|
+
needs: [
|
|
2546
|
+
"results:dancers.display",
|
|
2547
|
+
"results:dancers.appearances",
|
|
2548
|
+
"results:dancers.birth_lo",
|
|
2549
|
+
"results:dancers.birth_hi",
|
|
2550
|
+
"results:dancers.birth_source",
|
|
2551
|
+
"results:dancers.birth_conflict",
|
|
2552
|
+
"results:dancers.genders"
|
|
2553
|
+
],
|
|
2554
|
+
since: 215,
|
|
2555
|
+
calls: "dancers.records"
|
|
2556
|
+
},
|
|
2557
|
+
{
|
|
2558
|
+
feature: "dancers.years",
|
|
2559
|
+
needs: [
|
|
2560
|
+
"results:dancer_years.region",
|
|
2561
|
+
"results:dancer_years.region_source",
|
|
2562
|
+
"results:dancer_years.nationals",
|
|
2563
|
+
"results:dancer_years.nationals_source",
|
|
2564
|
+
"results:dancer_years.geohash"
|
|
2565
|
+
],
|
|
2566
|
+
since: 245,
|
|
2567
|
+
calls: "dancers.years"
|
|
2568
|
+
},
|
|
2301
2569
|
{
|
|
2302
2570
|
feature: "teams",
|
|
2303
2571
|
needs: [
|
|
@@ -2929,4 +3197,4 @@ function releases2(opts = {}) {
|
|
|
2929
3197
|
return new ReleaseManager2(opts);
|
|
2930
3198
|
}
|
|
2931
3199
|
|
|
2932
|
-
export { DATABASES2, planAsset2, sha256File2, unzstdTo2, NAME_LEVELS2, nameLevel2, FEIS_LOCAL_ID_FLOOR2, ResultFinder2, MajorsFinder2, nameOrderOf, DancerResolver2, readPopulation2, canonicalOf2, CompResolver2, NO_CALENDAR2, FeisFinder2, StaffFinder2, SchoolResolver2, TeamFinder2, EventFinder2, defaultBuilders2, indexPath2, indexKey2, isCurrent2, buildIndex2, ensureIndex2, listIndexes2, readPin2, youngest2, dancerResolverOf2, RegistrationResolver2, ghRemote2, httpsRemote2, fallbackRemote2, setRemote2, columnsOf2, FEATURES2, capabilityOf2, needsRelease2, resolveTag2, Release2, openRelease2, openCached2, ReleaseManager2, releases2 };
|
|
3200
|
+
export { DATABASES2, planAsset2, sha256File2, unzstdTo2, NAME_LEVELS2, nameLevel2, entryRank2, FEIS_LOCAL_ID_FLOOR2, ResultFinder2, MajorsFinder2, nameOrderOf, DancerResolver2, readPopulation2, canonicalOf2, CompResolver2, NO_CALENDAR2, FeisFinder2, StaffFinder2, SchoolResolver2, TeamFinder2, EventFinder2, defaultBuilders2, indexPath2, indexKey2, isCurrent2, buildIndex2, ensureIndex2, listIndexes2, readPin2, youngest2, dancerResolverOf2, RegistrationResolver2, ghRemote2, httpsRemote2, fallbackRemote2, setRemote2, columnsOf2, FEATURES2, capabilityOf2, needsRelease2, resolveTag2, Release2, openRelease2, openCached2, ReleaseManager2, releases2 };
|
package/dist/cli.js
CHANGED
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
nameOrderOf,
|
|
5
5
|
openRelease2,
|
|
6
6
|
releases2
|
|
7
|
-
} from "./chunks/index-
|
|
7
|
+
} from "./chunks/index-8gna56w2.js";
|
|
8
8
|
import"./chunks/index-hne1wadw.js";
|
|
9
9
|
import"./chunks/index-hghdy980.js";
|
|
10
10
|
|
|
@@ -50,6 +50,21 @@ var USAGE = `usage: idq <verb> [--cache <dir>] [--repo <owner/name>] [--json]
|
|
|
50
50
|
majors [--release <spec>] [--event <e>] [--year <y>] [--comp <competition>] [--dancer <id>]
|
|
51
51
|
the majors: every event and its years; an event's
|
|
52
52
|
competitions; a competition's, an event's or a dancer's rows
|
|
53
|
+
stream [--release <spec>] --scope majors|transcribed|platform|all [--entries] [--event <e,...>]
|
|
54
|
+
[--year <y> | --year <from>..<to>] [--tier <t,...>] [--category <c,...>]
|
|
55
|
+
[--level <feis_level,...>] [--dancer <id,...>] [--school <school_id>] [--primary]
|
|
56
|
+
every row a scope holds, one JSON line each, never the
|
|
57
|
+
whole table in memory; --entries one per address (the row
|
|
58
|
+
it stands for, with its recall order)
|
|
59
|
+
records [--release <spec>] [--dancer <id,...>]
|
|
60
|
+
every dancer's record: display, appearances, birth window,
|
|
61
|
+
populations
|
|
62
|
+
records --years [--release <spec>] [--dancer <id,...>] [--year <y>]
|
|
63
|
+
each dancer's region, nationals and place per year
|
|
64
|
+
feis-dates [--release <spec>] every feis's first and last day
|
|
65
|
+
tabulated [--release <spec>] [--min-round <n>]
|
|
66
|
+
the majors addresses the marks sheets tabulate to round n
|
|
67
|
+
or later (default 3)
|
|
53
68
|
teams [--release <spec>] [--event <e>] [--year <y>] [--rosters | --joins]
|
|
54
69
|
the team result rows of an event-year; with --rosters its
|
|
55
70
|
roster teams and their dancers; with --joins how each roster
|
|
@@ -107,7 +122,12 @@ var VALUE = new Set([
|
|
|
107
122
|
"--limit",
|
|
108
123
|
"--event",
|
|
109
124
|
"--title",
|
|
110
|
-
"--for"
|
|
125
|
+
"--for",
|
|
126
|
+
"--scope",
|
|
127
|
+
"--tier",
|
|
128
|
+
"--category",
|
|
129
|
+
"--level",
|
|
130
|
+
"--min-round"
|
|
111
131
|
]);
|
|
112
132
|
function parseArgs(argv) {
|
|
113
133
|
const positional = [];
|
|
@@ -319,6 +339,45 @@ async function resolveVerb(rel, what, args, p, say, stdin) {
|
|
|
319
339
|
throw new Error("resolve comp|dancer|registrations");
|
|
320
340
|
}
|
|
321
341
|
}
|
|
342
|
+
var SCOPES = ["majors", "transcribed", "platform", "all"];
|
|
343
|
+
var listOf = (v) => v.split(",").map((x) => x.trim()).filter((x) => x !== "");
|
|
344
|
+
var idsOf = (v) => v === undefined ? undefined : listOf(v).map(Number);
|
|
345
|
+
function streamQueryOf(p) {
|
|
346
|
+
const scope = p.flags.get("--scope");
|
|
347
|
+
if (scope === undefined || !SCOPES.includes(scope))
|
|
348
|
+
throw new Error(`stream takes --scope ${SCOPES.join("|")}`);
|
|
349
|
+
const q = { scope };
|
|
350
|
+
const event = p.flags.get("--event");
|
|
351
|
+
if (event !== undefined)
|
|
352
|
+
q.event = listOf(event);
|
|
353
|
+
const year = p.flags.get("--year");
|
|
354
|
+
if (year !== undefined) {
|
|
355
|
+
const m = /^(\d{4})\.\.(\d{4})$/.exec(year);
|
|
356
|
+
q.year = m === null ? Number(year) : [Number(m[1]), Number(m[2])];
|
|
357
|
+
if (typeof q.year === "number" && !Number.isInteger(q.year))
|
|
358
|
+
throw new Error(`--year takes a year or <from>..<to>, not "${year}"`);
|
|
359
|
+
}
|
|
360
|
+
for (const [flag, key] of [
|
|
361
|
+
["--tier", "tier"],
|
|
362
|
+
["--category", "category"]
|
|
363
|
+
]) {
|
|
364
|
+
const v = p.flags.get(flag);
|
|
365
|
+
if (v !== undefined)
|
|
366
|
+
q[key] = listOf(v);
|
|
367
|
+
}
|
|
368
|
+
const level = p.flags.get("--level");
|
|
369
|
+
if (level !== undefined)
|
|
370
|
+
q.feis_level = listOf(level).map(Number);
|
|
371
|
+
const dancers = idsOf(p.flags.get("--dancer"));
|
|
372
|
+
if (dancers !== undefined)
|
|
373
|
+
q.dancer_id = dancers;
|
|
374
|
+
const school = p.flags.get("--school");
|
|
375
|
+
if (school !== undefined)
|
|
376
|
+
q.school_id = school;
|
|
377
|
+
if (p.bools.has("--primary"))
|
|
378
|
+
q.primary = true;
|
|
379
|
+
return q;
|
|
380
|
+
}
|
|
322
381
|
function eventYearOf(p) {
|
|
323
382
|
const event = p.flags.get("--event");
|
|
324
383
|
const year = p.flags.get("--year");
|
|
@@ -644,6 +703,79 @@ async function main(argv, io = {}) {
|
|
|
644
703
|
rel.close();
|
|
645
704
|
}
|
|
646
705
|
}
|
|
706
|
+
case "stream": {
|
|
707
|
+
const q = streamQueryOf(p);
|
|
708
|
+
const rel = await openRelease2(spec, { ...opts, assets: [] });
|
|
709
|
+
try {
|
|
710
|
+
let n = 0;
|
|
711
|
+
const rows = p.bools.has("--entries") ? rel.results.entries(q) : rel.results.stream(q);
|
|
712
|
+
for await (const r of rows) {
|
|
713
|
+
say(JSON.stringify(r));
|
|
714
|
+
n++;
|
|
715
|
+
}
|
|
716
|
+
log(`${n} ${p.bools.has("--entries") ? "entries" : "rows"} in ${rel.tag}`);
|
|
717
|
+
return n === 0 ? 1 : 0;
|
|
718
|
+
} finally {
|
|
719
|
+
rel.close();
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
case "records": {
|
|
723
|
+
const rel = await openRelease2(spec, { ...opts, assets: [] });
|
|
724
|
+
try {
|
|
725
|
+
const ids = idsOf(p.flags.get("--dancer"));
|
|
726
|
+
if (p.bools.has("--years")) {
|
|
727
|
+
const year = p.flags.get("--year");
|
|
728
|
+
const a = await rel.dancers.years({
|
|
729
|
+
...ids !== undefined ? { ids } : {},
|
|
730
|
+
...year !== undefined ? { year: Number(year) } : {}
|
|
731
|
+
});
|
|
732
|
+
out(a, () => {
|
|
733
|
+
for (const y of a.years)
|
|
734
|
+
say(` ${y.dancer_id} ${y.year} ${y.region ?? "-"} (${y.region_source ?? "-"}) nationals ${y.nationals ?? "-"} ${y.geohash ?? "-"}`);
|
|
735
|
+
say(`${a.years.length} dancer-year(s) in ${a.tag}`);
|
|
736
|
+
});
|
|
737
|
+
return a.years.length === 0 ? 1 : 0;
|
|
738
|
+
}
|
|
739
|
+
const a = await rel.dancers.records(ids !== undefined ? { ids } : {});
|
|
740
|
+
out(a, () => {
|
|
741
|
+
for (const r of a.records)
|
|
742
|
+
say(` ${r.dancer_id} ${r.display} ${r.appearances} entries born ${r.birth_lo ?? "?"}..${r.birth_hi ?? "?"} (${r.birth_source}${r.birth_conflict ? ", conflict" : ""}) ${r.genders.join(",") || "-"}`);
|
|
743
|
+
say(`${a.records.length} dancer(s) in ${a.tag}`);
|
|
744
|
+
});
|
|
745
|
+
return a.records.length === 0 ? 1 : 0;
|
|
746
|
+
} finally {
|
|
747
|
+
rel.close();
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
case "feis-dates": {
|
|
751
|
+
const rel = await openRelease2(spec, { ...opts, assets: [] });
|
|
752
|
+
try {
|
|
753
|
+
const a = await rel.feises.dates();
|
|
754
|
+
out(a, () => {
|
|
755
|
+
for (const d of a.dates)
|
|
756
|
+
say(` ${d.feis_id} ${d.date_lo ?? "?"}..${d.date_hi ?? "?"}`);
|
|
757
|
+
say(`${a.dates.length} feis(es) in ${a.tag}`);
|
|
758
|
+
});
|
|
759
|
+
return a.dates.length === 0 ? 1 : 0;
|
|
760
|
+
} finally {
|
|
761
|
+
rel.close();
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
case "tabulated": {
|
|
765
|
+
const rel = await openRelease2(spec, { ...opts, assets: [] });
|
|
766
|
+
try {
|
|
767
|
+
const min = p.flags.get("--min-round");
|
|
768
|
+
const a = await rel.majors.tabulated(min !== undefined ? { min_true_round: Number(min) } : {});
|
|
769
|
+
out(a, () => {
|
|
770
|
+
for (const x of a.addresses)
|
|
771
|
+
say(` ${x}`);
|
|
772
|
+
say(`${a.addresses.length} address(es) tabulated to round ${a.min_true_round} or later in ${a.tag}`);
|
|
773
|
+
});
|
|
774
|
+
return a.addresses.length === 0 ? 1 : 0;
|
|
775
|
+
} finally {
|
|
776
|
+
rel.close();
|
|
777
|
+
}
|
|
778
|
+
}
|
|
647
779
|
case "teams": {
|
|
648
780
|
const rel = await openRelease2(spec, { ...opts, assets: [] });
|
|
649
781
|
try {
|
|
@@ -783,5 +915,6 @@ export {
|
|
|
783
915
|
USAGE,
|
|
784
916
|
jsonLines,
|
|
785
917
|
main,
|
|
786
|
-
parseArgs
|
|
918
|
+
parseArgs,
|
|
919
|
+
streamQueryOf
|
|
787
920
|
};
|
package/dist/index.js
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
unzstdTo2,
|
|
7
7
|
NAME_LEVELS2,
|
|
8
8
|
nameLevel2,
|
|
9
|
+
entryRank2,
|
|
9
10
|
FEIS_LOCAL_ID_FLOOR2,
|
|
10
11
|
ResultFinder2,
|
|
11
12
|
MajorsFinder2,
|
|
@@ -44,7 +45,7 @@ import {
|
|
|
44
45
|
openCached2,
|
|
45
46
|
ReleaseManager2,
|
|
46
47
|
releases2
|
|
47
|
-
} from "./chunks/index-
|
|
48
|
+
} from "./chunks/index-8gna56w2.js";
|
|
48
49
|
import {
|
|
49
50
|
cacheRoot2,
|
|
50
51
|
repoOf2
|
|
@@ -87,6 +88,7 @@ export {
|
|
|
87
88
|
dancerResolverOf2 as dancerResolverOf,
|
|
88
89
|
defaultBuilders2 as defaultBuilders,
|
|
89
90
|
ensureIndex2 as ensureIndex,
|
|
91
|
+
entryRank2 as entryRank,
|
|
90
92
|
fallbackRemote2 as fallbackRemote,
|
|
91
93
|
ghRemote2 as ghRemote,
|
|
92
94
|
httpsRemote2 as httpsRemote,
|
package/dist/types/cli.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
import type { OpenOptions } from "./release.js";
|
|
3
|
-
|
|
3
|
+
import type { StreamQuery } from "./stream.js";
|
|
4
|
+
export declare const USAGE = "usage: idq <verb> [--cache <dir>] [--repo <owner/name>] [--json]\n\n config repo <owner/name> set the user-local repository the releases come from\n list [--remote] the cached releases (size, files, indexes, the pin), and\n with --remote the published tags\n fetch [--release <spec>] [--assets results,majors,<file>...]\n download, verify and cache a release (default: results)\n pin <spec> the user-local pin: what a bare open (spec \"pinned\") opens\n unpin remove the pin (a bare open is then \"latest\")\n current the pin, and whether it is cached\n add <dir> --tag <tag> add a release built locally (its MANIFEST.json and files)\n to the cache under its tag\n index [--release <spec>] [<name>...] [--force]\n build the per-tag indexes (default: every one)\n verify [--release <spec>] re-hash every cached file against its receipt\n capabilities [--release <spec>] what the release carries of what the client reads, from\n its own schema: each feature full or missing (its calls\n refuse, naming the first cut that publishes it)\n prune [--keep N] [--dry-run] remove all but the N newest cached releases (default 1)\n and the pinned one\n rm <tag> [--dry-run] remove one cached release (not the pinned one)\n drop-indexes [<tag>] [--dry-run] remove the index files (of one release, or of every one)\n feis [--release <spec>] [--platform <p>] [--code <c>] [--id <id>] [--name <glob>] [--year <y>]\n the feises a query names\n series [--release <spec>] <name|host code|feis id>\n the series a name, a host code (fweb:ABC) or any feis id\n names: its years, hosts, codes and next instance\n school [--release <spec>] <print|school_id> [--region <code>]\n a school print or id to the published schools\n dancer [--release <spec>] <name> | --surname <s> | --like <glob> | --id <dancer_id>\n [--order surname-first|given-first] [--school <print|id>]\n [--yob <y> | --band <U10> [--year <y>] | --comp <competition>] [--as-of <date>]\n [--population girls|boys] [--rows]\n the dancers a name reaches, each with its evidence\n (name level, age, school, population) and the arm; the results of\n the one dancer where one answers (or --rows for each)\n results [--release <spec>] [--dancer <id>] [--feis <id>] [--comp <competition>]\n [--school <print|id>] [--year <y>] [--limit <n>]\n the published result rows, prints and ids\n majors [--release <spec>] [--event <e>] [--year <y>] [--comp <competition>] [--dancer <id>]\n the majors: every event and its years; an event's\n competitions; a competition's, an event's or a dancer's rows\n stream [--release <spec>] --scope majors|transcribed|platform|all [--entries] [--event <e,...>]\n [--year <y> | --year <from>..<to>] [--tier <t,...>] [--category <c,...>]\n [--level <feis_level,...>] [--dancer <id,...>] [--school <school_id>] [--primary]\n every row a scope holds, one JSON line each, never the\n whole table in memory; --entries one per address (the row\n it stands for, with its recall order)\n records [--release <spec>] [--dancer <id,...>]\n every dancer's record: display, appearances, birth window,\n populations\n records --years [--release <spec>] [--dancer <id,...>] [--year <y>]\n each dancer's region, nationals and place per year\n feis-dates [--release <spec>] every feis's first and last day\n tabulated [--release <spec>] [--min-round <n>]\n the majors addresses the marks sheets tabulate to round n\n or later (default 3)\n teams [--release <spec>] [--event <e>] [--year <y>] [--rosters | --joins]\n the team result rows of an event-year; with --rosters its\n roster teams and their dancers; with --joins how each roster\n team meets the results\n events [--release <spec>] [--event <e>] [--year <y>]\n each event-year's dates and place\n teacher [--release <spec>] <name|TD number>\n the staff lists' people: where they taught, the register,\n where they sat\n adjudicator [--release <spec>] <name|TD number>\n the register's and the panels' people: the same answer\n comp [--release <spec>] <feis> <code> [--year <y>] [--title <t>]\n a feis's own comp code to the comp it names, through that\n feis's syllabus (or the prior year's)\n syllabus [--release <spec>] <feis> [year]\n one feis-year's comps, in printed order\n syllabus [--release <spec>] --for <series> [year]\n a series' syllabus for a year: that year's where held,\n else the newest, saying which and what it is read from\n resolve comp [<feis> <code>] [--year <y>] [--title <t>]\n resolve dancer [<name>] [--school <s>] [--comp <feis>/<code> | --yob <y> | --band <b> --year <y>]\n [--order <o>] [--as-of <date>] [--population girls|boys]\n resolve registrations\n JSONL out, one answer per line; with no positional the\n questions are JSONL on stdin, one per line (a comp:\n {feis, code, year?, title?}, a dancer: {name, school?, age?,\n population?}, a registration: {name, school?, codes[], feis,\n year?, population?})\n\n <spec>: pinned (the default) | latest | a cut (42, 42.1) | a tag (archive-YYYY.MM.DD-N)";
|
|
4
5
|
export interface Parsed {
|
|
5
6
|
positional: string[];
|
|
6
7
|
flags: Map<string, string>;
|
|
@@ -15,6 +16,7 @@ type Line<T> = {
|
|
|
15
16
|
error: string;
|
|
16
17
|
};
|
|
17
18
|
export declare function jsonLines<T>(text: string, check: (v: T) => string | null): Line<T>[];
|
|
19
|
+
export declare function streamQueryOf(p: Parsed): StreamQuery;
|
|
18
20
|
export declare function main(argv: readonly string[], io?: {
|
|
19
21
|
say?: (s: string) => void;
|
|
20
22
|
log?: (s: string) => void;
|
package/dist/types/dancers.d.ts
CHANGED
|
@@ -140,10 +140,43 @@ export interface DancerRecord {
|
|
|
140
140
|
export declare const PACKAGE_KEY_PARTS: readonly string[];
|
|
141
141
|
export declare const dancersIndex: IndexBuilder;
|
|
142
142
|
export declare function yearOf(asOf: string | undefined): number | null;
|
|
143
|
+
export interface DancerBulkRecord {
|
|
144
|
+
dancer_id: number;
|
|
145
|
+
display: string;
|
|
146
|
+
scope: "per-release" | "stable";
|
|
147
|
+
appearances: number;
|
|
148
|
+
birth_lo: number | null;
|
|
149
|
+
birth_hi: number | null;
|
|
150
|
+
birth_source: string;
|
|
151
|
+
birth_conflict: boolean;
|
|
152
|
+
genders: string[];
|
|
153
|
+
}
|
|
154
|
+
export interface DancerYear {
|
|
155
|
+
dancer_id: number;
|
|
156
|
+
year: number;
|
|
157
|
+
region: string | null;
|
|
158
|
+
region_source: string | null;
|
|
159
|
+
nationals: string | null;
|
|
160
|
+
nationals_source: string | null;
|
|
161
|
+
geohash: string | null;
|
|
162
|
+
}
|
|
143
163
|
export declare class DancerResolver {
|
|
144
164
|
private readonly rel;
|
|
145
165
|
private readonly printIds;
|
|
146
166
|
constructor(rel: Release);
|
|
167
|
+
records(q?: {
|
|
168
|
+
ids?: readonly number[];
|
|
169
|
+
}): Promise<{
|
|
170
|
+
tag: string;
|
|
171
|
+
records: DancerBulkRecord[];
|
|
172
|
+
}>;
|
|
173
|
+
years(q?: {
|
|
174
|
+
ids?: readonly number[];
|
|
175
|
+
year?: number;
|
|
176
|
+
}): Promise<{
|
|
177
|
+
tag: string;
|
|
178
|
+
years: DancerYear[];
|
|
179
|
+
}>;
|
|
147
180
|
resolve(q: DancerQuery): Promise<DancerAnswer>;
|
|
148
181
|
search(q: DancerSearchQuery): Promise<DancerAnswer>;
|
|
149
182
|
private capped;
|
package/dist/types/feises.d.ts
CHANGED
|
@@ -77,6 +77,14 @@ export declare const NO_CALENDAR = "the release holds a feis-year once its resul
|
|
|
77
77
|
export declare class FeisFinder {
|
|
78
78
|
private readonly rel;
|
|
79
79
|
constructor(rel: Release);
|
|
80
|
+
dates(): Promise<{
|
|
81
|
+
tag: string;
|
|
82
|
+
dates: {
|
|
83
|
+
feis_id: string;
|
|
84
|
+
date_lo: string | null;
|
|
85
|
+
date_hi: string | null;
|
|
86
|
+
}[];
|
|
87
|
+
}>;
|
|
80
88
|
find(q: FeisQuery): Promise<FeisAnswer>;
|
|
81
89
|
codeStem(token: string, stem: string): Promise<string[]>;
|
|
82
90
|
seriesOf(brand: string): Promise<Series>;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { type AssetPlan, DATABASES, type DatabaseName, type LandedFile, type Receipt, type ReleaseManifest, planAsset, } from "./assets.js";
|
|
2
2
|
export { sha256File, unzstdTo } from "./bytes.js";
|
|
3
|
-
export { type AgeAsked, type AgeEvidence, type DancerAnswer, type DancerCandidate, type DancerQuery, type DancerRecord, DancerResolver, type DancerSchool, type DancerSearchQuery, type ExcludedCandidate, FEIS_LOCAL_ID_FLOOR, type PopulationEvidence, type SchoolEvidence, readPopulation, } from "./dancers.js";
|
|
3
|
+
export { type AgeAsked, type AgeEvidence, type DancerAnswer, type DancerBulkRecord, type DancerCandidate, type DancerQuery, type DancerRecord, DancerResolver, type DancerSchool, type DancerSearchQuery, type DancerYear, type ExcludedCandidate, FEIS_LOCAL_ID_FLOOR, type PopulationEvidence, type SchoolEvidence, readPopulation, } from "./dancers.js";
|
|
4
4
|
export { NAME_LEVELS, type NameLevel, nameLevel } from "./dancers-names.js";
|
|
5
5
|
export { type Comp, type CompAnswer, type CompKind, type CompQuery, CompResolver, type CompSource, type FeisPlace, type SyllabusAnswer, type SyllabusForAnswer, type SyllabusSource, type TitleCheck, canonicalOf, } from "./comps.js";
|
|
6
6
|
export { type ClientOptions, cacheRoot, repoOf } from "./config.js";
|
|
@@ -15,5 +15,6 @@ export { type MajorCompetition, type MajorEvent, MajorsFinder, type ResultAnswer
|
|
|
15
15
|
export { type DancerAnswerLike, type DancerQueryLike, type DancerResolverLike, type DancerUnavailable, type RegistrationRow, type ResolvedDancer, RegistrationResolver, type ResolvedRegistration, dancerResolverOf, youngest, } from "./registrations.js";
|
|
16
16
|
export { type SchoolAnswer, type SchoolCandidate, type SchoolQuery, SchoolResolver, type SchoolRung, } from "./schools.js";
|
|
17
17
|
export { type Capability, FEATURES, type Feature, type SchemaProbe, capabilityOf, columnsOf, needsRelease, } from "./schema.js";
|
|
18
|
+
export { type EntryRow, type StreamQuery, type StreamRow, type StreamScope, entryRank, } from "./stream.js";
|
|
18
19
|
export { EventFinder, type EventYear, type EventYearQuery, type ResultRoster, type RosterMember, type RosterTeam, TeamFinder, type TeamResult, } from "./teams.js";
|
|
19
20
|
export { ARCHIVE_TAG, type ArchiveTag, type ReleaseSpec, compareTagsNewestFirst, cutOf, parseArchiveTag, parseReleaseSpec, pickTag, renderArchiveTag, } from "./tag.js";
|
package/dist/types/results.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Release } from "./release.js";
|
|
2
|
+
import { type EntryRow, type StreamQuery, type StreamRow } from "./stream.js";
|
|
2
3
|
export declare const FEIS_LOCAL_ID_FLOOR = 17179869184;
|
|
3
4
|
export interface ResultQuery {
|
|
4
5
|
dancer_id?: number;
|
|
@@ -43,6 +44,9 @@ export declare class ResultFinder {
|
|
|
43
44
|
private readonly rel;
|
|
44
45
|
constructor(rel: Release);
|
|
45
46
|
query(q: ResultQuery): Promise<ResultAnswer>;
|
|
47
|
+
private streamDb;
|
|
48
|
+
stream(q: StreamQuery): AsyncGenerator<StreamRow>;
|
|
49
|
+
entries(q: StreamQuery): AsyncGenerator<EntryRow>;
|
|
46
50
|
}
|
|
47
51
|
export interface MajorEvent {
|
|
48
52
|
event: string;
|
|
@@ -78,5 +82,12 @@ export declare class MajorsFinder {
|
|
|
78
82
|
tag: string;
|
|
79
83
|
competitions: MajorCompetition[];
|
|
80
84
|
}>;
|
|
85
|
+
tabulated(q?: {
|
|
86
|
+
min_true_round?: number;
|
|
87
|
+
}): Promise<{
|
|
88
|
+
tag: string;
|
|
89
|
+
min_true_round: number;
|
|
90
|
+
addresses: string[];
|
|
91
|
+
}>;
|
|
81
92
|
results(q: ResultQuery): Promise<ResultAnswer>;
|
|
82
93
|
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { Database } from "bun:sqlite";
|
|
2
|
+
export type StreamScope = "majors" | "transcribed" | "platform" | "all";
|
|
3
|
+
export interface StreamQuery {
|
|
4
|
+
scope: StreamScope;
|
|
5
|
+
event?: string | string[];
|
|
6
|
+
year?: number | [number, number];
|
|
7
|
+
tier?: string[];
|
|
8
|
+
category?: string[];
|
|
9
|
+
feis_level?: number[];
|
|
10
|
+
dancer_id?: number[];
|
|
11
|
+
school_id?: string;
|
|
12
|
+
primary?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface StreamRow {
|
|
15
|
+
address: string;
|
|
16
|
+
competition: string;
|
|
17
|
+
event: string;
|
|
18
|
+
year: number | null;
|
|
19
|
+
tier: string;
|
|
20
|
+
comp_no: string | null;
|
|
21
|
+
title: string | null;
|
|
22
|
+
category: string | null;
|
|
23
|
+
age: string | null;
|
|
24
|
+
age_printed: string | null;
|
|
25
|
+
gender: string | null;
|
|
26
|
+
competitors: number | null;
|
|
27
|
+
feis_level: number | null;
|
|
28
|
+
level_printed: string | null;
|
|
29
|
+
date_printed: string | null;
|
|
30
|
+
source: string;
|
|
31
|
+
round: string | null;
|
|
32
|
+
feis_id: string | null;
|
|
33
|
+
feis_date_lo: string | null;
|
|
34
|
+
feis_date_hi: string | null;
|
|
35
|
+
section: string;
|
|
36
|
+
card: string;
|
|
37
|
+
place: number | null;
|
|
38
|
+
place_printed: string;
|
|
39
|
+
tie: number;
|
|
40
|
+
relative_place: number | null;
|
|
41
|
+
atts: string[];
|
|
42
|
+
withdrawn: string | null;
|
|
43
|
+
qualifier: string | null;
|
|
44
|
+
name_printed: string;
|
|
45
|
+
name: string | null;
|
|
46
|
+
school_printed: string;
|
|
47
|
+
school_loc: string;
|
|
48
|
+
school_id: string | null;
|
|
49
|
+
dancer_id: number | null;
|
|
50
|
+
dancer_scope: "per-release" | "stable" | null;
|
|
51
|
+
yob: number | null;
|
|
52
|
+
yob_printed: string | null;
|
|
53
|
+
points_printed: string | null;
|
|
54
|
+
platform_dancer_id: string | null;
|
|
55
|
+
primary_source: string | null;
|
|
56
|
+
}
|
|
57
|
+
export interface EntryRow extends StreamRow {
|
|
58
|
+
recall_place: number | null;
|
|
59
|
+
}
|
|
60
|
+
export declare function entryRank(section: string): number;
|
|
61
|
+
export declare const scopeDb: (s: StreamScope) => "majors" | "results";
|
|
62
|
+
export declare function streamSql(q: StreamQuery): {
|
|
63
|
+
sql: string;
|
|
64
|
+
args: (string | number)[];
|
|
65
|
+
};
|
|
66
|
+
export declare function feisDates(db: Database): Map<string, {
|
|
67
|
+
lo: string | null;
|
|
68
|
+
hi: string | null;
|
|
69
|
+
}>;
|
|
70
|
+
export declare function streamRows(db: Database, q: StreamQuery): AsyncGenerator<StreamRow>;
|
|
71
|
+
export declare function entryRows(db: Database, q: StreamQuery): AsyncGenerator<EntryRow>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@finbheara/archive-client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Open a versioned release of an Irish dance results archive: download, verify, decompress and cache it by tag, keep the cache, and resolve feises and schools against it",
|
|
5
5
|
"keywords": ["irish-dance", "results", "release", "cache", "sqlite"],
|
|
6
6
|
"license": "MIT",
|