@finbheara/archive-client 0.2.0 → 0.3.1
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 +23 -1
- package/dist/chunks/{index-6e2gb6sk.js → index-3va2jzse.js} +38 -11
- package/dist/cli.js +2 -2
- package/dist/index.js +1 -1
- package/dist/types/comps.d.ts +9 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -189,7 +189,8 @@ print exactly as the release published it, then the print read by `@finbheara/do
|
|
|
189
189
|
reader at its filing key (`sn3`) and at its real words. `ambiguous` and `none` are answers: a
|
|
190
190
|
best guess is never promoted to `unique`. `region` drops only a candidate the registry places in
|
|
191
191
|
other regions, and keeps one it places nowhere. A print the reader refuses (a placeholder)
|
|
192
|
-
answers `none` with the reason.
|
|
192
|
+
answers `none` with the reason. An id (or a retired id followed) answers with every print its
|
|
193
|
+
rows were published under and their rows, so it agrees with each print lookup of that school.
|
|
193
194
|
|
|
194
195
|
Every answer carries the release tag it came from.
|
|
195
196
|
|
|
@@ -249,6 +250,10 @@ A FEIS-LOCAL ID (`FEIS_LOCAL_ID_FLOOR`, 2^34, and up) is valid in its release on
|
|
|
249
250
|
carrying one say `scope: "per-release"` (`dancer_scope` on a row), so a caller never stores one
|
|
250
251
|
across releases. Every answer carries the release tag.
|
|
251
252
|
|
|
253
|
+
A MAJORS ID (under the floor) is kept across releases on a best-effort basis only: a merge
|
|
254
|
+
retires one, a split mints one, and a renumbered source page can hand one to another dancer. A
|
|
255
|
+
caller that joins ids across releases checks the name and the rows it expects.
|
|
256
|
+
|
|
252
257
|
## Results and the majors
|
|
253
258
|
|
|
254
259
|
```ts
|
|
@@ -284,6 +289,8 @@ c.source; // "syllabus" | "prior-year" | "title"
|
|
|
284
289
|
c.kind; // "championship" | "grade" | "unrated"
|
|
285
290
|
c.level; // "OC" (FF, BG, AB, NV, PW, PC, OC), c.feis_level 700
|
|
286
291
|
c.age; // "U10", c.population "mixed", c.canonical "710OC", c.title, c.competition
|
|
292
|
+
c.age_source; // "printed" | "title" | "code" | "merged" | null, c.age_printed "U10" as printed
|
|
293
|
+
c.second; // true for a second chance or a supplementary comp beside the main one
|
|
287
294
|
c.from; // { feis_ids: ["fweb:ABC25"], year: 2025 } where an earlier year answered
|
|
288
295
|
c.check; // "unchecked", or what the caller's `title` says about the earlier comp
|
|
289
296
|
c.syllabus_source; // "results": what the syllabus the answer read is read from
|
|
@@ -326,6 +333,21 @@ QuickFeis numbers its own and-over championships (`15 & over` prelim `616PC`, `1
|
|
|
326
333
|
`719OC`). An and-over code is then the same string as an `Under N + 1` one, and `age` (`O18`)
|
|
327
334
|
tells them apart. An adult band, a range and a grade render none.
|
|
328
335
|
|
|
336
|
+
`age` is the release's reading, and `age_source` says where it was read. A `merged` comp (a
|
|
337
|
+
platform's comps merged into one, `710OCM` with no `710OC` beside it) prints one member's band,
|
|
338
|
+
so its `age` is the union of its members' (`U12` for `710OCM - U10 Open Champion` where the next
|
|
339
|
+
open the feis prints is `713OCM`), and `age_printed` keeps the platform's own field (`U10`). A
|
|
340
|
+
joined code at the bottom of its series stays open below (`710OC/711OC` with no open under 10
|
|
341
|
+
beside it is `U11/11yr`, every age under 11), as a younger dancer dances up into it.
|
|
342
|
+
|
|
343
|
+
`population` is the sex the release states, else a population word in the title, else the
|
|
344
|
+
code's sex suffix read with every code its feis printed (`codePopulation` from
|
|
345
|
+
`@finbheara/domain/title`: `720OCB` beside `720OCG` is boys and girls, `512M` beside `512` is
|
|
346
|
+
boys, a lone `713OCM` says nothing), else the release's `mixed` for a grade or a preliminary
|
|
347
|
+
championship. `second` is read from the words of the title and the platform's level and dance
|
|
348
|
+
fields (`secondIn`: `2nd Chance`, `2nd Chc`, `Second Chance`, `Supplementary Prelim`, `2nd Open
|
|
349
|
+
Champ`), and never from a code's digit, which marks a round's half at some hosts (`610PC2H`).
|
|
350
|
+
|
|
329
351
|
## Registrations
|
|
330
352
|
|
|
331
353
|
```ts
|
|
@@ -655,9 +655,11 @@ function ageEvidence(d, asked) {
|
|
|
655
655
|
|
|
656
656
|
import { Age as Age2 } from "@finbheara/domain/age";
|
|
657
657
|
import {
|
|
658
|
+
codePopulation,
|
|
658
659
|
compTitle,
|
|
659
660
|
matchTitle,
|
|
660
661
|
populationIn as populationIn2,
|
|
662
|
+
secondIn,
|
|
661
663
|
titleRelation
|
|
662
664
|
} from "@finbheara/domain/title";
|
|
663
665
|
var LEVEL = Object.freeze({
|
|
@@ -674,17 +676,25 @@ CREATE TABLE comp(
|
|
|
674
676
|
competition TEXT PRIMARY KEY, feis_id TEXT NOT NULL, brand_id TEXT, year INTEGER,
|
|
675
677
|
code TEXT NOT NULL, code_fold TEXT NOT NULL, title TEXT, age TEXT, gender TEXT,
|
|
676
678
|
feis_level INTEGER, round TEXT, platform TEXT NOT NULL, captures INTEGER NOT NULL,
|
|
677
|
-
file TEXT NOT NULL, line INTEGER NOT NULL
|
|
679
|
+
file TEXT NOT NULL, line INTEGER NOT NULL, age_source TEXT, age_printed TEXT,
|
|
680
|
+
gender_source TEXT, level_printed TEXT, dance_printed TEXT
|
|
678
681
|
);
|
|
679
682
|
`;
|
|
680
683
|
var INDEXES = [
|
|
681
684
|
"CREATE INDEX comp_feis_code ON comp(feis_id, code_fold)",
|
|
682
685
|
"CREATE INDEX comp_brand_year ON comp(brand_id, year)"
|
|
683
686
|
];
|
|
687
|
+
var OPTIONAL = [
|
|
688
|
+
"age_source",
|
|
689
|
+
"age_printed",
|
|
690
|
+
"gender_source",
|
|
691
|
+
"level_printed",
|
|
692
|
+
"dance_printed"
|
|
693
|
+
];
|
|
684
694
|
var fold = (code) => code.trim().toLowerCase();
|
|
685
695
|
var compsIndex = {
|
|
686
696
|
name: "comps",
|
|
687
|
-
version: "
|
|
697
|
+
version: "2",
|
|
688
698
|
inputs: ["results"],
|
|
689
699
|
says: "every competition by its feis and its own code, with its series and year",
|
|
690
700
|
build(rel, out) {
|
|
@@ -697,19 +707,23 @@ var compsIndex = {
|
|
|
697
707
|
const captures = new Map;
|
|
698
708
|
for (const r of src.query("SELECT competition, count(*) AS n FROM competitions GROUP BY competition").all())
|
|
699
709
|
captures.set(r.competition, r.n);
|
|
700
|
-
const put = out.prepare("INSERT OR IGNORE INTO comp VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
|
|
701
|
-
|
|
710
|
+
const put = out.prepare("INSERT OR IGNORE INTO comp VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
|
|
711
|
+
const has = new Set(src.query("PRAGMA table_info(competitions)").all().map((r) => r.name));
|
|
712
|
+
const opt = (col) => has.has(col) ? col : `NULL AS ${col}`;
|
|
713
|
+
for (const c of src.query(`SELECT competition, event, year, comp_no, title, age, gender, feis_level, round, source, file, line, ${OPTIONAL.map(opt).join(", ")} FROM competitions WHERE comp_no IS NOT NULL AND trim(comp_no) != '' ORDER BY file, line`).iterate()) {
|
|
702
714
|
const f = brand.get(c.event);
|
|
703
|
-
put.run(c.competition, c.event, f?.brand ?? null, c.year ?? f?.year ?? null, c.comp_no.trim(), fold(c.comp_no), c.title, c.age, c.gender, c.feis_level, c.round, c.source, captures.get(c.competition) ?? 1, c.file, c.line);
|
|
715
|
+
put.run(c.competition, c.event, f?.brand ?? null, c.year ?? f?.year ?? null, c.comp_no.trim(), fold(c.comp_no), c.title, c.age, c.gender, c.feis_level, c.round, c.source, captures.get(c.competition) ?? 1, c.file, c.line, c.age_source, c.age_printed, c.gender_source, c.level_printed, c.dance_printed);
|
|
704
716
|
}
|
|
705
717
|
for (const s of INDEXES)
|
|
706
718
|
out.run(s);
|
|
707
719
|
}
|
|
708
720
|
};
|
|
709
|
-
function compOf(r) {
|
|
721
|
+
function compOf(r, codes = []) {
|
|
710
722
|
const lv = r.feis_level;
|
|
711
723
|
const kind = lv === null ? "unrated" : lv >= 600 ? "championship" : "grade";
|
|
712
|
-
const
|
|
724
|
+
const stated = r.gender_source === "level" ? "" : populationIn2(r.gender ?? "");
|
|
725
|
+
const pop = stated || populationIn2(r.title ?? "") || (r.platform === "ifeis" && codes.length > 0 ? codePopulation(r.code, codes) : "") || populationIn2(r.gender ?? "");
|
|
726
|
+
const second = [r.title, r.level_printed, r.dance_printed].some((t) => t != null && secondIn(t));
|
|
713
727
|
const round = r.round ?? (r.title === null ? null : compTitle(r.title).round?.toString() ?? null);
|
|
714
728
|
return {
|
|
715
729
|
competition: r.competition,
|
|
@@ -721,7 +735,10 @@ function compOf(r) {
|
|
|
721
735
|
feis_level: lv,
|
|
722
736
|
level: lv === null ? null : LEVEL[lv] ?? null,
|
|
723
737
|
age: r.age,
|
|
738
|
+
age_source: r.age_source ?? null,
|
|
739
|
+
age_printed: r.age_printed ?? null,
|
|
724
740
|
population: pop === "" ? null : pop,
|
|
741
|
+
second,
|
|
725
742
|
round,
|
|
726
743
|
canonical: canonicalOf2(lv, r.age),
|
|
727
744
|
platform: r.platform,
|
|
@@ -828,7 +845,12 @@ class CompResolver2 {
|
|
|
828
845
|
const marks = feisIds.map(() => "?").join(", ");
|
|
829
846
|
const sql = `SELECT * FROM comp WHERE feis_id IN (${marks})${code !== undefined ? " AND code_fold = ?" : ""} ORDER BY file, line`;
|
|
830
847
|
const args = code !== undefined ? [...feisIds, fold(code)] : [...feisIds];
|
|
831
|
-
|
|
848
|
+
const rows = db.query(sql).all(...args);
|
|
849
|
+
const all = code === undefined ? rows : db.query(`SELECT feis_id, code FROM comp WHERE feis_id IN (${marks})`).all(...feisIds);
|
|
850
|
+
const codes = new Map;
|
|
851
|
+
for (const r of all)
|
|
852
|
+
codes.set(r.feis_id, [...codes.get(r.feis_id) ?? [], r.code]);
|
|
853
|
+
return rows.map((r) => compOf(r, codes.get(r.feis_id) ?? []));
|
|
832
854
|
}
|
|
833
855
|
async idsOf(brand, year) {
|
|
834
856
|
return (await this.ofSeries("", brand, year, "series")).feis_ids;
|
|
@@ -1437,7 +1459,7 @@ var encoderOf = (r) => schoolEncoder({ reader: r.reader });
|
|
|
1437
1459
|
var TABLE = "school_name";
|
|
1438
1460
|
var schoolsIndex = {
|
|
1439
1461
|
name: "schools",
|
|
1440
|
-
version: "
|
|
1462
|
+
version: "2",
|
|
1441
1463
|
inputs: ["results", "school-registry.jsonl", "school-redirects.jsonl"],
|
|
1442
1464
|
says: "every published school print and its ids, read at the school reader's slots",
|
|
1443
1465
|
keyParts: (rel) => [`reader=${rel.schoolReader().id}`],
|
|
@@ -1453,6 +1475,7 @@ var schoolsIndex = {
|
|
|
1453
1475
|
const putPair = out.prepare("INSERT INTO print_id VALUES (?, ?, ?)");
|
|
1454
1476
|
for (const r of pairs)
|
|
1455
1477
|
putPair.run(r.p, r.s, r.n);
|
|
1478
|
+
out.run("CREATE INDEX print_id_school ON print_id(school_id)");
|
|
1456
1479
|
const names = createIndex3(out, encoder, {
|
|
1457
1480
|
table: TABLE
|
|
1458
1481
|
});
|
|
@@ -1512,9 +1535,13 @@ class SchoolResolver2 {
|
|
|
1512
1535
|
...extra
|
|
1513
1536
|
};
|
|
1514
1537
|
};
|
|
1538
|
+
const byId = (id, by) => {
|
|
1539
|
+
const rs = db.query("SELECT print, rows FROM print_id WHERE school_id = ? ORDER BY print").all(id);
|
|
1540
|
+
return candidate(id, by, rs.reduce((n, r) => n + r.rows, 0), rs.map((r) => r.print));
|
|
1541
|
+
};
|
|
1515
1542
|
const a = asked.trim();
|
|
1516
1543
|
if (reg.get(a) !== null)
|
|
1517
|
-
return answer([
|
|
1544
|
+
return answer([byId(a, "id")]);
|
|
1518
1545
|
let live = a;
|
|
1519
1546
|
const seen = new Set;
|
|
1520
1547
|
for (;; ) {
|
|
@@ -1525,7 +1552,7 @@ class SchoolResolver2 {
|
|
|
1525
1552
|
live = r.new_id;
|
|
1526
1553
|
}
|
|
1527
1554
|
if (live !== a)
|
|
1528
|
-
return answer([
|
|
1555
|
+
return answer([byId(live, "redirect")], { redirected: { from: a, to: live } });
|
|
1529
1556
|
const byPrints = (prints, by) => {
|
|
1530
1557
|
const ids = new Map;
|
|
1531
1558
|
const q2 = db.query("SELECT school_id, rows FROM print_id WHERE print = ?");
|
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-3va2jzse.js";
|
|
8
8
|
import"./chunks/index-hne1wadw.js";
|
|
9
9
|
import"./chunks/index-hghdy980.js";
|
|
10
10
|
|
|
@@ -690,7 +690,7 @@ async function main(argv, io = {}) {
|
|
|
690
690
|
out(a, () => {
|
|
691
691
|
say(`${a.feis.asked} ${a.year ?? "?"} ${a.held ? `held: ${a.feis.feis_ids.join(", ")}` : "not held"} series ${a.feis.brand_id ?? "-"} (years ${a.years.join(", ") || "-"}) in ${a.tag}`);
|
|
692
692
|
for (const c of a.entries)
|
|
693
|
-
say(` ${c.code} ${c.kind} ${c.level ?? "-"} ${c.age ?? "-"} ${c.population ?? "-"} "${c.title ?? ""}"`);
|
|
693
|
+
say(` ${c.code} ${c.kind} ${c.level ?? "-"} ${c.age ?? "-"} ${c.population ?? "-"}${c.second ? " second" : ""} "${c.title ?? ""}"`);
|
|
694
694
|
say(`${a.entries.length} comp(s)`);
|
|
695
695
|
});
|
|
696
696
|
rel.close();
|
package/dist/index.js
CHANGED
package/dist/types/comps.d.ts
CHANGED
|
@@ -15,7 +15,10 @@ export interface Comp {
|
|
|
15
15
|
feis_level: number | null;
|
|
16
16
|
level: string | null;
|
|
17
17
|
age: string | null;
|
|
18
|
+
age_source: string | null;
|
|
19
|
+
age_printed: string | null;
|
|
18
20
|
population: Population | null;
|
|
21
|
+
second: boolean;
|
|
19
22
|
round: string | null;
|
|
20
23
|
canonical: string | null;
|
|
21
24
|
platform: string;
|
|
@@ -107,8 +110,13 @@ interface CompRow {
|
|
|
107
110
|
round: string | null;
|
|
108
111
|
platform: string;
|
|
109
112
|
captures: number;
|
|
113
|
+
age_source?: string | null;
|
|
114
|
+
age_printed?: string | null;
|
|
115
|
+
gender_source?: string | null;
|
|
116
|
+
level_printed?: string | null;
|
|
117
|
+
dance_printed?: string | null;
|
|
110
118
|
}
|
|
111
|
-
export declare function compOf(r: CompRow): Comp;
|
|
119
|
+
export declare function compOf(r: CompRow, codes?: readonly string[]): Comp;
|
|
112
120
|
export declare function canonicalOf(level: number | null, age: string | null): string | null;
|
|
113
121
|
export declare class CompResolver {
|
|
114
122
|
private readonly rel;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@finbheara/archive-client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
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",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"prepublishOnly": "bun scripts/build.ts && bun ../../tools/checks/archive-client-tarball.ts"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@finbheara/domain": "0.
|
|
47
|
+
"@finbheara/domain": "0.49.0",
|
|
48
48
|
"@finbheara/names": "0.22.0"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|