@finbheara/archive-client 0.13.0 → 0.15.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 +26 -4
- package/dist/chunks/{index-1ty89s8d.js → index-9r4rw6xq.js} +251 -191
- package/dist/cli.js +3 -2
- package/dist/index.js +4 -2
- package/dist/types/cli.d.ts +1 -1
- package/dist/types/comps.d.ts +1 -0
- package/dist/types/dancers-names.d.ts +3 -1
- package/dist/types/dancers.d.ts +1 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/schools.d.ts +6 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -238,12 +238,26 @@ NO NEW MATCHER. A print is read in the dancer's role by `@finbheara/domain` over
|
|
|
238
238
|
`@finbheara/names`, and a candidate's `nameLevel` is the finest of: `nn0` to `nn4` (equal at that
|
|
239
239
|
level of the names package: the print, the key, the folded key, the tokens in any order),
|
|
240
240
|
`initial` (one surname, one given name the other's made poorer: `givenAbbreviates`), `middle`
|
|
241
|
-
(a middle name one print omits: `nameRelation`)
|
|
241
|
+
(a middle name one print omits: `nameRelation`), `given-middle` (one surname, and the first given
|
|
242
|
+
name one print uses is a later given name of the other's, `Grace Zumock` of `Ailbhe Grace Zumock`:
|
|
243
|
+
asked only where no finer level found anyone), `spanish` (see below). `age` is how the dancer's published birth window
|
|
242
244
|
meets the asked age (`Age.fitsIn`, `overlaps`): `fits`, `overlaps`, `contradicts`, `unknown`.
|
|
243
245
|
`school` is how the dancer's schools meet the asked one: `same` (the latest school as of `asOf`),
|
|
244
246
|
`lineage` (the latest school is one the release's lineage joins to the asked one), `moved` (an
|
|
245
247
|
earlier one is the asked one), `none`, `unresolved` (the print reached no school).
|
|
246
248
|
|
|
249
|
+
A SPANISH NAME, AT A SITE THAT CARRIES `spanishNames`. A register prints the full form, given
|
|
250
|
+
names and a paternal and a maternal surname (`Ana Inés Varrondo Quelmar`), and a results sheet
|
|
251
|
+
often prints one given name and the paternal surname alone (`Inés Varrondo`). A school file, or a
|
|
252
|
+
branch of one, is flagged `spanishNames: true` in the store, and the release's
|
|
253
|
+
`school-registry.jsonl` line carries it as `spanish_names: { file, prints }` (the file's own flag,
|
|
254
|
+
and the prints of its flagged branches). Where the name as asked finds no one and the asked school
|
|
255
|
+
reads that way (`readsSpanishNames(candidates)`: a flagged file, or a print that reached it is one
|
|
256
|
+
of its flagged branches' prints), every print of every dancer at that school is asked under the
|
|
257
|
+
names package's Spanish reading (`createNameKinship({ spanishNames: true })`), and a print it
|
|
258
|
+
relates is a candidate at `nameLevel: "spanish"`. A release with no `spanish_names` reads every
|
|
259
|
+
school the default way. A name the release already finds answers exactly as before.
|
|
260
|
+
|
|
247
261
|
THE LINEAGE is the release's `school-lineage.jsonl`: every line joins its `id` and its `other`,
|
|
248
262
|
whatever its direction (`precedes`, `succeeds`) or shape (a rename, a split, a merger, an absorb,
|
|
249
263
|
a relation), so a file carrying one end of an edge reads as one carrying both. The whole line
|
|
@@ -531,12 +545,20 @@ the host likes, so a code is answered from that feis's competitions in the relea
|
|
|
531
545
|
another platform's numbering. The sources, in order:
|
|
532
546
|
|
|
533
547
|
- `syllabus`: the feis-year is in the release, and one of its competitions prints the code
|
|
534
|
-
- `prior-year`: the feis-year is not (next year's, before its results)
|
|
535
|
-
|
|
536
|
-
|
|
548
|
+
- `prior-year`: the feis-year is not (next year's, before its results), and its platform numbers
|
|
549
|
+
every feis by one grammar (QuickFeis: `CODE_READER`, `@finbheara/domain/code`): the newest
|
|
550
|
+
earlier year of the same series printing the code. Give the comp's `title` and `matchTitle`
|
|
551
|
+
checks it against the earlier comp (`check`), and with no title the answer says `unchecked`
|
|
537
552
|
- `title`: the code answers nothing and a `title` was given: the competitions of that syllabus
|
|
538
553
|
the title names, by band and population
|
|
539
554
|
|
|
555
|
+
AN EARLIER YEAR'S CODE IS NEVER READ ON A FEIS-SPECIFIC PLATFORM. FeisWeb, FeisWorx, iFeis and
|
|
556
|
+
the rest renumber their competitions from one year to the next: measured in October 2026, the
|
|
557
|
+
same code at the same series one held year later names another band or level on 13% to 29% of
|
|
558
|
+
codes, a plausible answer and a wrong one. So an unheld feis-year there answers by its `title`
|
|
559
|
+
over the newest earlier syllabus, and a code with no title is `none`, saying why. The code of a
|
|
560
|
+
held feis-year is still read from that feis-year's own competitions.
|
|
561
|
+
|
|
540
562
|
A feis the release holds names itself, its year and its series. A series instance or brand id
|
|
541
563
|
names the series. A feis id the release does not hold is placed in a series by its host code
|
|
542
564
|
(`<token>:<stem><yy>` where the held codes of that stem carry their own year), and a stem two
|
|
@@ -68,7 +68,7 @@ function sha256OfDigest(digest) {
|
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
import { Age, DANCE_UP_YEARS, birthYearsMeet } from "@finbheara/domain/age";
|
|
71
|
-
import { createIndex, indexSchema, personEncoder } from "@finbheara/domain/noun-index";
|
|
71
|
+
import { createIndex as createIndex2, indexSchema as indexSchema2, personEncoder } from "@finbheara/domain/noun-index";
|
|
72
72
|
import domainPkg from "@finbheara/domain/package.json";
|
|
73
73
|
import { dancerName } from "@finbheara/domain/person";
|
|
74
74
|
import {
|
|
@@ -80,20 +80,25 @@ import {
|
|
|
80
80
|
composeNames,
|
|
81
81
|
foldNameKey,
|
|
82
82
|
nameBlockKeys,
|
|
83
|
-
nameKinship,
|
|
83
|
+
nameKinship as nameKinship2,
|
|
84
84
|
surnameBlock
|
|
85
85
|
} from "@finbheara/names/normalize";
|
|
86
86
|
import namesPkg from "@finbheara/names/package.json";
|
|
87
87
|
|
|
88
88
|
import {
|
|
89
|
+
KINSHIP_VIAS,
|
|
89
90
|
NAME_LEVEL_COLUMNS,
|
|
91
|
+
createNameKinship,
|
|
90
92
|
givenAbbreviates,
|
|
93
|
+
nameKinship,
|
|
91
94
|
nameRelation
|
|
92
95
|
} from "@finbheara/names/normalize";
|
|
93
96
|
var NAME_LEVELS2 = [
|
|
94
97
|
...NAME_LEVEL_COLUMNS,
|
|
95
98
|
"initial",
|
|
96
99
|
"middle",
|
|
100
|
+
"given-middle",
|
|
101
|
+
"spanish",
|
|
97
102
|
"form",
|
|
98
103
|
"surname",
|
|
99
104
|
"like"
|
|
@@ -113,6 +118,17 @@ function nameLevel2(q, c) {
|
|
|
113
118
|
return "middle";
|
|
114
119
|
return null;
|
|
115
120
|
}
|
|
121
|
+
function givenMiddleLevel(q, c) {
|
|
122
|
+
if (!q.isPerson() || !c.isPerson())
|
|
123
|
+
return null;
|
|
124
|
+
const k = nameKinship(q, c);
|
|
125
|
+
return k.relation !== "different" && k.via.includes("given-middle") && k.via.every((v) => v === "given-middle" || KINSHIP_VIAS[v].gateSafe) ? "given-middle" : null;
|
|
126
|
+
}
|
|
127
|
+
var spanish = createNameKinship({ spanishNames: true });
|
|
128
|
+
function spanishLevel(q, c) {
|
|
129
|
+
const k = spanish(q, c);
|
|
130
|
+
return k.relation !== "different" && k.via.includes("spanish") ? "spanish" : null;
|
|
131
|
+
}
|
|
116
132
|
|
|
117
133
|
import { readFileSync } from "fs";
|
|
118
134
|
var SCHEMA = `
|
|
@@ -616,6 +632,189 @@ class MajorsFinder2 {
|
|
|
616
632
|
}
|
|
617
633
|
}
|
|
618
634
|
|
|
635
|
+
import { createIndex, indexSchema } from "@finbheara/domain/noun-index";
|
|
636
|
+
import {
|
|
637
|
+
DEFAULT_SCHOOL_NAME_READER,
|
|
638
|
+
schoolEncoder
|
|
639
|
+
} from "@finbheara/domain/school";
|
|
640
|
+
function readsSpanishNames2(candidates) {
|
|
641
|
+
return candidates.some((c) => c.spanishNames !== undefined && (c.spanishNames.file || c.prints.some((p) => c.spanishNames?.prints.includes(p.trim()))));
|
|
642
|
+
}
|
|
643
|
+
var GENERIC_SCHOOL_READER = {
|
|
644
|
+
id: "generic",
|
|
645
|
+
reader: DEFAULT_SCHOOL_NAME_READER
|
|
646
|
+
};
|
|
647
|
+
var encoderOf = (r) => schoolEncoder({ reader: r.reader });
|
|
648
|
+
var TABLE = "school_name";
|
|
649
|
+
var schoolsIndex = {
|
|
650
|
+
name: "schools",
|
|
651
|
+
version: "3",
|
|
652
|
+
inputs: ["results", "school-registry.jsonl", "school-redirects.jsonl"],
|
|
653
|
+
says: "every published school print and its ids, read at the school reader's slots",
|
|
654
|
+
keyParts: (rel) => [`reader=${rel.schoolReader().id}`],
|
|
655
|
+
build(rel, out) {
|
|
656
|
+
const choice = rel.schoolReader();
|
|
657
|
+
const encoder = encoderOf(choice);
|
|
658
|
+
out.run("CREATE TABLE print_id(print TEXT NOT NULL, school_id TEXT NOT NULL, rows INTEGER NOT NULL, year_lo INTEGER, year_hi INTEGER, PRIMARY KEY(print, school_id)) WITHOUT ROWID");
|
|
659
|
+
out.run("CREATE TABLE registry(school_id TEXT PRIMARY KEY, display TEXT NOT NULL, regions TEXT NOT NULL, places TEXT NOT NULL, spanish TEXT)");
|
|
660
|
+
out.run("CREATE TABLE redirect(old_id TEXT PRIMARY KEY, new_id TEXT NOT NULL, kind TEXT NOT NULL)");
|
|
661
|
+
const schema = indexSchema(encoder, { table: TABLE });
|
|
662
|
+
out.run(schema.table);
|
|
663
|
+
const src = rel.db("results");
|
|
664
|
+
const lined = src.query("PRAGMA table_info(results)").all().some((c) => c.name === "competition_line");
|
|
665
|
+
const pairs = src.query(lined ? `SELECT trim(r.school_printed) AS p, r.school_id AS s, count(*) AS n,
|
|
666
|
+
min(c.year) AS lo, max(c.year) AS hi
|
|
667
|
+
FROM results r LEFT JOIN competitions c ON c.file = r.file AND c.line = r.competition_line
|
|
668
|
+
WHERE r.school_id IS NOT NULL GROUP BY 1, 2 ORDER BY 1, 2` : `SELECT trim(school_printed) AS p, school_id AS s, count(*) AS n, NULL AS lo, NULL AS hi
|
|
669
|
+
FROM results WHERE school_id IS NOT NULL GROUP BY 1, 2 ORDER BY 1, 2`).all();
|
|
670
|
+
const putPair = out.prepare("INSERT INTO print_id VALUES (?, ?, ?, ?, ?)");
|
|
671
|
+
for (const r of pairs)
|
|
672
|
+
putPair.run(r.p, r.s, r.n, r.lo, r.hi);
|
|
673
|
+
out.run("CREATE INDEX print_id_school ON print_id(school_id)");
|
|
674
|
+
const names = createIndex(out, encoder, {
|
|
675
|
+
table: TABLE
|
|
676
|
+
});
|
|
677
|
+
let last = null;
|
|
678
|
+
for (const r of pairs) {
|
|
679
|
+
if (r.p === last)
|
|
680
|
+
continue;
|
|
681
|
+
last = r.p;
|
|
682
|
+
names.add(choice.reader.schoolName(r.p), r.p);
|
|
683
|
+
}
|
|
684
|
+
for (const s of schema.indexes)
|
|
685
|
+
out.run(s);
|
|
686
|
+
const putReg = out.prepare("INSERT OR REPLACE INTO registry VALUES (?, ?, ?, ?, ?)");
|
|
687
|
+
for (const r of readJsonl(rel.path("school-registry.jsonl")))
|
|
688
|
+
putReg.run(r.school_id, r.display, JSON.stringify([...new Set(r.regions.map((x) => x.region))]), JSON.stringify([...new Set(r.locations.map((x) => x.place))]), r.spanish_names === undefined ? null : JSON.stringify({
|
|
689
|
+
file: r.spanish_names.file === true,
|
|
690
|
+
prints: [...new Set(r.spanish_names.prints.map((p) => p.trim()))].sort()
|
|
691
|
+
}));
|
|
692
|
+
const putRed = out.prepare("INSERT OR REPLACE INTO redirect VALUES (?, ?, ?)");
|
|
693
|
+
for (const r of readJsonl(rel.path("school-redirects.jsonl")))
|
|
694
|
+
putRed.run(r.old_id, r.new_id, r.kind);
|
|
695
|
+
}
|
|
696
|
+
};
|
|
697
|
+
|
|
698
|
+
class SchoolResolver2 {
|
|
699
|
+
rel;
|
|
700
|
+
constructor(rel) {
|
|
701
|
+
this.rel = rel;
|
|
702
|
+
}
|
|
703
|
+
async resolve(asked, q = {}) {
|
|
704
|
+
const db = await this.rel.indexDb("schools");
|
|
705
|
+
const reg = db.query("SELECT display, regions, places, spanish FROM registry WHERE school_id = ?");
|
|
706
|
+
const candidate = (id, by, rows, prints) => {
|
|
707
|
+
const r = reg.get(id);
|
|
708
|
+
return {
|
|
709
|
+
school_id: id,
|
|
710
|
+
display: r?.display ?? null,
|
|
711
|
+
rows,
|
|
712
|
+
by,
|
|
713
|
+
prints,
|
|
714
|
+
regions: r === null ? [] : JSON.parse(r.regions),
|
|
715
|
+
places: r === null ? [] : JSON.parse(r.places),
|
|
716
|
+
...r?.spanish == null ? {} : { spanishNames: JSON.parse(r.spanish) }
|
|
717
|
+
};
|
|
718
|
+
};
|
|
719
|
+
const answer = (candidates, extra = {}) => {
|
|
720
|
+
let cs = candidates.sort((a, b) => b.rows - a.rows || (a.school_id < b.school_id ? -1 : 1));
|
|
721
|
+
let year;
|
|
722
|
+
if (q.year !== undefined && cs.length > 1 && cs.every((c) => c.years !== undefined)) {
|
|
723
|
+
const y = q.year;
|
|
724
|
+
const span = (c) => c.years;
|
|
725
|
+
let kept = cs.filter((c) => {
|
|
726
|
+
const { lo, hi } = span(c);
|
|
727
|
+
return lo !== null && hi !== null && lo <= y && y <= hi;
|
|
728
|
+
});
|
|
729
|
+
if (kept.length === 0) {
|
|
730
|
+
const before = cs.filter((c) => span(c).hi !== null && span(c).hi < y);
|
|
731
|
+
const last = Math.max(...before.map((c) => span(c).hi));
|
|
732
|
+
kept = before.filter((c) => span(c).hi === last);
|
|
733
|
+
}
|
|
734
|
+
year = { asked: y, narrowed: kept.length > 0 && kept.length < cs.length };
|
|
735
|
+
if (kept.length > 0)
|
|
736
|
+
cs = kept;
|
|
737
|
+
}
|
|
738
|
+
let region;
|
|
739
|
+
if (q.region !== undefined) {
|
|
740
|
+
const kept = cs.filter((c) => c.regions.length === 0 || c.regions.includes(q.region));
|
|
741
|
+
region = { asked: q.region, narrowed: kept.length > 0 && kept.length < cs.length };
|
|
742
|
+
if (kept.length > 0)
|
|
743
|
+
cs = kept;
|
|
744
|
+
}
|
|
745
|
+
return {
|
|
746
|
+
tag: this.rel.tag,
|
|
747
|
+
asked,
|
|
748
|
+
arm: cs.length === 0 ? "none" : cs.length === 1 ? "unique" : "ambiguous",
|
|
749
|
+
candidates: cs,
|
|
750
|
+
...region !== undefined ? { region } : {},
|
|
751
|
+
...year !== undefined ? { year } : {},
|
|
752
|
+
...extra
|
|
753
|
+
};
|
|
754
|
+
};
|
|
755
|
+
const byId = (id, by) => {
|
|
756
|
+
const rs = db.query("SELECT print, rows FROM print_id WHERE school_id = ? ORDER BY print").all(id);
|
|
757
|
+
return candidate(id, by, rs.reduce((n, r) => n + r.rows, 0), rs.map((r) => r.print));
|
|
758
|
+
};
|
|
759
|
+
const a = asked.trim();
|
|
760
|
+
if (reg.get(a) !== null)
|
|
761
|
+
return answer([byId(a, "id")]);
|
|
762
|
+
let live = a;
|
|
763
|
+
const seen = new Set;
|
|
764
|
+
for (;; ) {
|
|
765
|
+
const r = db.query("SELECT new_id FROM redirect WHERE old_id = ?").get(live);
|
|
766
|
+
if (r === null || seen.has(r.new_id))
|
|
767
|
+
break;
|
|
768
|
+
seen.add(live);
|
|
769
|
+
live = r.new_id;
|
|
770
|
+
}
|
|
771
|
+
if (live !== a)
|
|
772
|
+
return answer([byId(live, "redirect")], { redirected: { from: a, to: live } });
|
|
773
|
+
const byPrints = (prints, by) => {
|
|
774
|
+
const ids = new Map;
|
|
775
|
+
const q2 = db.query("SELECT school_id, rows, year_lo AS lo, year_hi AS hi FROM print_id WHERE print = ?");
|
|
776
|
+
for (const p of prints)
|
|
777
|
+
for (const r of q2.all(p)) {
|
|
778
|
+
const e = ids.get(r.school_id) ?? {
|
|
779
|
+
rows: 0,
|
|
780
|
+
prints: new Set,
|
|
781
|
+
lo: null,
|
|
782
|
+
hi: null
|
|
783
|
+
};
|
|
784
|
+
e.rows += r.rows;
|
|
785
|
+
e.prints.add(p);
|
|
786
|
+
if (r.lo !== null && (e.lo === null || r.lo < e.lo))
|
|
787
|
+
e.lo = r.lo;
|
|
788
|
+
if (r.hi !== null && (e.hi === null || r.hi > e.hi))
|
|
789
|
+
e.hi = r.hi;
|
|
790
|
+
ids.set(r.school_id, e);
|
|
791
|
+
}
|
|
792
|
+
return [...ids].map(([id, e]) => ({
|
|
793
|
+
...candidate(id, by, e.rows, [...e.prints].sort()),
|
|
794
|
+
years: { lo: e.lo, hi: e.hi }
|
|
795
|
+
}));
|
|
796
|
+
};
|
|
797
|
+
const exact = byPrints([a], "print");
|
|
798
|
+
if (exact.length > 0)
|
|
799
|
+
return answer(exact);
|
|
800
|
+
const choice = this.rel.schoolReader();
|
|
801
|
+
const read = choice.reader.schoolName(a);
|
|
802
|
+
if (!read.isSchool())
|
|
803
|
+
return answer([], {
|
|
804
|
+
refused: read.refusal?.reason ?? (read.isEmpty() ? "empty" : "not a school")
|
|
805
|
+
});
|
|
806
|
+
const names = createIndex(db, encoderOf(choice), {
|
|
807
|
+
table: TABLE
|
|
808
|
+
});
|
|
809
|
+
for (const level of ["sn3", "realWords"]) {
|
|
810
|
+
const prints = names.get(read, level);
|
|
811
|
+
if (prints.length > 0)
|
|
812
|
+
return answer(byPrints(prints, level));
|
|
813
|
+
}
|
|
814
|
+
return answer([]);
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
|
|
619
818
|
var LINEAGE_FILE = "school-lineage.jsonl";
|
|
620
819
|
function schoolLine(lineage, ids, year) {
|
|
621
820
|
const reached = new Set(ids);
|
|
@@ -649,7 +848,7 @@ var dancersIndex = {
|
|
|
649
848
|
keyParts: () => [...PACKAGE_KEY_PARTS],
|
|
650
849
|
says: "every published dancer print at the names package's keys, its dancers, schools and years",
|
|
651
850
|
build(rel, out) {
|
|
652
|
-
const schema =
|
|
851
|
+
const schema = indexSchema2(ENCODER, PERSON);
|
|
653
852
|
out.run(schema.table);
|
|
654
853
|
out.run("CREATE TABLE print_dancer(person INTEGER NOT NULL, dancer_id INTEGER, rows INTEGER NOT NULL, year_lo INTEGER, year_hi INTEGER)");
|
|
655
854
|
out.run("CREATE TABLE dancer(dancer_id INTEGER PRIMARY KEY, display TEXT NOT NULL, names_printed TEXT NOT NULL, genders TEXT NOT NULL, appearances INTEGER NOT NULL, kind TEXT, birth_lo INTEGER, birth_hi INTEGER, birth_source TEXT NOT NULL, birth_conflict INTEGER NOT NULL, rows INTEGER NOT NULL, year_lo INTEGER, year_hi INTEGER)");
|
|
@@ -664,7 +863,7 @@ var dancersIndex = {
|
|
|
664
863
|
count(*) AS n, min(c.year) AS lo, max(c.year) AS hi
|
|
665
864
|
FROM results r JOIN competitions c ON c.file = r.file AND c.line = r.competition_line
|
|
666
865
|
GROUP BY 1, 2, 3, 4, 5 ORDER BY 1, 2, 3, 4, 5`).all();
|
|
667
|
-
const names =
|
|
866
|
+
const names = createIndex2(out, ENCODER, PERSON);
|
|
668
867
|
const personOf = new Map;
|
|
669
868
|
let next = 0;
|
|
670
869
|
const idOf = (p, o) => {
|
|
@@ -776,6 +975,8 @@ var NAME_WEIGHT = {
|
|
|
776
975
|
nn4: 3,
|
|
777
976
|
initial: 2,
|
|
778
977
|
middle: 1.5,
|
|
978
|
+
"given-middle": 1.25,
|
|
979
|
+
spanish: 1.25,
|
|
779
980
|
form: 1.25,
|
|
780
981
|
surname: 1,
|
|
781
982
|
like: 1
|
|
@@ -909,14 +1110,22 @@ class DancerResolver2 {
|
|
|
909
1110
|
unlinked: [],
|
|
910
1111
|
refused: asked.printsNoName() ? "the print names no person" : "the print reads as no person (a bare word is a surname: search it)"
|
|
911
1112
|
};
|
|
912
|
-
const names =
|
|
1113
|
+
const names = createIndex2(db, ENCODER, PERSON);
|
|
913
1114
|
const hits = new Map;
|
|
1115
|
+
const middleUsed = new Map;
|
|
914
1116
|
for (const { value, row } of names.rows({ surname_key: [asked.surnameKey()], nn4: [asked.nn4] }, ["print", "reading"])) {
|
|
915
1117
|
const c = ENCODER.decode(row);
|
|
916
1118
|
const level = nameLevel2(asked, c);
|
|
917
1119
|
if (level !== null)
|
|
918
1120
|
hits.set(value, level);
|
|
919
|
-
|
|
1121
|
+
else if (givenMiddleLevel(asked, c) !== null)
|
|
1122
|
+
middleUsed.set(value, "given-middle");
|
|
1123
|
+
}
|
|
1124
|
+
if (hits.size === 0)
|
|
1125
|
+
for (const [k, v] of middleUsed)
|
|
1126
|
+
hits.set(k, v);
|
|
1127
|
+
if (hits.size === 0 && q.school !== undefined)
|
|
1128
|
+
await this.spanishHits(db, asked, q.school, hits);
|
|
920
1129
|
const exact = await this.answer(db, q, hits);
|
|
921
1130
|
if (exact.arm !== "none")
|
|
922
1131
|
return exact;
|
|
@@ -962,12 +1171,29 @@ class DancerResolver2 {
|
|
|
962
1171
|
out.set(id, [...composed.via]);
|
|
963
1172
|
continue;
|
|
964
1173
|
}
|
|
965
|
-
const kin =
|
|
1174
|
+
const kin = nameKinship2(asked, c);
|
|
966
1175
|
if (kin.relation !== "different")
|
|
967
1176
|
out.set(id, [...kin.via]);
|
|
968
1177
|
}
|
|
969
1178
|
return out;
|
|
970
1179
|
}
|
|
1180
|
+
async spanishHits(db, asked, school, hits) {
|
|
1181
|
+
const s = await this.rel.schools.resolve(school);
|
|
1182
|
+
if (s.candidates.length === 0)
|
|
1183
|
+
return;
|
|
1184
|
+
if (!readsSpanishNames2(s.candidates))
|
|
1185
|
+
return;
|
|
1186
|
+
const ids = s.candidates.map((c) => c.school_id);
|
|
1187
|
+
const persons = db.query(`SELECT DISTINCT p.id AS id, p.print AS print, p.reading AS reading
|
|
1188
|
+
FROM dancer_school s JOIN print_dancer x ON x.dancer_id = s.dancer_id
|
|
1189
|
+
JOIN person p ON p.id = x.person
|
|
1190
|
+
WHERE s.school_id IN (${ids.map(() => "?").join(",")}) ORDER BY p.id`).all(...ids);
|
|
1191
|
+
for (const r of persons) {
|
|
1192
|
+
const c = ENCODER.decode(r);
|
|
1193
|
+
if (spanishLevel(asked, c) !== null)
|
|
1194
|
+
hits.set(r.id, "spanish");
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
971
1197
|
async search(q) {
|
|
972
1198
|
if (q.name !== undefined) {
|
|
973
1199
|
const a = await this.resolve({ ...q, name: q.name });
|
|
@@ -975,7 +1201,7 @@ class DancerResolver2 {
|
|
|
975
1201
|
}
|
|
976
1202
|
const db = await this.rel.indexDb("dancers");
|
|
977
1203
|
const hits = new Map;
|
|
978
|
-
const names =
|
|
1204
|
+
const names = createIndex2(db, ENCODER, PERSON);
|
|
979
1205
|
if (q.surname !== undefined) {
|
|
980
1206
|
const block = surnameBlock(foldNameKey(q.surname).toUpperCase());
|
|
981
1207
|
if (block !== null)
|
|
@@ -1399,7 +1625,7 @@ function otherGiven(db, dancerId, asked) {
|
|
|
1399
1625
|
continue;
|
|
1400
1626
|
if (nameLevel2(asked, p) !== null)
|
|
1401
1627
|
continue;
|
|
1402
|
-
if (
|
|
1628
|
+
if (nameKinship2(asked, p).relation !== "different")
|
|
1403
1629
|
continue;
|
|
1404
1630
|
return `printed "${print}", another given name than the asked one, and met it only through an initial`;
|
|
1405
1631
|
}
|
|
@@ -1508,6 +1734,7 @@ function contradictionFact(x, age, slack) {
|
|
|
1508
1734
|
}
|
|
1509
1735
|
|
|
1510
1736
|
import { Age as Age2 } from "@finbheara/domain/age";
|
|
1737
|
+
import { createCodeReader } from "@finbheara/domain/code";
|
|
1511
1738
|
import {
|
|
1512
1739
|
codePopulation,
|
|
1513
1740
|
compTitle as compTitle2,
|
|
@@ -1613,6 +1840,7 @@ function canonicalOf2(level, age) {
|
|
|
1613
1840
|
return null;
|
|
1614
1841
|
return `${level / 100}${String(n).padStart(2, "0")}${level === 600 ? "PC" : "OC"}`;
|
|
1615
1842
|
}
|
|
1843
|
+
var CODE_READER = createCodeReader({ standardized: ["quickfeis"] });
|
|
1616
1844
|
var entryOf = (c) => ({
|
|
1617
1845
|
title: c.title ?? "",
|
|
1618
1846
|
...c.age !== null ? { age: c.age } : {},
|
|
@@ -1825,6 +2053,14 @@ class CompResolver2 {
|
|
|
1825
2053
|
return answer("none", null, [], {
|
|
1826
2054
|
why: `the release holds no year of ${place.asked}'s series before ${place.year ?? "?"}`
|
|
1827
2055
|
});
|
|
2056
|
+
const newestYear = earlier[0];
|
|
2057
|
+
const newestIds = await this.idsOf(place.brand_id, newestYear);
|
|
2058
|
+
const newestComps = await this.compsOf(newestIds);
|
|
2059
|
+
const platform = newestComps[0]?.platform ?? null;
|
|
2060
|
+
if (platform === null || CODE_READER.scheme(platform) === "feis-specific") {
|
|
2061
|
+
const noChamps = newestComps.some((c) => c.kind === "championship") ? "" : `, and the ${newestYear} syllabus, read from results, lists no championship`;
|
|
2062
|
+
return byTitle(newestIds, { feis_ids: newestIds, year: newestYear }, `${platform ?? "the series' platform"} numbers each feis-year's competitions its own way: code ${q.code} is read only in the ${place.year ?? "asked"} syllabus, which the release does not hold${noChamps}`);
|
|
2063
|
+
}
|
|
1828
2064
|
for (const y of earlier) {
|
|
1829
2065
|
const ids = await this.idsOf(place.brand_id, y);
|
|
1830
2066
|
const hits = await this.compsOf(ids, q.code);
|
|
@@ -1865,8 +2101,8 @@ import { existsSync, mkdirSync, readdirSync, renameSync, rmSync, statSync } from
|
|
|
1865
2101
|
import { join } from "path";
|
|
1866
2102
|
|
|
1867
2103
|
import {
|
|
1868
|
-
createIndex as
|
|
1869
|
-
indexSchema as
|
|
2104
|
+
createIndex as createIndex3,
|
|
2105
|
+
indexSchema as indexSchema3,
|
|
1870
2106
|
roleEncoder
|
|
1871
2107
|
} from "@finbheara/domain/noun-index";
|
|
1872
2108
|
import { roleName } from "@finbheara/domain/person";
|
|
@@ -1900,10 +2136,10 @@ var staffIndex = {
|
|
|
1900
2136
|
keyParts: () => [...PACKAGE_KEY_PARTS],
|
|
1901
2137
|
says: "teachers and adjudicators by name and TD number: the schools they taught at, the register, the seats they sat",
|
|
1902
2138
|
build(rel, out) {
|
|
1903
|
-
const schema =
|
|
2139
|
+
const schema = indexSchema3(ENCODER2, WHO);
|
|
1904
2140
|
out.run(schema.table);
|
|
1905
2141
|
out.run(SCHEMA3);
|
|
1906
|
-
const who =
|
|
2142
|
+
const who = createIndex3(out, ENCODER2, WHO);
|
|
1907
2143
|
const putEntry = out.prepare("INSERT INTO entry VALUES (?, ?, ?, ?, ?)");
|
|
1908
2144
|
let next = 0;
|
|
1909
2145
|
const add = (role, print, clrg, judgeId, schools, source) => {
|
|
@@ -2002,7 +2238,7 @@ class StaffFinder2 {
|
|
|
2002
2238
|
if (!q.isPerson())
|
|
2003
2239
|
refused = "the print reads as no person";
|
|
2004
2240
|
else {
|
|
2005
|
-
const who =
|
|
2241
|
+
const who = createIndex3(db, ENCODER2, WHO);
|
|
2006
2242
|
for (const { value, row } of who.rows({ surname_key: [q.surnameKey()], nn4: [q.nn4] })) {
|
|
2007
2243
|
const p = ENCODER2.decode(row);
|
|
2008
2244
|
if (p.role !== role)
|
|
@@ -2099,182 +2335,6 @@ class StaffFinder2 {
|
|
|
2099
2335
|
}
|
|
2100
2336
|
}
|
|
2101
2337
|
|
|
2102
|
-
import { createIndex as createIndex3, indexSchema as indexSchema3 } from "@finbheara/domain/noun-index";
|
|
2103
|
-
import {
|
|
2104
|
-
DEFAULT_SCHOOL_NAME_READER,
|
|
2105
|
-
schoolEncoder
|
|
2106
|
-
} from "@finbheara/domain/school";
|
|
2107
|
-
var GENERIC_SCHOOL_READER = {
|
|
2108
|
-
id: "generic",
|
|
2109
|
-
reader: DEFAULT_SCHOOL_NAME_READER
|
|
2110
|
-
};
|
|
2111
|
-
var encoderOf = (r) => schoolEncoder({ reader: r.reader });
|
|
2112
|
-
var TABLE = "school_name";
|
|
2113
|
-
var schoolsIndex = {
|
|
2114
|
-
name: "schools",
|
|
2115
|
-
version: "3",
|
|
2116
|
-
inputs: ["results", "school-registry.jsonl", "school-redirects.jsonl"],
|
|
2117
|
-
says: "every published school print and its ids, read at the school reader's slots",
|
|
2118
|
-
keyParts: (rel) => [`reader=${rel.schoolReader().id}`],
|
|
2119
|
-
build(rel, out) {
|
|
2120
|
-
const choice = rel.schoolReader();
|
|
2121
|
-
const encoder = encoderOf(choice);
|
|
2122
|
-
out.run("CREATE TABLE print_id(print TEXT NOT NULL, school_id TEXT NOT NULL, rows INTEGER NOT NULL, year_lo INTEGER, year_hi INTEGER, PRIMARY KEY(print, school_id)) WITHOUT ROWID");
|
|
2123
|
-
out.run("CREATE TABLE registry(school_id TEXT PRIMARY KEY, display TEXT NOT NULL, regions TEXT NOT NULL, places TEXT NOT NULL)");
|
|
2124
|
-
out.run("CREATE TABLE redirect(old_id TEXT PRIMARY KEY, new_id TEXT NOT NULL, kind TEXT NOT NULL)");
|
|
2125
|
-
const schema = indexSchema3(encoder, { table: TABLE });
|
|
2126
|
-
out.run(schema.table);
|
|
2127
|
-
const src = rel.db("results");
|
|
2128
|
-
const lined = src.query("PRAGMA table_info(results)").all().some((c) => c.name === "competition_line");
|
|
2129
|
-
const pairs = src.query(lined ? `SELECT trim(r.school_printed) AS p, r.school_id AS s, count(*) AS n,
|
|
2130
|
-
min(c.year) AS lo, max(c.year) AS hi
|
|
2131
|
-
FROM results r LEFT JOIN competitions c ON c.file = r.file AND c.line = r.competition_line
|
|
2132
|
-
WHERE r.school_id IS NOT NULL GROUP BY 1, 2 ORDER BY 1, 2` : `SELECT trim(school_printed) AS p, school_id AS s, count(*) AS n, NULL AS lo, NULL AS hi
|
|
2133
|
-
FROM results WHERE school_id IS NOT NULL GROUP BY 1, 2 ORDER BY 1, 2`).all();
|
|
2134
|
-
const putPair = out.prepare("INSERT INTO print_id VALUES (?, ?, ?, ?, ?)");
|
|
2135
|
-
for (const r of pairs)
|
|
2136
|
-
putPair.run(r.p, r.s, r.n, r.lo, r.hi);
|
|
2137
|
-
out.run("CREATE INDEX print_id_school ON print_id(school_id)");
|
|
2138
|
-
const names = createIndex3(out, encoder, {
|
|
2139
|
-
table: TABLE
|
|
2140
|
-
});
|
|
2141
|
-
let last = null;
|
|
2142
|
-
for (const r of pairs) {
|
|
2143
|
-
if (r.p === last)
|
|
2144
|
-
continue;
|
|
2145
|
-
last = r.p;
|
|
2146
|
-
names.add(choice.reader.schoolName(r.p), r.p);
|
|
2147
|
-
}
|
|
2148
|
-
for (const s of schema.indexes)
|
|
2149
|
-
out.run(s);
|
|
2150
|
-
const putReg = out.prepare("INSERT OR REPLACE INTO registry VALUES (?, ?, ?, ?)");
|
|
2151
|
-
for (const r of readJsonl(rel.path("school-registry.jsonl")))
|
|
2152
|
-
putReg.run(r.school_id, r.display, JSON.stringify([...new Set(r.regions.map((x) => x.region))]), JSON.stringify([...new Set(r.locations.map((x) => x.place))]));
|
|
2153
|
-
const putRed = out.prepare("INSERT OR REPLACE INTO redirect VALUES (?, ?, ?)");
|
|
2154
|
-
for (const r of readJsonl(rel.path("school-redirects.jsonl")))
|
|
2155
|
-
putRed.run(r.old_id, r.new_id, r.kind);
|
|
2156
|
-
}
|
|
2157
|
-
};
|
|
2158
|
-
|
|
2159
|
-
class SchoolResolver2 {
|
|
2160
|
-
rel;
|
|
2161
|
-
constructor(rel) {
|
|
2162
|
-
this.rel = rel;
|
|
2163
|
-
}
|
|
2164
|
-
async resolve(asked, q = {}) {
|
|
2165
|
-
const db = await this.rel.indexDb("schools");
|
|
2166
|
-
const reg = db.query("SELECT display, regions, places FROM registry WHERE school_id = ?");
|
|
2167
|
-
const candidate = (id, by, rows, prints) => {
|
|
2168
|
-
const r = reg.get(id);
|
|
2169
|
-
return {
|
|
2170
|
-
school_id: id,
|
|
2171
|
-
display: r?.display ?? null,
|
|
2172
|
-
rows,
|
|
2173
|
-
by,
|
|
2174
|
-
prints,
|
|
2175
|
-
regions: r === null ? [] : JSON.parse(r.regions),
|
|
2176
|
-
places: r === null ? [] : JSON.parse(r.places)
|
|
2177
|
-
};
|
|
2178
|
-
};
|
|
2179
|
-
const answer = (candidates, extra = {}) => {
|
|
2180
|
-
let cs = candidates.sort((a, b) => b.rows - a.rows || (a.school_id < b.school_id ? -1 : 1));
|
|
2181
|
-
let year;
|
|
2182
|
-
if (q.year !== undefined && cs.length > 1 && cs.every((c) => c.years !== undefined)) {
|
|
2183
|
-
const y = q.year;
|
|
2184
|
-
const span = (c) => c.years;
|
|
2185
|
-
let kept = cs.filter((c) => {
|
|
2186
|
-
const { lo, hi } = span(c);
|
|
2187
|
-
return lo !== null && hi !== null && lo <= y && y <= hi;
|
|
2188
|
-
});
|
|
2189
|
-
if (kept.length === 0) {
|
|
2190
|
-
const before = cs.filter((c) => span(c).hi !== null && span(c).hi < y);
|
|
2191
|
-
const last = Math.max(...before.map((c) => span(c).hi));
|
|
2192
|
-
kept = before.filter((c) => span(c).hi === last);
|
|
2193
|
-
}
|
|
2194
|
-
year = { asked: y, narrowed: kept.length > 0 && kept.length < cs.length };
|
|
2195
|
-
if (kept.length > 0)
|
|
2196
|
-
cs = kept;
|
|
2197
|
-
}
|
|
2198
|
-
let region;
|
|
2199
|
-
if (q.region !== undefined) {
|
|
2200
|
-
const kept = cs.filter((c) => c.regions.length === 0 || c.regions.includes(q.region));
|
|
2201
|
-
region = { asked: q.region, narrowed: kept.length > 0 && kept.length < cs.length };
|
|
2202
|
-
if (kept.length > 0)
|
|
2203
|
-
cs = kept;
|
|
2204
|
-
}
|
|
2205
|
-
return {
|
|
2206
|
-
tag: this.rel.tag,
|
|
2207
|
-
asked,
|
|
2208
|
-
arm: cs.length === 0 ? "none" : cs.length === 1 ? "unique" : "ambiguous",
|
|
2209
|
-
candidates: cs,
|
|
2210
|
-
...region !== undefined ? { region } : {},
|
|
2211
|
-
...year !== undefined ? { year } : {},
|
|
2212
|
-
...extra
|
|
2213
|
-
};
|
|
2214
|
-
};
|
|
2215
|
-
const byId = (id, by) => {
|
|
2216
|
-
const rs = db.query("SELECT print, rows FROM print_id WHERE school_id = ? ORDER BY print").all(id);
|
|
2217
|
-
return candidate(id, by, rs.reduce((n, r) => n + r.rows, 0), rs.map((r) => r.print));
|
|
2218
|
-
};
|
|
2219
|
-
const a = asked.trim();
|
|
2220
|
-
if (reg.get(a) !== null)
|
|
2221
|
-
return answer([byId(a, "id")]);
|
|
2222
|
-
let live = a;
|
|
2223
|
-
const seen = new Set;
|
|
2224
|
-
for (;; ) {
|
|
2225
|
-
const r = db.query("SELECT new_id FROM redirect WHERE old_id = ?").get(live);
|
|
2226
|
-
if (r === null || seen.has(r.new_id))
|
|
2227
|
-
break;
|
|
2228
|
-
seen.add(live);
|
|
2229
|
-
live = r.new_id;
|
|
2230
|
-
}
|
|
2231
|
-
if (live !== a)
|
|
2232
|
-
return answer([byId(live, "redirect")], { redirected: { from: a, to: live } });
|
|
2233
|
-
const byPrints = (prints, by) => {
|
|
2234
|
-
const ids = new Map;
|
|
2235
|
-
const q2 = db.query("SELECT school_id, rows, year_lo AS lo, year_hi AS hi FROM print_id WHERE print = ?");
|
|
2236
|
-
for (const p of prints)
|
|
2237
|
-
for (const r of q2.all(p)) {
|
|
2238
|
-
const e = ids.get(r.school_id) ?? {
|
|
2239
|
-
rows: 0,
|
|
2240
|
-
prints: new Set,
|
|
2241
|
-
lo: null,
|
|
2242
|
-
hi: null
|
|
2243
|
-
};
|
|
2244
|
-
e.rows += r.rows;
|
|
2245
|
-
e.prints.add(p);
|
|
2246
|
-
if (r.lo !== null && (e.lo === null || r.lo < e.lo))
|
|
2247
|
-
e.lo = r.lo;
|
|
2248
|
-
if (r.hi !== null && (e.hi === null || r.hi > e.hi))
|
|
2249
|
-
e.hi = r.hi;
|
|
2250
|
-
ids.set(r.school_id, e);
|
|
2251
|
-
}
|
|
2252
|
-
return [...ids].map(([id, e]) => ({
|
|
2253
|
-
...candidate(id, by, e.rows, [...e.prints].sort()),
|
|
2254
|
-
years: { lo: e.lo, hi: e.hi }
|
|
2255
|
-
}));
|
|
2256
|
-
};
|
|
2257
|
-
const exact = byPrints([a], "print");
|
|
2258
|
-
if (exact.length > 0)
|
|
2259
|
-
return answer(exact);
|
|
2260
|
-
const choice = this.rel.schoolReader();
|
|
2261
|
-
const read = choice.reader.schoolName(a);
|
|
2262
|
-
if (!read.isSchool())
|
|
2263
|
-
return answer([], {
|
|
2264
|
-
refused: read.refusal?.reason ?? (read.isEmpty() ? "empty" : "not a school")
|
|
2265
|
-
});
|
|
2266
|
-
const names = createIndex3(db, encoderOf(choice), {
|
|
2267
|
-
table: TABLE
|
|
2268
|
-
});
|
|
2269
|
-
for (const level of ["sn3", "realWords"]) {
|
|
2270
|
-
const prints = names.get(read, level);
|
|
2271
|
-
if (prints.length > 0)
|
|
2272
|
-
return answer(byPrints(prints, level));
|
|
2273
|
-
}
|
|
2274
|
-
return answer([]);
|
|
2275
|
-
}
|
|
2276
|
-
}
|
|
2277
|
-
|
|
2278
2338
|
import { parquetMetadata, parquetReadObjects, parquetSchema } from "hyparquet";
|
|
2279
2339
|
var COMPRESSORS = {
|
|
2280
2340
|
ZSTD: (input) => new Uint8Array(Bun.zstdDecompressSync(input))
|
|
@@ -3723,4 +3783,4 @@ function releases2(opts = {}) {
|
|
|
3723
3783
|
return new ReleaseManager2(opts);
|
|
3724
3784
|
}
|
|
3725
3785
|
|
|
3726
|
-
export { DATABASES2, planAsset2, sha256File2, unzstdTo2, NAME_LEVELS2, nameLevel2, NO_CALENDAR2, FeisFinder2, entryRank2, FEIS_LOCAL_ID_FLOOR2, ResultFinder2, MajorsFinder2, initialsOnly2, nameOrderOf, DancerResolver2, readPopulation2, canonicalOf2, CompResolver2, StaffFinder2,
|
|
3786
|
+
export { DATABASES2, planAsset2, sha256File2, unzstdTo2, NAME_LEVELS2, nameLevel2, NO_CALENDAR2, FeisFinder2, entryRank2, FEIS_LOCAL_ID_FLOOR2, ResultFinder2, MajorsFinder2, readsSpanishNames2, SchoolResolver2, initialsOnly2, nameOrderOf, DancerResolver2, readPopulation2, canonicalOf2, CompResolver2, StaffFinder2, 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-9r4rw6xq.js";
|
|
8
8
|
import"./chunks/index-hne1wadw.js";
|
|
9
9
|
import"./chunks/index-hghdy980.js";
|
|
10
10
|
|
|
@@ -81,7 +81,8 @@ var USAGE = `usage: idq <verb> [--cache <dir>] [--repo <owner/name>] [--json]
|
|
|
81
81
|
the register's and the panels' people: the same answer
|
|
82
82
|
comp [--release <spec>] <feis> <code> [--year <y>] [--title <t>]
|
|
83
83
|
a feis's own comp code to the comp it names, through that
|
|
84
|
-
feis's syllabus (
|
|
84
|
+
feis's syllabus (the prior year's only where the platform
|
|
85
|
+
numbers every feis alike; elsewhere the title)
|
|
85
86
|
syllabus [--release <spec>] <feis> [year]
|
|
86
87
|
one feis-year's comps, in printed order
|
|
87
88
|
syllabus [--release <spec>] --for <series> [year]
|
package/dist/index.js
CHANGED
|
@@ -12,13 +12,14 @@ import {
|
|
|
12
12
|
FEIS_LOCAL_ID_FLOOR2,
|
|
13
13
|
ResultFinder2,
|
|
14
14
|
MajorsFinder2,
|
|
15
|
+
readsSpanishNames2,
|
|
16
|
+
SchoolResolver2,
|
|
15
17
|
initialsOnly2,
|
|
16
18
|
DancerResolver2,
|
|
17
19
|
readPopulation2,
|
|
18
20
|
canonicalOf2,
|
|
19
21
|
CompResolver2,
|
|
20
22
|
StaffFinder2,
|
|
21
|
-
SchoolResolver2,
|
|
22
23
|
TeamFinder2,
|
|
23
24
|
EventFinder2,
|
|
24
25
|
defaultBuilders2,
|
|
@@ -46,7 +47,7 @@ import {
|
|
|
46
47
|
openCached2,
|
|
47
48
|
ReleaseManager2,
|
|
48
49
|
releases2
|
|
49
|
-
} from "./chunks/index-
|
|
50
|
+
} from "./chunks/index-9r4rw6xq.js";
|
|
50
51
|
import {
|
|
51
52
|
cacheRoot2,
|
|
52
53
|
repoOf2
|
|
@@ -108,6 +109,7 @@ export {
|
|
|
108
109
|
planAsset2 as planAsset,
|
|
109
110
|
readPin2 as readPin,
|
|
110
111
|
readPopulation2 as readPopulation,
|
|
112
|
+
readsSpanishNames2 as readsSpanishNames,
|
|
111
113
|
releases2 as releases,
|
|
112
114
|
renderArchiveTag2 as renderArchiveTag,
|
|
113
115
|
repoOf2 as repoOf,
|
package/dist/types/cli.d.ts
CHANGED
|
@@ -1,7 +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] [--oireachtas <region>[:<year>]] [--rows]\n the dancers a name reaches, each with its evidence\n (name level, age, school, population, region) and the arm;\n --oireachtas is the regional the roster is for, its region in\n the release's spelling (SRO, MAO), its year the --as-of year\n where none is given; 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 (
|
|
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] [--oireachtas <region>[:<year>]] [--rows]\n the dancers a name reaches, each with its evidence\n (name level, age, school, population, region) and the arm;\n --oireachtas is the regional the roster is for, its region in\n the release's spelling (SRO, MAO), its year the --as-of year\n where none is given; 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 (the prior year's only where the platform\n numbers every feis alike; elsewhere the title)\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 [--oireachtas <region>[:<year>]]\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?, oireachtas?}, a registration: {name, school?,\n codes[], feis, year?, population?, oireachtas?})\n\n <spec>: pinned (the default) | latest | a cut (42, 42.1) | a tag (archive-YYYY.MM.DD-N)";
|
|
5
5
|
export interface Parsed {
|
|
6
6
|
positional: string[];
|
|
7
7
|
flags: Map<string, string>;
|
package/dist/types/comps.d.ts
CHANGED
|
@@ -121,6 +121,7 @@ interface CompRow {
|
|
|
121
121
|
}
|
|
122
122
|
export declare function compOf(r: CompRow, codes?: readonly string[]): Comp;
|
|
123
123
|
export declare function canonicalOf(level: number | null, age: string | null): string | null;
|
|
124
|
+
export declare const CODE_READER: import("@finbheara/domain/code").CodeReader;
|
|
124
125
|
export declare class CompResolver {
|
|
125
126
|
private readonly rel;
|
|
126
127
|
constructor(rel: Release);
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { type PersonName, type TransitiveLevel } from "@finbheara/names/normalize";
|
|
2
|
-
export type NameLevel = TransitiveLevel | "initial" | "middle" | "form" | "surname" | "like";
|
|
2
|
+
export type NameLevel = TransitiveLevel | "initial" | "middle" | "given-middle" | "spanish" | "form" | "surname" | "like";
|
|
3
3
|
export declare const NAME_LEVELS: readonly NameLevel[];
|
|
4
4
|
export declare const finer: (a: NameLevel, b: NameLevel) => NameLevel;
|
|
5
5
|
export declare function nameLevel(q: PersonName, c: PersonName): NameLevel | null;
|
|
6
|
+
export declare function givenMiddleLevel(q: PersonName, c: PersonName): "given-middle" | null;
|
|
7
|
+
export declare function spanishLevel(q: PersonName, c: PersonName): "spanish" | null;
|
package/dist/types/dancers.d.ts
CHANGED
|
@@ -222,6 +222,7 @@ export declare class DancerResolver {
|
|
|
222
222
|
}>;
|
|
223
223
|
resolve(q: DancerQuery): Promise<DancerAnswer>;
|
|
224
224
|
private formsOf;
|
|
225
|
+
private spanishHits;
|
|
225
226
|
search(q: DancerSearchQuery): Promise<DancerAnswer>;
|
|
226
227
|
private capped;
|
|
227
228
|
get(dancerId: number): Promise<DancerRecord | null>;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -13,7 +13,7 @@ export { type Remote, type RemoteAsset, fallbackRemote, ghRemote, httpsRemote, s
|
|
|
13
13
|
export { type OpenOptions, Release, openCached, openRelease, resolveTag, } from "./release.js";
|
|
14
14
|
export { type MajorCompetition, type MajorEvent, MajorsFinder, type ResultAnswer, ResultFinder, type ResultQuery, type ResultRow, } from "./results.js";
|
|
15
15
|
export { type DancerAnswerLike, type DancerQueryLike, type DancerResolverLike, type DancerUnavailable, type RegistrationRow, type ResolvedDancer, RegistrationResolver, type ResolvedRegistration, dancerResolverOf, youngest, } from "./registrations.js";
|
|
16
|
-
export { type SchoolAnswer, type SchoolCandidate, type SchoolQuery, SchoolResolver, type SchoolRung, } from "./schools.js";
|
|
16
|
+
export { type SchoolAnswer, type SchoolCandidate, type SchoolQuery, SchoolResolver, type SchoolRung, readsSpanishNames, type SpanishNames, } from "./schools.js";
|
|
17
17
|
export { type Capability, FEATURES, type Feature, type SchemaProbe, capabilityOf, columnsOf, needsRelease, } from "./schema.js";
|
|
18
18
|
export { type EntryRow, type StreamQuery, type StreamRow, type StreamScope, entryRank, } from "./stream.js";
|
|
19
19
|
export { EventFinder, type EventYear, type EventYearQuery, type ResultRoster, type RosterMember, type RosterTeam, TeamFinder, type TeamResult, } from "./teams.js";
|
package/dist/types/schools.d.ts
CHANGED
|
@@ -14,6 +14,11 @@ export interface SchoolCandidate {
|
|
|
14
14
|
lo: number | null;
|
|
15
15
|
hi: number | null;
|
|
16
16
|
};
|
|
17
|
+
spanishNames?: SpanishNames;
|
|
18
|
+
}
|
|
19
|
+
export interface SpanishNames {
|
|
20
|
+
file: boolean;
|
|
21
|
+
prints: string[];
|
|
17
22
|
}
|
|
18
23
|
export interface SchoolAnswer {
|
|
19
24
|
tag: string;
|
|
@@ -42,6 +47,7 @@ export interface SchoolReaderChoice {
|
|
|
42
47
|
id: string;
|
|
43
48
|
reader: SchoolNameParser;
|
|
44
49
|
}
|
|
50
|
+
export declare function readsSpanishNames(candidates: readonly SchoolCandidate[]): boolean;
|
|
45
51
|
export declare const GENERIC_SCHOOL_READER: SchoolReaderChoice;
|
|
46
52
|
export declare const schoolsIndex: IndexBuilder;
|
|
47
53
|
export declare class SchoolResolver {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@finbheara/archive-client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.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",
|
|
@@ -44,8 +44,8 @@
|
|
|
44
44
|
"prepublishOnly": "bun scripts/build.ts && bun ../../tools/checks/archive-client-tarball.ts"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@finbheara/domain": "0.
|
|
48
|
-
"@finbheara/names": "0.
|
|
47
|
+
"@finbheara/domain": "0.53.0",
|
|
48
|
+
"@finbheara/names": "0.26.0",
|
|
49
49
|
"hyparquet": "1.31.2"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|