@finbheara/archive-client 0.23.0 → 0.25.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 +68 -1
- package/dist/chunks/{index-vsk6837c.js → index-2ms980hc.js} +427 -16
- package/dist/cli.js +601 -144
- package/dist/index.js +7 -1
- package/dist/types/cli-spec.d.ts +15 -0
- package/dist/types/cli.d.ts +4 -2
- package/dist/types/index.d.ts +2 -0
- package/dist/types/people.d.ts +12 -0
- package/dist/types/release.d.ts +4 -0
- package/dist/types/school-bulk.d.ts +80 -0
- package/dist/types/schools.d.ts +33 -0
- package/dist/types/tabs.d.ts +132 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -95,6 +95,13 @@ c.features; // [{ feature: "dancers", state: "full" | "missing", missing: [...
|
|
|
95
95
|
| `teams` | `teams.results`, `teams.rosters`, `teams.resultRosters` | 260 |
|
|
96
96
|
| `teams.fields` | the fields `teams.results` (`age`, `gender`, `printed_status`) and `teams.rosters` (`dance`, `school_printed_as_of`, a member's `gender`) carry; absent, never refused, without it | 266 |
|
|
97
97
|
| `events` | `events.years` | 260 |
|
|
98
|
+
| `tabs`, `panels` | `tabs.query`, `tabs.stream`; `panels.query` | 184 |
|
|
99
|
+
| `feis-panels` | `feisPanels.query` | 260 |
|
|
100
|
+
| `staff.adjudicators` | `staff.adjudicators` | 230 |
|
|
101
|
+
| `schools.registry` | `schools.list` | 260 |
|
|
102
|
+
| `schools.prints`, `schools.redirects` | `schools.prints`; `schools.redirects` | 184 |
|
|
103
|
+
| `schools.lineage` | `schools.links`, `schools.line`, `schools.lineage` | 184 |
|
|
104
|
+
| `schools.associations` | `schools.associations` | 215 |
|
|
98
105
|
|
|
99
106
|
A spec is `pinned` (the default: the user-local pin, else the latest), `latest`, a cut number
|
|
100
107
|
(`42`, or `42.1` for a fraction) or a tag (`archive-YYYY.MM.DD-N`).
|
|
@@ -227,6 +234,29 @@ rows were published under and their rows, so it agrees with each print lookup of
|
|
|
227
234
|
|
|
228
235
|
Every answer carries the release tag it came from.
|
|
229
236
|
|
|
237
|
+
### The schools in bulk
|
|
238
|
+
|
|
239
|
+
```ts
|
|
240
|
+
await rel.schools.list(); // { schools: [{ school_id, display, regions, places }] }: the registry
|
|
241
|
+
await rel.schools.prints({ event: "<event>", year: 2024 });
|
|
242
|
+
// { prints: [{ event, year, print, school_id, rows }] }
|
|
243
|
+
await rel.schools.redirects(); // { redirects: [{ old_id, new_id, kind, since }] }
|
|
244
|
+
await rel.schools.lineage(); // { edges: [{ id, direction, other, shape, year, provisional,
|
|
245
|
+
// decision, confidence }] }
|
|
246
|
+
await rel.schools.associations({ school_id: "<id>" });
|
|
247
|
+
// { associations: [{ at, seq, date, person, person_printed,
|
|
248
|
+
// person_type, credentials, caption, school_printed, school_id,
|
|
249
|
+
// association_type, src_type, src, candidate_school_id, candidate_rung, ... }] }
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
`prints` is every (print, school id) pair the release's result rows attach in an event-year (the
|
|
253
|
+
print trimmed), with the rows that carry it: an event's (case-blind), a year's, both or every one.
|
|
254
|
+
A row attached to no school is in no pair, and a team result's school is `rel.teams.results`'.
|
|
255
|
+
`lineage` is each edge end as the release publishes it (an edge may carry both ends): `links` and
|
|
256
|
+
`line` are the graph over them. `associations` is the people a directory lists beside a school, as
|
|
257
|
+
evidence of an association, never an identity: `school_id` is the school the print attached to,
|
|
258
|
+
`candidate_school_id` one it reached without attaching.
|
|
259
|
+
|
|
230
260
|
### How two schools are linked
|
|
231
261
|
|
|
232
262
|
```ts
|
|
@@ -550,6 +580,33 @@ await rel.feises.dates(); // every feis id with its first a
|
|
|
550
580
|
await rel.majors.tabulated({ min_true_round: 3 }); // the majors addresses marked to round 3 or later
|
|
551
581
|
```
|
|
552
582
|
|
|
583
|
+
## Marks sheets and panels
|
|
584
|
+
|
|
585
|
+
```ts
|
|
586
|
+
const s = await rel.tabs.query({ competition: "<competition>" }); // or { address }, and a { round }
|
|
587
|
+
s.rows; // [{ address, competition, card, line, event, year, tier, round, true_round, seat_index,
|
|
588
|
+
// section, panel_size, column_order, drop_rule, the judge (name, print, TD number,
|
|
589
|
+
// id, unmatched reason), mark, mark_printed, place, place_printed, tie, points,
|
|
590
|
+
// points_printed }]
|
|
591
|
+
for await (const t of rel.tabs.stream({ tier: ["T1", "T2", "T3"], year: [2015, 2025] })) ...
|
|
592
|
+
await rel.panels.query({ competition: "<competition>" }); // { seats: [{ competition, panel, round,
|
|
593
|
+
// seat_index, address, the judge (print, TD number, id, unmatched reason) }] }
|
|
594
|
+
await rel.feisPanels.query({ address: "fweb:<code>.<comp>" }); // { seats: [{ address, platform, round,
|
|
595
|
+
// seat_index, panel_size, panel_kind, the judge (print, state printed, TD number, id,
|
|
596
|
+
// unmatched reason, basis) }] }
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
A marks sheet is a row per card, round and seat, with the seat's mark, place and points as read
|
|
600
|
+
beside their prints, from `results.sqlite` (every tabulated sheet, the T4 events' too). The stream
|
|
601
|
+
takes an event (or several, case-blind), a year or an inclusive range, tiers, competitions, or
|
|
602
|
+
nothing (every cell), and yields one competition's rows together. A sheet's `event`, `year` and
|
|
603
|
+
`tier` are its competition's: a solo competition's from the results, a team competition's from the
|
|
604
|
+
team results (with the tier the release gives that event-year's solo competitions). A sheet the
|
|
605
|
+
release places in neither carries nulls, and a filter on them never reaches it. `panels` and
|
|
606
|
+
`feisPanels` with nothing named answer every seat. `round` is `rx` where one panel sat every round.
|
|
607
|
+
A seat carries its judge's TD number where the release linked one, else a judge id, else the
|
|
608
|
+
reason it is linked to neither (`TabRow`, `PanelSeat` and `FeisPanelSeat` name the fields).
|
|
609
|
+
|
|
553
610
|
## Teams and event-years
|
|
554
611
|
|
|
555
612
|
```ts
|
|
@@ -596,6 +653,9 @@ release into the `teams` and `events` indexes.
|
|
|
596
653
|
```ts
|
|
597
654
|
await rel.staff.teacher("<name>"); // or a TD number
|
|
598
655
|
await rel.staff.adjudicator("<name>");
|
|
656
|
+
await rel.staff.adjudicators({ year: 2025 }); // the register's rows (or a TD number's, or every one):
|
|
657
|
+
// [{ the TD number, year, cat, name_printed, country, country_printed, country_code, region,
|
|
658
|
+
// region_printed, region_code, geohash, src }] (`RegisterRow`)
|
|
599
659
|
```
|
|
600
660
|
|
|
601
661
|
One person per TD number (else per judge id, else per name): the schools taught at (role,
|
|
@@ -747,6 +807,13 @@ is passed to the dancer resolver as asked (`rel.dancers`, above).
|
|
|
747
807
|
idq records --years [--release <spec>] [--dancer <id,...>] [--year <y>]
|
|
748
808
|
idq feis-dates [--release <spec>]
|
|
749
809
|
idq tabulated [--release <spec>] [--min-round <n>]
|
|
810
|
+
idq tabs [--release <spec>] --comp <competition> | --address <address> [--round <r>]
|
|
811
|
+
idq tabs --stream [--release <spec>] [--comp <c,...>] [--event <e,...>] [--year <y> | --year <from>..<to>] [--tier <t,...>]
|
|
812
|
+
idq panels [--release <spec>] [--comp <competition>]
|
|
813
|
+
idq feis-panels [--release <spec>] [--address <feis competition>] [--platform <p>]
|
|
814
|
+
idq register [--release <spec>] [--year <y>] [--td <TD number>]
|
|
815
|
+
idq schools [--release <spec>] [--prints [--event <e>] [--year <y>] | --redirects | --lineage
|
|
816
|
+
| --associations [--school <school_id>]]
|
|
750
817
|
idq teams [--release <spec>] [--event <e>] [--year <y>] [--rosters | --joins]
|
|
751
818
|
idq events [--release <spec>] [--event <e>] [--year <y>]
|
|
752
819
|
idq teacher [--release <spec>] <name|TD number>
|
|
@@ -759,7 +826,7 @@ is passed to the dancer resolver as asked (`rel.dancers`, above).
|
|
|
759
826
|
[--oireachtas <region>[:<year>]]
|
|
760
827
|
idq resolve registrations
|
|
761
828
|
|
|
762
|
-
`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
|
|
829
|
+
`stream` (and `tabs --stream`) prints one JSON line per row (or entry, or cell), as it reads them. `dancer` prints the results of the one dancer where the answer is unique (every candidate's with
|
|
763
830
|
`--rows`). `--json` prints the call's answer as it is. `--cache` and `--repo` override the defaults.
|
|
764
831
|
|
|
765
832
|
`update` moves to the newest published release, as a package manager's `update` moves to the newest
|
|
@@ -774,6 +774,96 @@ import {
|
|
|
774
774
|
DEFAULT_SCHOOL_NAME_READER,
|
|
775
775
|
schoolEncoder
|
|
776
776
|
} from "@finbheara/domain/school";
|
|
777
|
+
|
|
778
|
+
var str = (v) => typeof v === "string" && v !== "" ? v : null;
|
|
779
|
+
var num = (v) => typeof v === "number" ? v : null;
|
|
780
|
+
var uniq = (xs) => [...new Set(xs)];
|
|
781
|
+
async function registrySchools(rel) {
|
|
782
|
+
await rel.require("schools.registry");
|
|
783
|
+
await rel.fetch("school-registry.jsonl");
|
|
784
|
+
const schools = readJsonl(rel.path("school-registry.jsonl")).map((r) => ({
|
|
785
|
+
school_id: r.school_id,
|
|
786
|
+
display: r.display,
|
|
787
|
+
regions: uniq((r.regions ?? []).map((x) => x.region)),
|
|
788
|
+
places: uniq((r.locations ?? []).map((x) => x.place))
|
|
789
|
+
})).sort((a, b) => a.school_id < b.school_id ? -1 : a.school_id > b.school_id ? 1 : 0);
|
|
790
|
+
return { tag: rel.tag, schools };
|
|
791
|
+
}
|
|
792
|
+
async function schoolPrints(rel, q) {
|
|
793
|
+
await rel.fetch("results");
|
|
794
|
+
await rel.require("schools.prints");
|
|
795
|
+
const where = ["r.school_id IS NOT NULL"];
|
|
796
|
+
const args = [];
|
|
797
|
+
if (q.event !== undefined) {
|
|
798
|
+
where.push("c.event = ? COLLATE NOCASE");
|
|
799
|
+
args.push(q.event);
|
|
800
|
+
}
|
|
801
|
+
if (q.year !== undefined) {
|
|
802
|
+
where.push("c.year = ?");
|
|
803
|
+
args.push(q.year);
|
|
804
|
+
}
|
|
805
|
+
const prints = rel.db("results").query(`SELECT c.event AS event, c.year AS year, trim(r.school_printed) AS print,
|
|
806
|
+
r.school_id AS school_id, count(*) AS rows
|
|
807
|
+
FROM competitions c JOIN results r ON r.file = c.file AND r.competition_line = c.line
|
|
808
|
+
WHERE ${where.join(" AND ")} GROUP BY 1, 2, 3, 4 ORDER BY 2, 1, 3, 4`).all(...args);
|
|
809
|
+
return { tag: rel.tag, asked: q, prints };
|
|
810
|
+
}
|
|
811
|
+
async function schoolRedirects(rel) {
|
|
812
|
+
await rel.require("schools.redirects");
|
|
813
|
+
await rel.fetch("school-redirects.jsonl");
|
|
814
|
+
const redirects = readJsonl(rel.path("school-redirects.jsonl")).map((r) => ({
|
|
815
|
+
old_id: String(r.old_id),
|
|
816
|
+
new_id: String(r.new_id),
|
|
817
|
+
kind: String(r.kind),
|
|
818
|
+
since: num(r.since)
|
|
819
|
+
}));
|
|
820
|
+
return { tag: rel.tag, redirects };
|
|
821
|
+
}
|
|
822
|
+
async function schoolLineage(rel) {
|
|
823
|
+
await rel.require("schools.lineage");
|
|
824
|
+
await rel.fetch("school-lineage.jsonl");
|
|
825
|
+
const edges = readJsonl(rel.path("school-lineage.jsonl")).map((r) => ({
|
|
826
|
+
id: String(r.id),
|
|
827
|
+
direction: String(r.direction),
|
|
828
|
+
other: String(r.other),
|
|
829
|
+
shape: String(r.shape),
|
|
830
|
+
year: num(r.year),
|
|
831
|
+
provisional: r.provisional === true,
|
|
832
|
+
decision: str(r.decision),
|
|
833
|
+
confidence: num(r.confidence)
|
|
834
|
+
}));
|
|
835
|
+
return { tag: rel.tag, edges };
|
|
836
|
+
}
|
|
837
|
+
async function observedAssociations(rel, q) {
|
|
838
|
+
await rel.require("schools.associations");
|
|
839
|
+
await rel.fetch("observed-associations.jsonl");
|
|
840
|
+
const associations = [];
|
|
841
|
+
for (const r of readJsonl(rel.path("observed-associations.jsonl"))) {
|
|
842
|
+
const school_id = str(r.schoolId);
|
|
843
|
+
if (q.school_id !== undefined && school_id !== q.school_id)
|
|
844
|
+
continue;
|
|
845
|
+
associations.push({
|
|
846
|
+
at: String(r.at),
|
|
847
|
+
seq: num(r.seq) ?? 0,
|
|
848
|
+
date: str(r.date),
|
|
849
|
+
person: str(r.person),
|
|
850
|
+
person_printed: typeof r.personPrinted === "string" ? r.personPrinted : "",
|
|
851
|
+
reading: str(r.reading),
|
|
852
|
+
person_type: str(r.personType),
|
|
853
|
+
credentials: str(r.credentials),
|
|
854
|
+
caption: str(r.caption),
|
|
855
|
+
school_printed: str(r.school),
|
|
856
|
+
school_id,
|
|
857
|
+
association_type: str(r.associationType),
|
|
858
|
+
src_type: str(r.srcType),
|
|
859
|
+
src: str(r.src),
|
|
860
|
+
candidate_school_id: str(r.candidateSchoolId),
|
|
861
|
+
candidate_rung: str(r.candidateRung)
|
|
862
|
+
});
|
|
863
|
+
}
|
|
864
|
+
return { tag: rel.tag, asked: q, associations };
|
|
865
|
+
}
|
|
866
|
+
|
|
777
867
|
function readsSpanishNames2(candidates) {
|
|
778
868
|
return candidates.some((c) => c.spanishNames !== undefined && (c.spanishNames.file || c.prints.some((p) => c.spanishNames?.prints.includes(p.trim()))));
|
|
779
869
|
}
|
|
@@ -846,6 +936,21 @@ class SchoolResolver2 {
|
|
|
846
936
|
this.graph ??= releaseSchoolGraph2(this.rel);
|
|
847
937
|
return { tag: this.rel.tag, ...(await this.graph).line(a.trim(), q) };
|
|
848
938
|
}
|
|
939
|
+
list() {
|
|
940
|
+
return registrySchools(this.rel);
|
|
941
|
+
}
|
|
942
|
+
prints(q = {}) {
|
|
943
|
+
return schoolPrints(this.rel, q);
|
|
944
|
+
}
|
|
945
|
+
redirects() {
|
|
946
|
+
return schoolRedirects(this.rel);
|
|
947
|
+
}
|
|
948
|
+
lineage() {
|
|
949
|
+
return schoolLineage(this.rel);
|
|
950
|
+
}
|
|
951
|
+
associations(q = {}) {
|
|
952
|
+
return observedAssociations(this.rel, q);
|
|
953
|
+
}
|
|
849
954
|
async resolve(asked, q = {}) {
|
|
850
955
|
const db = await this.rel.indexDb("schools");
|
|
851
956
|
const reg = db.query("SELECT display, regions, places, spanish FROM registry WHERE school_id = ?");
|
|
@@ -2246,6 +2351,218 @@ import {
|
|
|
2246
2351
|
roleEncoder
|
|
2247
2352
|
} from "@finbheara/domain/noun-index";
|
|
2248
2353
|
import { roleName } from "@finbheara/domain/person";
|
|
2354
|
+
|
|
2355
|
+
var TAB_COLUMNS = `address, slug AS competition, card, line, round, true_round, seat_index,
|
|
2356
|
+
section, panel_size, column_order, drop_rule, judge_name, judge_name_printed, judge_clrg,
|
|
2357
|
+
judge_id, judge_unmatched, mark, mark_printed, place, place_printed, tie, points, points_printed`;
|
|
2358
|
+
var TAB_NEEDS = [
|
|
2359
|
+
"address",
|
|
2360
|
+
"slug",
|
|
2361
|
+
"card",
|
|
2362
|
+
"line",
|
|
2363
|
+
"round",
|
|
2364
|
+
"true_round",
|
|
2365
|
+
"seat_index",
|
|
2366
|
+
"section",
|
|
2367
|
+
"panel_size",
|
|
2368
|
+
"column_order",
|
|
2369
|
+
"drop_rule",
|
|
2370
|
+
"judge_name",
|
|
2371
|
+
"judge_name_printed",
|
|
2372
|
+
"judge_clrg",
|
|
2373
|
+
"judge_id",
|
|
2374
|
+
"judge_unmatched",
|
|
2375
|
+
"mark",
|
|
2376
|
+
"mark_printed",
|
|
2377
|
+
"place",
|
|
2378
|
+
"place_printed",
|
|
2379
|
+
"tie",
|
|
2380
|
+
"points",
|
|
2381
|
+
"points_printed"
|
|
2382
|
+
].map((c) => `results:tabs.${c}`);
|
|
2383
|
+
var NO_SHEET = { event: null, year: null, tier: null };
|
|
2384
|
+
var cardRange = (competition) => [`${competition}#`, `${competition}$`];
|
|
2385
|
+
|
|
2386
|
+
class TabFinder2 {
|
|
2387
|
+
rel;
|
|
2388
|
+
constructor(rel) {
|
|
2389
|
+
this.rel = rel;
|
|
2390
|
+
}
|
|
2391
|
+
async db() {
|
|
2392
|
+
await this.rel.fetch("results");
|
|
2393
|
+
await this.rel.require("tabs");
|
|
2394
|
+
return this.rel.db("results");
|
|
2395
|
+
}
|
|
2396
|
+
async sheets(db, only) {
|
|
2397
|
+
const out = new Map;
|
|
2398
|
+
const tiers = new Map;
|
|
2399
|
+
const rows = [];
|
|
2400
|
+
if (only === null)
|
|
2401
|
+
rows.push(...db.query("SELECT competition, event, year, tier FROM competitions WHERE competition IN (SELECT DISTINCT slug FROM tabs)").all());
|
|
2402
|
+
else
|
|
2403
|
+
for (let i = 0;i < only.length; i += 500) {
|
|
2404
|
+
const part = only.slice(i, i + 500);
|
|
2405
|
+
rows.push(...db.query(`SELECT competition, event, year, tier FROM competitions WHERE competition IN (${part.map(() => "?").join(", ")})`).all(...part));
|
|
2406
|
+
}
|
|
2407
|
+
for (const r of rows) {
|
|
2408
|
+
out.set(r.competition, { event: r.event, year: r.year, tier: r.tier });
|
|
2409
|
+
tiers.set(`${r.event.toLowerCase()}\x00${r.year}`, r.tier);
|
|
2410
|
+
}
|
|
2411
|
+
const missing = only === null ? null : only.filter((c) => !out.has(c));
|
|
2412
|
+
if (missing !== null && missing.length === 0)
|
|
2413
|
+
return out;
|
|
2414
|
+
if ((await this.rel.capability("teams")).state !== "full")
|
|
2415
|
+
return out;
|
|
2416
|
+
const teams = await this.rel.indexDb("teams");
|
|
2417
|
+
const team = teams.query("SELECT competition, event, year FROM result WHERE competition IS NOT NULL GROUP BY competition");
|
|
2418
|
+
const want = missing === null ? null : new Set(missing);
|
|
2419
|
+
for (const t of team.all()) {
|
|
2420
|
+
if (out.has(t.competition) || want !== null && !want.has(t.competition))
|
|
2421
|
+
continue;
|
|
2422
|
+
out.set(t.competition, {
|
|
2423
|
+
event: t.event,
|
|
2424
|
+
year: t.year,
|
|
2425
|
+
tier: tiers.get(`${t.event.toLowerCase()}\x00${t.year}`) ?? null
|
|
2426
|
+
});
|
|
2427
|
+
}
|
|
2428
|
+
if ([...out.values()].some((s) => s.tier === null && s.event !== null)) {
|
|
2429
|
+
for (const r of db.query("SELECT event, year, min(tier) AS tier FROM competitions GROUP BY event, year").all())
|
|
2430
|
+
tiers.set(`${r.event.toLowerCase()}\x00${r.year}`, r.tier);
|
|
2431
|
+
for (const s of out.values())
|
|
2432
|
+
if (s.tier === null && s.event !== null)
|
|
2433
|
+
s.tier = tiers.get(`${s.event.toLowerCase()}\x00${s.year}`) ?? null;
|
|
2434
|
+
}
|
|
2435
|
+
return out;
|
|
2436
|
+
}
|
|
2437
|
+
async query(q) {
|
|
2438
|
+
const db = await this.db();
|
|
2439
|
+
const where = [];
|
|
2440
|
+
const args = [];
|
|
2441
|
+
if (q.address !== undefined) {
|
|
2442
|
+
where.push("address = ?");
|
|
2443
|
+
args.push(q.address);
|
|
2444
|
+
} else if (q.competition !== undefined) {
|
|
2445
|
+
const [lo, hi] = cardRange(q.competition);
|
|
2446
|
+
where.push("address >= ? AND address < ? AND slug = ?");
|
|
2447
|
+
args.push(lo, hi, q.competition);
|
|
2448
|
+
} else
|
|
2449
|
+
throw new Error("archive-client: a tabs query names a competition or an address");
|
|
2450
|
+
if (q.round !== undefined) {
|
|
2451
|
+
where.push("round = ?");
|
|
2452
|
+
args.push(q.round);
|
|
2453
|
+
}
|
|
2454
|
+
const raw = db.query(`SELECT ${TAB_COLUMNS} FROM tabs WHERE ${where.join(" AND ")} ORDER BY address, round, seat_index, line`).all(...args);
|
|
2455
|
+
const sheets = raw.length === 0 ? new Map : await this.sheets(db, [...new Set(raw.map((r) => r.competition))]);
|
|
2456
|
+
return {
|
|
2457
|
+
tag: this.rel.tag,
|
|
2458
|
+
asked: q,
|
|
2459
|
+
rows: raw.map((r) => ({ ...r, ...sheets.get(r.competition) ?? NO_SHEET }))
|
|
2460
|
+
};
|
|
2461
|
+
}
|
|
2462
|
+
async* stream(q = {}) {
|
|
2463
|
+
const db = await this.db();
|
|
2464
|
+
const sheets = await this.sheets(db, q.competition ?? null);
|
|
2465
|
+
const events = q.event === undefined ? null : new Set((typeof q.event === "string" ? [q.event] : q.event).map((e) => e.toLowerCase()));
|
|
2466
|
+
const tiers = q.tier === undefined ? null : new Set(q.tier);
|
|
2467
|
+
const holds = (s) => {
|
|
2468
|
+
if (events !== null && (s.event === null || !events.has(s.event.toLowerCase())))
|
|
2469
|
+
return false;
|
|
2470
|
+
if (tiers !== null && (s.tier === null || !tiers.has(s.tier)))
|
|
2471
|
+
return false;
|
|
2472
|
+
if (typeof q.year === "number" && s.year !== q.year)
|
|
2473
|
+
return false;
|
|
2474
|
+
if (Array.isArray(q.year) && (s.year === null || s.year < q.year[0] || s.year > q.year[1]))
|
|
2475
|
+
return false;
|
|
2476
|
+
return true;
|
|
2477
|
+
};
|
|
2478
|
+
const filtered = events !== null || tiers !== null || q.year !== undefined;
|
|
2479
|
+
const run = function* (stmt, args) {
|
|
2480
|
+
for (const r of stmt.iterate(...args))
|
|
2481
|
+
yield { ...r, ...sheets.get(r.competition) ?? NO_SHEET };
|
|
2482
|
+
};
|
|
2483
|
+
if (!filtered && q.competition === undefined) {
|
|
2484
|
+
const all = db.prepare(`SELECT ${TAB_COLUMNS} FROM tabs ORDER BY address, round, seat_index, line`);
|
|
2485
|
+
try {
|
|
2486
|
+
yield* run(all, []);
|
|
2487
|
+
} finally {
|
|
2488
|
+
all.finalize();
|
|
2489
|
+
}
|
|
2490
|
+
return;
|
|
2491
|
+
}
|
|
2492
|
+
const asked = [...new Set(q.competition ?? sheets.keys())].filter((c) => holds(sheets.get(c) ?? NO_SHEET));
|
|
2493
|
+
const one = db.prepare(`SELECT ${TAB_COLUMNS} FROM tabs WHERE address >= ? AND address < ? AND slug = ? ORDER BY address, round, seat_index, line`);
|
|
2494
|
+
try {
|
|
2495
|
+
for (const c of asked.sort((a, b) => a < b ? -1 : a > b ? 1 : 0)) {
|
|
2496
|
+
const [lo, hi] = cardRange(c);
|
|
2497
|
+
yield* run(one, [lo, hi, c]);
|
|
2498
|
+
}
|
|
2499
|
+
} finally {
|
|
2500
|
+
one.finalize();
|
|
2501
|
+
}
|
|
2502
|
+
}
|
|
2503
|
+
}
|
|
2504
|
+
|
|
2505
|
+
class PanelFinder2 {
|
|
2506
|
+
rel;
|
|
2507
|
+
constructor(rel) {
|
|
2508
|
+
this.rel = rel;
|
|
2509
|
+
}
|
|
2510
|
+
async query(q = {}) {
|
|
2511
|
+
await this.rel.fetch("results");
|
|
2512
|
+
await this.rel.require("panels");
|
|
2513
|
+
const where = q.competition === undefined ? "" : " WHERE slug = ?";
|
|
2514
|
+
const seats = this.rel.db("results").query(`SELECT slug AS competition, panel, round, seat_index, address, judge_name_printed,
|
|
2515
|
+
judge_clrg, judge_id, judge_unmatched
|
|
2516
|
+
FROM panels${where} ORDER BY slug, panel, round, seat_index`).all(...q.competition === undefined ? [] : [q.competition]);
|
|
2517
|
+
return { tag: this.rel.tag, asked: q, seats };
|
|
2518
|
+
}
|
|
2519
|
+
}
|
|
2520
|
+
|
|
2521
|
+
class FeisPanelFinder2 {
|
|
2522
|
+
rel;
|
|
2523
|
+
constructor(rel) {
|
|
2524
|
+
this.rel = rel;
|
|
2525
|
+
}
|
|
2526
|
+
async query(q = {}) {
|
|
2527
|
+
await this.rel.fetch("results");
|
|
2528
|
+
await this.rel.require("feis-panels");
|
|
2529
|
+
const where = [];
|
|
2530
|
+
const args = [];
|
|
2531
|
+
if (q.address !== undefined) {
|
|
2532
|
+
where.push("address = ?");
|
|
2533
|
+
args.push(q.address);
|
|
2534
|
+
}
|
|
2535
|
+
if (q.platform !== undefined) {
|
|
2536
|
+
where.push("platform = ?");
|
|
2537
|
+
args.push(q.platform);
|
|
2538
|
+
}
|
|
2539
|
+
const seats = this.rel.db("results").query(`SELECT address, platform, round, seat_index, panel_size, panel_kind, judge_name_printed,
|
|
2540
|
+
judge_state_printed, judge_clrg, judge_id, judge_unmatched, judge_basis
|
|
2541
|
+
FROM feis_panels${where.length === 0 ? "" : ` WHERE ${where.join(" AND ")}`}
|
|
2542
|
+
ORDER BY address, round, seat_index`).all(...args);
|
|
2543
|
+
return { tag: this.rel.tag, asked: q, seats };
|
|
2544
|
+
}
|
|
2545
|
+
}
|
|
2546
|
+
async function registerRows(rel, q) {
|
|
2547
|
+
await rel.fetch("results");
|
|
2548
|
+
await rel.require("staff.adjudicators");
|
|
2549
|
+
const where = [];
|
|
2550
|
+
const args = [];
|
|
2551
|
+
if (q.judge_clrg !== undefined) {
|
|
2552
|
+
where.push("judge_clrg = ?");
|
|
2553
|
+
args.push(q.judge_clrg);
|
|
2554
|
+
}
|
|
2555
|
+
if (q.year !== undefined) {
|
|
2556
|
+
where.push("year = ?");
|
|
2557
|
+
args.push(q.year);
|
|
2558
|
+
}
|
|
2559
|
+
const rows = rel.db("results").query(`SELECT judge_clrg, year, cat, name_printed, country, country_printed, country_code, region,
|
|
2560
|
+
region_printed, region_code, geohash, src
|
|
2561
|
+
FROM adjudicators${where.length === 0 ? "" : ` WHERE ${where.join(" AND ")}`}
|
|
2562
|
+
ORDER BY judge_clrg, year`).all(...args);
|
|
2563
|
+
return { tag: rel.tag, asked: q, rows };
|
|
2564
|
+
}
|
|
2565
|
+
|
|
2249
2566
|
var ENCODER2 = roleEncoder();
|
|
2250
2567
|
var WHO = { table: "who", value: "entry", valueType: "INTEGER PRIMARY KEY" };
|
|
2251
2568
|
var ASKED2 = ["surname_key", "nn4", "id"];
|
|
@@ -2363,6 +2680,9 @@ class StaffFinder2 {
|
|
|
2363
2680
|
adjudicator(asked) {
|
|
2364
2681
|
return this.find(asked, "adjudicator");
|
|
2365
2682
|
}
|
|
2683
|
+
adjudicators(q = {}) {
|
|
2684
|
+
return registerRows(this.rel, q);
|
|
2685
|
+
}
|
|
2366
2686
|
async find(asked, role) {
|
|
2367
2687
|
const db = await this.rel.indexDb("staff");
|
|
2368
2688
|
const a = asked.trim();
|
|
@@ -2507,8 +2827,8 @@ async function parquetColumns(path) {
|
|
|
2507
2827
|
return new Set(parquetSchema(meta).children.map((c) => c.element.name));
|
|
2508
2828
|
}
|
|
2509
2829
|
|
|
2510
|
-
var
|
|
2511
|
-
var
|
|
2830
|
+
var str2 = (v) => typeof v === "string" && v !== "" ? v : null;
|
|
2831
|
+
var num2 = (v) => typeof v === "number" ? v : null;
|
|
2512
2832
|
var strs = (v) => Array.isArray(v) ? v.filter((x) => typeof x === "string") : [];
|
|
2513
2833
|
var scope = (id) => id === null ? null : id >= FEIS_LOCAL_ID_FLOOR2 ? "per-release" : "stable";
|
|
2514
2834
|
var TEAM_TABLES = [
|
|
@@ -2563,9 +2883,9 @@ var teamsIndex = {
|
|
|
2563
2883
|
const ey = new Map;
|
|
2564
2884
|
const putEy = out.prepare("INSERT OR IGNORE INTO event_year VALUES (?, ?, ?)");
|
|
2565
2885
|
for (const r of t.event_years) {
|
|
2566
|
-
const k =
|
|
2567
|
-
const event =
|
|
2568
|
-
const year =
|
|
2886
|
+
const k = str2(r.event_year);
|
|
2887
|
+
const event = str2(r.event);
|
|
2888
|
+
const year = num2(r.year);
|
|
2569
2889
|
if (k === null || event === null || year === null)
|
|
2570
2890
|
continue;
|
|
2571
2891
|
ey.set(k, { event, year });
|
|
@@ -2574,19 +2894,19 @@ var teamsIndex = {
|
|
|
2574
2894
|
const putR = out.prepare("INSERT OR IGNORE INTO result VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
|
|
2575
2895
|
let ord = 0;
|
|
2576
2896
|
for (const r of t.team_results)
|
|
2577
|
-
putR.run(
|
|
2897
|
+
putR.run(str2(r.address), str2(r.slug), str2(r.event), num2(r.year), str2(r.card), str2(r.comp_no), str2(r.title), str2(r.category), num2(r.hands), str2(r.letter), str2(r.label), str2(r.name_printed), str2(r.school_printed), str2(r.school_loc), str2(r.school_id), num2(r.place), str2(r.place_printed), num2(r.tie), num2(r.competitors), JSON.stringify(strs(r.atts)), str2(r.age), str2(r.gender), JSON.stringify(strs(r.printed_status)), ord++);
|
|
2578
2898
|
const putT = out.prepare("INSERT OR IGNORE INTO roster_team VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
|
|
2579
2899
|
for (const r of t.roster_teams) {
|
|
2580
|
-
const e = ey.get(
|
|
2581
|
-
putT.run(
|
|
2900
|
+
const e = ey.get(str2(r.event_year) ?? "");
|
|
2901
|
+
putT.run(str2(r.team), str2(r.kind), e?.event ?? null, num2(r.year) ?? e?.year ?? null, str2(r.comp_no), str2(r.title), str2(r.team_index), num2(r.seq), str2(r.school_id), str2(r.school_print_materialized), str2(r.dance), str2(r.school_print_as_of), ord++);
|
|
2582
2902
|
}
|
|
2583
2903
|
const putM = out.prepare("INSERT INTO roster_member VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
|
|
2584
2904
|
for (const r of t.roster_members)
|
|
2585
|
-
putM.run(
|
|
2905
|
+
putM.run(str2(r.team), num2(r.seq), typeof r.name_printed === "string" ? r.name_printed : "", str2(r.name), num2(r.yob), num2(r.dancer_id), str2(r.gender), ord++);
|
|
2586
2906
|
const putJ = out.prepare("INSERT INTO result_roster VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
|
|
2587
2907
|
for (const r of t.team_result_rosters) {
|
|
2588
|
-
const e = ey.get(
|
|
2589
|
-
putJ.run(
|
|
2908
|
+
const e = ey.get(str2(r.event_year) ?? "");
|
|
2909
|
+
putJ.run(str2(r.team), e?.event ?? null, e?.year ?? null, str2(r.comp_no), str2(r.school_id), str2(r.result_address), str2(r.join_kind), num2(r.via_split) === 1 ? 1 : 0, num2(r.roster_teams), num2(r.result_teams), str2(r.roster_index), str2(r.result_letter), ord++);
|
|
2590
2910
|
}
|
|
2591
2911
|
for (const s of TEAMS_INDEXES)
|
|
2592
2912
|
out.run(s);
|
|
@@ -2606,11 +2926,11 @@ var eventsIndex = {
|
|
|
2606
2926
|
out.run(EVENTS_SCHEMA);
|
|
2607
2927
|
const put = out.prepare("INSERT OR IGNORE INTO event_year VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)");
|
|
2608
2928
|
for (const r of rows) {
|
|
2609
|
-
const event =
|
|
2610
|
-
const year =
|
|
2929
|
+
const event = str2(r.event);
|
|
2930
|
+
const year = num2(r.year);
|
|
2611
2931
|
if (event === null || year === null)
|
|
2612
2932
|
continue;
|
|
2613
|
-
put.run(event, year,
|
|
2933
|
+
put.run(event, year, str2(r.date_lo), str2(r.date_hi), str2(r.resolution), str2(r.source), JSON.stringify(strs(r.date_printed)), str2(r.place), JSON.stringify(strs(r.place_printed)));
|
|
2614
2934
|
}
|
|
2615
2935
|
out.run("CREATE INDEX event_year_event ON event_year(event COLLATE NOCASE)");
|
|
2616
2936
|
}
|
|
@@ -3238,7 +3558,7 @@ var FEATURES2 = [
|
|
|
3238
3558
|
feature: "schools.lineage",
|
|
3239
3559
|
needs: ["school-lineage.jsonl"],
|
|
3240
3560
|
since: 184,
|
|
3241
|
-
calls: "schools.links and schools.
|
|
3561
|
+
calls: "schools.links, schools.line and schools.lineage (refused on a release without it), and the `lineage` school evidence of dancers.resolve and dancers.search: no school is joined by lineage, never refused, on a release without it"
|
|
3242
3562
|
},
|
|
3243
3563
|
{
|
|
3244
3564
|
feature: "results.stream",
|
|
@@ -3407,6 +3727,91 @@ var FEATURES2 = [
|
|
|
3407
3727
|
],
|
|
3408
3728
|
since: 260,
|
|
3409
3729
|
calls: "staff.teacher, staff.adjudicator (the staff index)"
|
|
3730
|
+
},
|
|
3731
|
+
{ feature: "tabs", needs: TAB_NEEDS, since: 184, calls: "tabs.query, tabs.stream" },
|
|
3732
|
+
{
|
|
3733
|
+
feature: "panels",
|
|
3734
|
+
needs: [
|
|
3735
|
+
"slug",
|
|
3736
|
+
"panel",
|
|
3737
|
+
"round",
|
|
3738
|
+
"seat_index",
|
|
3739
|
+
"address",
|
|
3740
|
+
"judge_name_printed",
|
|
3741
|
+
"judge_clrg",
|
|
3742
|
+
"judge_id",
|
|
3743
|
+
"judge_unmatched"
|
|
3744
|
+
].map((c) => `results:panels.${c}`),
|
|
3745
|
+
since: 184,
|
|
3746
|
+
calls: "panels.query"
|
|
3747
|
+
},
|
|
3748
|
+
{
|
|
3749
|
+
feature: "feis-panels",
|
|
3750
|
+
needs: [
|
|
3751
|
+
"address",
|
|
3752
|
+
"platform",
|
|
3753
|
+
"round",
|
|
3754
|
+
"seat_index",
|
|
3755
|
+
"panel_size",
|
|
3756
|
+
"panel_kind",
|
|
3757
|
+
"judge_name_printed",
|
|
3758
|
+
"judge_state_printed",
|
|
3759
|
+
"judge_clrg",
|
|
3760
|
+
"judge_id",
|
|
3761
|
+
"judge_unmatched",
|
|
3762
|
+
"judge_basis"
|
|
3763
|
+
].map((c) => `results:feis_panels.${c}`),
|
|
3764
|
+
since: 260,
|
|
3765
|
+
calls: "feisPanels.query"
|
|
3766
|
+
},
|
|
3767
|
+
{
|
|
3768
|
+
feature: "staff.adjudicators",
|
|
3769
|
+
needs: [
|
|
3770
|
+
"judge_clrg",
|
|
3771
|
+
"year",
|
|
3772
|
+
"cat",
|
|
3773
|
+
"name_printed",
|
|
3774
|
+
"country",
|
|
3775
|
+
"country_printed",
|
|
3776
|
+
"country_code",
|
|
3777
|
+
"region",
|
|
3778
|
+
"region_printed",
|
|
3779
|
+
"region_code",
|
|
3780
|
+
"geohash",
|
|
3781
|
+
"src"
|
|
3782
|
+
].map((c) => `results:adjudicators.${c}`),
|
|
3783
|
+
since: 230,
|
|
3784
|
+
calls: "staff.adjudicators"
|
|
3785
|
+
},
|
|
3786
|
+
{
|
|
3787
|
+
feature: "schools.registry",
|
|
3788
|
+
needs: ["school-registry.jsonl"],
|
|
3789
|
+
since: 260,
|
|
3790
|
+
calls: "schools.list"
|
|
3791
|
+
},
|
|
3792
|
+
{
|
|
3793
|
+
feature: "schools.prints",
|
|
3794
|
+
needs: [
|
|
3795
|
+
"results:results.school_printed",
|
|
3796
|
+
"results:results.school_id",
|
|
3797
|
+
"results:results.competition_line",
|
|
3798
|
+
"results:competitions.event",
|
|
3799
|
+
"results:competitions.year"
|
|
3800
|
+
],
|
|
3801
|
+
since: 184,
|
|
3802
|
+
calls: "schools.prints"
|
|
3803
|
+
},
|
|
3804
|
+
{
|
|
3805
|
+
feature: "schools.redirects",
|
|
3806
|
+
needs: ["school-redirects.jsonl"],
|
|
3807
|
+
since: 184,
|
|
3808
|
+
calls: "schools.redirects"
|
|
3809
|
+
},
|
|
3810
|
+
{
|
|
3811
|
+
feature: "schools.associations",
|
|
3812
|
+
needs: ["observed-associations.jsonl"],
|
|
3813
|
+
since: 215,
|
|
3814
|
+
calls: "schools.associations"
|
|
3410
3815
|
}
|
|
3411
3816
|
];
|
|
3412
3817
|
async function hasNeed(probe, n) {
|
|
@@ -3490,6 +3895,9 @@ class Release2 {
|
|
|
3490
3895
|
registrations;
|
|
3491
3896
|
teams;
|
|
3492
3897
|
events;
|
|
3898
|
+
tabs;
|
|
3899
|
+
panels;
|
|
3900
|
+
feisPanels;
|
|
3493
3901
|
opts;
|
|
3494
3902
|
handles = new Map;
|
|
3495
3903
|
remoteAssets = null;
|
|
@@ -3512,6 +3920,9 @@ class Release2 {
|
|
|
3512
3920
|
this.registrations = new RegistrationResolver2(this, this.comps, opts.dancerResolver);
|
|
3513
3921
|
this.teams = new TeamFinder2(this);
|
|
3514
3922
|
this.events = new EventFinder2(this);
|
|
3923
|
+
this.tabs = new TabFinder2(this);
|
|
3924
|
+
this.panels = new PanelFinder2(this);
|
|
3925
|
+
this.feisPanels = new FeisPanelFinder2(this);
|
|
3515
3926
|
}
|
|
3516
3927
|
receipt() {
|
|
3517
3928
|
return readReceipt(this.dir) ?? { tag: this.tag, source: "unknown", files: {} };
|
|
@@ -4232,4 +4643,4 @@ function staleWarning2(answered, latest, floor, tags = [], command = "idq") {
|
|
|
4232
4643
|
return `answered from ${answered}. ${floorTag ?? `cut ${floor.cut}`} is required${why}: run \`${command} use ${floor.cut}\` to get it`;
|
|
4233
4644
|
}
|
|
4234
4645
|
|
|
4235
|
-
export { DATABASES2, planAsset2, sha256File2, unzstdTo2, NAME_LEVELS2, nameLevel2, NO_CALENDAR2, FeisFinder2, ADVANCEMENT_DANCES2, entryRank2, FEIS_LOCAL_ID_FLOOR2, ResultFinder2, MajorsFinder2, LINEAGE_FILE2, linksOfLineage2, releaseSchoolGraph2, readsSpanishNames2, SchoolResolver2, initialsOnly2, nameOrderOf, DancerResolver2, readPopulation2, syllabusSourceOf2, canonicalOf2, CompResolver2, StaffFinder2, TeamFinder2, EventFinder2, defaultBuilders2, indexPath2, indexKey2, isCurrent2, buildIndex2, ensureIndex2, listIndexes2, readPin2, youngest2, dancerResolverOf2, RegistrationResolver2, ghRemote2, httpsRemote2, fallbackRemote2, setRemote2, defaultRemote, columnsOf2, FEATURES2, capabilityOf2, needsRelease2, resolveTag2, Release2, openRelease2, openCached2, DEFAULT_KEEP2, ReleaseManager2, releases2, LOCAL_DIR2, localRoot2, newerThan2, incomplete2, releaseVersion2, pickBuild2, buildTag2, lacks, openBuild2, sweepBuilds2, LATEST_CHECK_MS2, LATEST_CHECK_BUDGET_MS2, latestCheckPath2, readLatestCheck2, latestCheck2, within, staleWarning2 };
|
|
4646
|
+
export { DATABASES2, planAsset2, sha256File2, unzstdTo2, NAME_LEVELS2, nameLevel2, NO_CALENDAR2, FeisFinder2, ADVANCEMENT_DANCES2, entryRank2, FEIS_LOCAL_ID_FLOOR2, ResultFinder2, MajorsFinder2, LINEAGE_FILE2, linksOfLineage2, releaseSchoolGraph2, readsSpanishNames2, SchoolResolver2, initialsOnly2, nameOrderOf, DancerResolver2, readPopulation2, syllabusSourceOf2, canonicalOf2, CompResolver2, TabFinder2, PanelFinder2, FeisPanelFinder2, StaffFinder2, TeamFinder2, EventFinder2, defaultBuilders2, indexPath2, indexKey2, isCurrent2, buildIndex2, ensureIndex2, listIndexes2, readPin2, youngest2, dancerResolverOf2, RegistrationResolver2, ghRemote2, httpsRemote2, fallbackRemote2, setRemote2, defaultRemote, columnsOf2, FEATURES2, capabilityOf2, needsRelease2, resolveTag2, Release2, openRelease2, openCached2, DEFAULT_KEEP2, ReleaseManager2, releases2, LOCAL_DIR2, localRoot2, newerThan2, incomplete2, releaseVersion2, pickBuild2, buildTag2, lacks, openBuild2, sweepBuilds2, LATEST_CHECK_MS2, LATEST_CHECK_BUDGET_MS2, latestCheckPath2, readLatestCheck2, latestCheck2, within, staleWarning2 };
|