@finbheara/archive-client 0.24.0 → 0.26.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 +116 -3
- package/dist/chunks/{index-vsk6837c.js → index-8mwx3n9j.js} +724 -20
- package/dist/cli.js +304 -2
- package/dist/index.js +13 -1
- package/dist/types/cli.d.ts +2 -0
- package/dist/types/feises.d.ts +9 -0
- package/dist/types/index.d.ts +4 -1
- package/dist/types/people.d.ts +12 -0
- package/dist/types/release.d.ts +6 -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/dist/types/upcoming.d.ts +138 -0
- package/package.json +1 -1
|
@@ -201,6 +201,7 @@ var feisesIndex = {
|
|
|
201
201
|
}
|
|
202
202
|
};
|
|
203
203
|
var NO_CALENDAR2 = "the release holds a feis-year once its results are captured and carries no calendar of scheduled feiseanna";
|
|
204
|
+
var NO_UPCOMING2 = "the release's feis-index lists no occurrence of the series dated on or after the cut's day";
|
|
204
205
|
var globToLike = (g) => g.replace(/[\\%_]/g, (c) => `\\${c}`).replace(/\*/g, "%").replace(/\?/g, "_");
|
|
205
206
|
|
|
206
207
|
class FeisFinder2 {
|
|
@@ -296,6 +297,29 @@ class FeisFinder2 {
|
|
|
296
297
|
instances
|
|
297
298
|
};
|
|
298
299
|
}
|
|
300
|
+
async nextOf(brand) {
|
|
301
|
+
if ((await this.rel.capability("upcoming.feises")).state === "missing")
|
|
302
|
+
return { next: null, next_why: NO_CALENDAR2 };
|
|
303
|
+
const db = await this.rel.indexDb("feises");
|
|
304
|
+
const retired = db.query("SELECT old_id FROM redirect WHERE new_id = ? AND kind = 'brand' ORDER BY old_id").all(brand).map((r) => r.old_id);
|
|
305
|
+
let best = null;
|
|
306
|
+
for (const id of [brand, ...retired])
|
|
307
|
+
for (const o of (await this.rel.upcoming.feises({ state: "upcoming", brand: id })).feises) {
|
|
308
|
+
if (best !== null && (best.date < o.date_lo || best.date === o.date_lo && best.occurrence_id <= o.occurrence_id))
|
|
309
|
+
continue;
|
|
310
|
+
best = {
|
|
311
|
+
feis_id: o.hosts.find((h) => h.feis_id !== null)?.feis_id ?? null,
|
|
312
|
+
date: o.date_lo,
|
|
313
|
+
date_hi: o.date_hi,
|
|
314
|
+
occurrence_id: o.occurrence_id,
|
|
315
|
+
name_printed: o.name_printed,
|
|
316
|
+
hosts: o.hosts,
|
|
317
|
+
captured_id: o.captured_id,
|
|
318
|
+
series_basis: o.series_basis
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
return best === null ? { next: null, next_why: NO_UPCOMING2 } : { next: best };
|
|
322
|
+
}
|
|
299
323
|
async series(q) {
|
|
300
324
|
const asked = q.trim();
|
|
301
325
|
const answer = async (brands, via, more = {}) => {
|
|
@@ -314,8 +338,7 @@ class FeisFinder2 {
|
|
|
314
338
|
host: u?.host ?? null,
|
|
315
339
|
years: u?.years ?? [],
|
|
316
340
|
instances: u?.instances ?? [],
|
|
317
|
-
next: null,
|
|
318
|
-
...u !== null ? { next_why: NO_CALENDAR2 } : {},
|
|
341
|
+
...u !== null ? await this.nextOf(u.series_id) : { next: null },
|
|
319
342
|
candidates,
|
|
320
343
|
...arm === "ambiguous" ? { why: `${candidates.length} series answer "${asked}": ${brands.join(", ")}` } : {},
|
|
321
344
|
...more
|
|
@@ -774,6 +797,96 @@ import {
|
|
|
774
797
|
DEFAULT_SCHOOL_NAME_READER,
|
|
775
798
|
schoolEncoder
|
|
776
799
|
} from "@finbheara/domain/school";
|
|
800
|
+
|
|
801
|
+
var str = (v) => typeof v === "string" && v !== "" ? v : null;
|
|
802
|
+
var num = (v) => typeof v === "number" ? v : null;
|
|
803
|
+
var uniq = (xs) => [...new Set(xs)];
|
|
804
|
+
async function registrySchools(rel) {
|
|
805
|
+
await rel.require("schools.registry");
|
|
806
|
+
await rel.fetch("school-registry.jsonl");
|
|
807
|
+
const schools = readJsonl(rel.path("school-registry.jsonl")).map((r) => ({
|
|
808
|
+
school_id: r.school_id,
|
|
809
|
+
display: r.display,
|
|
810
|
+
regions: uniq((r.regions ?? []).map((x) => x.region)),
|
|
811
|
+
places: uniq((r.locations ?? []).map((x) => x.place))
|
|
812
|
+
})).sort((a, b) => a.school_id < b.school_id ? -1 : a.school_id > b.school_id ? 1 : 0);
|
|
813
|
+
return { tag: rel.tag, schools };
|
|
814
|
+
}
|
|
815
|
+
async function schoolPrints(rel, q) {
|
|
816
|
+
await rel.fetch("results");
|
|
817
|
+
await rel.require("schools.prints");
|
|
818
|
+
const where = ["r.school_id IS NOT NULL"];
|
|
819
|
+
const args = [];
|
|
820
|
+
if (q.event !== undefined) {
|
|
821
|
+
where.push("c.event = ? COLLATE NOCASE");
|
|
822
|
+
args.push(q.event);
|
|
823
|
+
}
|
|
824
|
+
if (q.year !== undefined) {
|
|
825
|
+
where.push("c.year = ?");
|
|
826
|
+
args.push(q.year);
|
|
827
|
+
}
|
|
828
|
+
const prints = rel.db("results").query(`SELECT c.event AS event, c.year AS year, trim(r.school_printed) AS print,
|
|
829
|
+
r.school_id AS school_id, count(*) AS rows
|
|
830
|
+
FROM competitions c JOIN results r ON r.file = c.file AND r.competition_line = c.line
|
|
831
|
+
WHERE ${where.join(" AND ")} GROUP BY 1, 2, 3, 4 ORDER BY 2, 1, 3, 4`).all(...args);
|
|
832
|
+
return { tag: rel.tag, asked: q, prints };
|
|
833
|
+
}
|
|
834
|
+
async function schoolRedirects(rel) {
|
|
835
|
+
await rel.require("schools.redirects");
|
|
836
|
+
await rel.fetch("school-redirects.jsonl");
|
|
837
|
+
const redirects = readJsonl(rel.path("school-redirects.jsonl")).map((r) => ({
|
|
838
|
+
old_id: String(r.old_id),
|
|
839
|
+
new_id: String(r.new_id),
|
|
840
|
+
kind: String(r.kind),
|
|
841
|
+
since: num(r.since)
|
|
842
|
+
}));
|
|
843
|
+
return { tag: rel.tag, redirects };
|
|
844
|
+
}
|
|
845
|
+
async function schoolLineage(rel) {
|
|
846
|
+
await rel.require("schools.lineage");
|
|
847
|
+
await rel.fetch("school-lineage.jsonl");
|
|
848
|
+
const edges = readJsonl(rel.path("school-lineage.jsonl")).map((r) => ({
|
|
849
|
+
id: String(r.id),
|
|
850
|
+
direction: String(r.direction),
|
|
851
|
+
other: String(r.other),
|
|
852
|
+
shape: String(r.shape),
|
|
853
|
+
year: num(r.year),
|
|
854
|
+
provisional: r.provisional === true,
|
|
855
|
+
decision: str(r.decision),
|
|
856
|
+
confidence: num(r.confidence)
|
|
857
|
+
}));
|
|
858
|
+
return { tag: rel.tag, edges };
|
|
859
|
+
}
|
|
860
|
+
async function observedAssociations(rel, q) {
|
|
861
|
+
await rel.require("schools.associations");
|
|
862
|
+
await rel.fetch("observed-associations.jsonl");
|
|
863
|
+
const associations = [];
|
|
864
|
+
for (const r of readJsonl(rel.path("observed-associations.jsonl"))) {
|
|
865
|
+
const school_id = str(r.schoolId);
|
|
866
|
+
if (q.school_id !== undefined && school_id !== q.school_id)
|
|
867
|
+
continue;
|
|
868
|
+
associations.push({
|
|
869
|
+
at: String(r.at),
|
|
870
|
+
seq: num(r.seq) ?? 0,
|
|
871
|
+
date: str(r.date),
|
|
872
|
+
person: str(r.person),
|
|
873
|
+
person_printed: typeof r.personPrinted === "string" ? r.personPrinted : "",
|
|
874
|
+
reading: str(r.reading),
|
|
875
|
+
person_type: str(r.personType),
|
|
876
|
+
credentials: str(r.credentials),
|
|
877
|
+
caption: str(r.caption),
|
|
878
|
+
school_printed: str(r.school),
|
|
879
|
+
school_id,
|
|
880
|
+
association_type: str(r.associationType),
|
|
881
|
+
src_type: str(r.srcType),
|
|
882
|
+
src: str(r.src),
|
|
883
|
+
candidate_school_id: str(r.candidateSchoolId),
|
|
884
|
+
candidate_rung: str(r.candidateRung)
|
|
885
|
+
});
|
|
886
|
+
}
|
|
887
|
+
return { tag: rel.tag, asked: q, associations };
|
|
888
|
+
}
|
|
889
|
+
|
|
777
890
|
function readsSpanishNames2(candidates) {
|
|
778
891
|
return candidates.some((c) => c.spanishNames !== undefined && (c.spanishNames.file || c.prints.some((p) => c.spanishNames?.prints.includes(p.trim()))));
|
|
779
892
|
}
|
|
@@ -846,6 +959,21 @@ class SchoolResolver2 {
|
|
|
846
959
|
this.graph ??= releaseSchoolGraph2(this.rel);
|
|
847
960
|
return { tag: this.rel.tag, ...(await this.graph).line(a.trim(), q) };
|
|
848
961
|
}
|
|
962
|
+
list() {
|
|
963
|
+
return registrySchools(this.rel);
|
|
964
|
+
}
|
|
965
|
+
prints(q = {}) {
|
|
966
|
+
return schoolPrints(this.rel, q);
|
|
967
|
+
}
|
|
968
|
+
redirects() {
|
|
969
|
+
return schoolRedirects(this.rel);
|
|
970
|
+
}
|
|
971
|
+
lineage() {
|
|
972
|
+
return schoolLineage(this.rel);
|
|
973
|
+
}
|
|
974
|
+
associations(q = {}) {
|
|
975
|
+
return observedAssociations(this.rel, q);
|
|
976
|
+
}
|
|
849
977
|
async resolve(asked, q = {}) {
|
|
850
978
|
const db = await this.rel.indexDb("schools");
|
|
851
979
|
const reg = db.query("SELECT display, regions, places, spanish FROM registry WHERE school_id = ?");
|
|
@@ -2246,6 +2374,218 @@ import {
|
|
|
2246
2374
|
roleEncoder
|
|
2247
2375
|
} from "@finbheara/domain/noun-index";
|
|
2248
2376
|
import { roleName } from "@finbheara/domain/person";
|
|
2377
|
+
|
|
2378
|
+
var TAB_COLUMNS = `address, slug AS competition, card, line, round, true_round, seat_index,
|
|
2379
|
+
section, panel_size, column_order, drop_rule, judge_name, judge_name_printed, judge_clrg,
|
|
2380
|
+
judge_id, judge_unmatched, mark, mark_printed, place, place_printed, tie, points, points_printed`;
|
|
2381
|
+
var TAB_NEEDS = [
|
|
2382
|
+
"address",
|
|
2383
|
+
"slug",
|
|
2384
|
+
"card",
|
|
2385
|
+
"line",
|
|
2386
|
+
"round",
|
|
2387
|
+
"true_round",
|
|
2388
|
+
"seat_index",
|
|
2389
|
+
"section",
|
|
2390
|
+
"panel_size",
|
|
2391
|
+
"column_order",
|
|
2392
|
+
"drop_rule",
|
|
2393
|
+
"judge_name",
|
|
2394
|
+
"judge_name_printed",
|
|
2395
|
+
"judge_clrg",
|
|
2396
|
+
"judge_id",
|
|
2397
|
+
"judge_unmatched",
|
|
2398
|
+
"mark",
|
|
2399
|
+
"mark_printed",
|
|
2400
|
+
"place",
|
|
2401
|
+
"place_printed",
|
|
2402
|
+
"tie",
|
|
2403
|
+
"points",
|
|
2404
|
+
"points_printed"
|
|
2405
|
+
].map((c) => `results:tabs.${c}`);
|
|
2406
|
+
var NO_SHEET = { event: null, year: null, tier: null };
|
|
2407
|
+
var cardRange = (competition) => [`${competition}#`, `${competition}$`];
|
|
2408
|
+
|
|
2409
|
+
class TabFinder2 {
|
|
2410
|
+
rel;
|
|
2411
|
+
constructor(rel) {
|
|
2412
|
+
this.rel = rel;
|
|
2413
|
+
}
|
|
2414
|
+
async db() {
|
|
2415
|
+
await this.rel.fetch("results");
|
|
2416
|
+
await this.rel.require("tabs");
|
|
2417
|
+
return this.rel.db("results");
|
|
2418
|
+
}
|
|
2419
|
+
async sheets(db, only) {
|
|
2420
|
+
const out = new Map;
|
|
2421
|
+
const tiers = new Map;
|
|
2422
|
+
const rows = [];
|
|
2423
|
+
if (only === null)
|
|
2424
|
+
rows.push(...db.query("SELECT competition, event, year, tier FROM competitions WHERE competition IN (SELECT DISTINCT slug FROM tabs)").all());
|
|
2425
|
+
else
|
|
2426
|
+
for (let i = 0;i < only.length; i += 500) {
|
|
2427
|
+
const part = only.slice(i, i + 500);
|
|
2428
|
+
rows.push(...db.query(`SELECT competition, event, year, tier FROM competitions WHERE competition IN (${part.map(() => "?").join(", ")})`).all(...part));
|
|
2429
|
+
}
|
|
2430
|
+
for (const r of rows) {
|
|
2431
|
+
out.set(r.competition, { event: r.event, year: r.year, tier: r.tier });
|
|
2432
|
+
tiers.set(`${r.event.toLowerCase()}\x00${r.year}`, r.tier);
|
|
2433
|
+
}
|
|
2434
|
+
const missing = only === null ? null : only.filter((c) => !out.has(c));
|
|
2435
|
+
if (missing !== null && missing.length === 0)
|
|
2436
|
+
return out;
|
|
2437
|
+
if ((await this.rel.capability("teams")).state !== "full")
|
|
2438
|
+
return out;
|
|
2439
|
+
const teams = await this.rel.indexDb("teams");
|
|
2440
|
+
const team = teams.query("SELECT competition, event, year FROM result WHERE competition IS NOT NULL GROUP BY competition");
|
|
2441
|
+
const want = missing === null ? null : new Set(missing);
|
|
2442
|
+
for (const t of team.all()) {
|
|
2443
|
+
if (out.has(t.competition) || want !== null && !want.has(t.competition))
|
|
2444
|
+
continue;
|
|
2445
|
+
out.set(t.competition, {
|
|
2446
|
+
event: t.event,
|
|
2447
|
+
year: t.year,
|
|
2448
|
+
tier: tiers.get(`${t.event.toLowerCase()}\x00${t.year}`) ?? null
|
|
2449
|
+
});
|
|
2450
|
+
}
|
|
2451
|
+
if ([...out.values()].some((s) => s.tier === null && s.event !== null)) {
|
|
2452
|
+
for (const r of db.query("SELECT event, year, min(tier) AS tier FROM competitions GROUP BY event, year").all())
|
|
2453
|
+
tiers.set(`${r.event.toLowerCase()}\x00${r.year}`, r.tier);
|
|
2454
|
+
for (const s of out.values())
|
|
2455
|
+
if (s.tier === null && s.event !== null)
|
|
2456
|
+
s.tier = tiers.get(`${s.event.toLowerCase()}\x00${s.year}`) ?? null;
|
|
2457
|
+
}
|
|
2458
|
+
return out;
|
|
2459
|
+
}
|
|
2460
|
+
async query(q) {
|
|
2461
|
+
const db = await this.db();
|
|
2462
|
+
const where = [];
|
|
2463
|
+
const args = [];
|
|
2464
|
+
if (q.address !== undefined) {
|
|
2465
|
+
where.push("address = ?");
|
|
2466
|
+
args.push(q.address);
|
|
2467
|
+
} else if (q.competition !== undefined) {
|
|
2468
|
+
const [lo, hi] = cardRange(q.competition);
|
|
2469
|
+
where.push("address >= ? AND address < ? AND slug = ?");
|
|
2470
|
+
args.push(lo, hi, q.competition);
|
|
2471
|
+
} else
|
|
2472
|
+
throw new Error("archive-client: a tabs query names a competition or an address");
|
|
2473
|
+
if (q.round !== undefined) {
|
|
2474
|
+
where.push("round = ?");
|
|
2475
|
+
args.push(q.round);
|
|
2476
|
+
}
|
|
2477
|
+
const raw = db.query(`SELECT ${TAB_COLUMNS} FROM tabs WHERE ${where.join(" AND ")} ORDER BY address, round, seat_index, line`).all(...args);
|
|
2478
|
+
const sheets = raw.length === 0 ? new Map : await this.sheets(db, [...new Set(raw.map((r) => r.competition))]);
|
|
2479
|
+
return {
|
|
2480
|
+
tag: this.rel.tag,
|
|
2481
|
+
asked: q,
|
|
2482
|
+
rows: raw.map((r) => ({ ...r, ...sheets.get(r.competition) ?? NO_SHEET }))
|
|
2483
|
+
};
|
|
2484
|
+
}
|
|
2485
|
+
async* stream(q = {}) {
|
|
2486
|
+
const db = await this.db();
|
|
2487
|
+
const sheets = await this.sheets(db, q.competition ?? null);
|
|
2488
|
+
const events = q.event === undefined ? null : new Set((typeof q.event === "string" ? [q.event] : q.event).map((e) => e.toLowerCase()));
|
|
2489
|
+
const tiers = q.tier === undefined ? null : new Set(q.tier);
|
|
2490
|
+
const holds = (s) => {
|
|
2491
|
+
if (events !== null && (s.event === null || !events.has(s.event.toLowerCase())))
|
|
2492
|
+
return false;
|
|
2493
|
+
if (tiers !== null && (s.tier === null || !tiers.has(s.tier)))
|
|
2494
|
+
return false;
|
|
2495
|
+
if (typeof q.year === "number" && s.year !== q.year)
|
|
2496
|
+
return false;
|
|
2497
|
+
if (Array.isArray(q.year) && (s.year === null || s.year < q.year[0] || s.year > q.year[1]))
|
|
2498
|
+
return false;
|
|
2499
|
+
return true;
|
|
2500
|
+
};
|
|
2501
|
+
const filtered = events !== null || tiers !== null || q.year !== undefined;
|
|
2502
|
+
const run = function* (stmt, args) {
|
|
2503
|
+
for (const r of stmt.iterate(...args))
|
|
2504
|
+
yield { ...r, ...sheets.get(r.competition) ?? NO_SHEET };
|
|
2505
|
+
};
|
|
2506
|
+
if (!filtered && q.competition === undefined) {
|
|
2507
|
+
const all = db.prepare(`SELECT ${TAB_COLUMNS} FROM tabs ORDER BY address, round, seat_index, line`);
|
|
2508
|
+
try {
|
|
2509
|
+
yield* run(all, []);
|
|
2510
|
+
} finally {
|
|
2511
|
+
all.finalize();
|
|
2512
|
+
}
|
|
2513
|
+
return;
|
|
2514
|
+
}
|
|
2515
|
+
const asked = [...new Set(q.competition ?? sheets.keys())].filter((c) => holds(sheets.get(c) ?? NO_SHEET));
|
|
2516
|
+
const one = db.prepare(`SELECT ${TAB_COLUMNS} FROM tabs WHERE address >= ? AND address < ? AND slug = ? ORDER BY address, round, seat_index, line`);
|
|
2517
|
+
try {
|
|
2518
|
+
for (const c of asked.sort((a, b) => a < b ? -1 : a > b ? 1 : 0)) {
|
|
2519
|
+
const [lo, hi] = cardRange(c);
|
|
2520
|
+
yield* run(one, [lo, hi, c]);
|
|
2521
|
+
}
|
|
2522
|
+
} finally {
|
|
2523
|
+
one.finalize();
|
|
2524
|
+
}
|
|
2525
|
+
}
|
|
2526
|
+
}
|
|
2527
|
+
|
|
2528
|
+
class PanelFinder2 {
|
|
2529
|
+
rel;
|
|
2530
|
+
constructor(rel) {
|
|
2531
|
+
this.rel = rel;
|
|
2532
|
+
}
|
|
2533
|
+
async query(q = {}) {
|
|
2534
|
+
await this.rel.fetch("results");
|
|
2535
|
+
await this.rel.require("panels");
|
|
2536
|
+
const where = q.competition === undefined ? "" : " WHERE slug = ?";
|
|
2537
|
+
const seats = this.rel.db("results").query(`SELECT slug AS competition, panel, round, seat_index, address, judge_name_printed,
|
|
2538
|
+
judge_clrg, judge_id, judge_unmatched
|
|
2539
|
+
FROM panels${where} ORDER BY slug, panel, round, seat_index`).all(...q.competition === undefined ? [] : [q.competition]);
|
|
2540
|
+
return { tag: this.rel.tag, asked: q, seats };
|
|
2541
|
+
}
|
|
2542
|
+
}
|
|
2543
|
+
|
|
2544
|
+
class FeisPanelFinder2 {
|
|
2545
|
+
rel;
|
|
2546
|
+
constructor(rel) {
|
|
2547
|
+
this.rel = rel;
|
|
2548
|
+
}
|
|
2549
|
+
async query(q = {}) {
|
|
2550
|
+
await this.rel.fetch("results");
|
|
2551
|
+
await this.rel.require("feis-panels");
|
|
2552
|
+
const where = [];
|
|
2553
|
+
const args = [];
|
|
2554
|
+
if (q.address !== undefined) {
|
|
2555
|
+
where.push("address = ?");
|
|
2556
|
+
args.push(q.address);
|
|
2557
|
+
}
|
|
2558
|
+
if (q.platform !== undefined) {
|
|
2559
|
+
where.push("platform = ?");
|
|
2560
|
+
args.push(q.platform);
|
|
2561
|
+
}
|
|
2562
|
+
const seats = this.rel.db("results").query(`SELECT address, platform, round, seat_index, panel_size, panel_kind, judge_name_printed,
|
|
2563
|
+
judge_state_printed, judge_clrg, judge_id, judge_unmatched, judge_basis
|
|
2564
|
+
FROM feis_panels${where.length === 0 ? "" : ` WHERE ${where.join(" AND ")}`}
|
|
2565
|
+
ORDER BY address, round, seat_index`).all(...args);
|
|
2566
|
+
return { tag: this.rel.tag, asked: q, seats };
|
|
2567
|
+
}
|
|
2568
|
+
}
|
|
2569
|
+
async function registerRows(rel, q) {
|
|
2570
|
+
await rel.fetch("results");
|
|
2571
|
+
await rel.require("staff.adjudicators");
|
|
2572
|
+
const where = [];
|
|
2573
|
+
const args = [];
|
|
2574
|
+
if (q.judge_clrg !== undefined) {
|
|
2575
|
+
where.push("judge_clrg = ?");
|
|
2576
|
+
args.push(q.judge_clrg);
|
|
2577
|
+
}
|
|
2578
|
+
if (q.year !== undefined) {
|
|
2579
|
+
where.push("year = ?");
|
|
2580
|
+
args.push(q.year);
|
|
2581
|
+
}
|
|
2582
|
+
const rows = rel.db("results").query(`SELECT judge_clrg, year, cat, name_printed, country, country_printed, country_code, region,
|
|
2583
|
+
region_printed, region_code, geohash, src
|
|
2584
|
+
FROM adjudicators${where.length === 0 ? "" : ` WHERE ${where.join(" AND ")}`}
|
|
2585
|
+
ORDER BY judge_clrg, year`).all(...args);
|
|
2586
|
+
return { tag: rel.tag, asked: q, rows };
|
|
2587
|
+
}
|
|
2588
|
+
|
|
2249
2589
|
var ENCODER2 = roleEncoder();
|
|
2250
2590
|
var WHO = { table: "who", value: "entry", valueType: "INTEGER PRIMARY KEY" };
|
|
2251
2591
|
var ASKED2 = ["surname_key", "nn4", "id"];
|
|
@@ -2363,6 +2703,9 @@ class StaffFinder2 {
|
|
|
2363
2703
|
adjudicator(asked) {
|
|
2364
2704
|
return this.find(asked, "adjudicator");
|
|
2365
2705
|
}
|
|
2706
|
+
adjudicators(q = {}) {
|
|
2707
|
+
return registerRows(this.rel, q);
|
|
2708
|
+
}
|
|
2366
2709
|
async find(asked, role) {
|
|
2367
2710
|
const db = await this.rel.indexDb("staff");
|
|
2368
2711
|
const a = asked.trim();
|
|
@@ -2507,8 +2850,8 @@ async function parquetColumns(path) {
|
|
|
2507
2850
|
return new Set(parquetSchema(meta).children.map((c) => c.element.name));
|
|
2508
2851
|
}
|
|
2509
2852
|
|
|
2510
|
-
var
|
|
2511
|
-
var
|
|
2853
|
+
var str2 = (v) => typeof v === "string" && v !== "" ? v : null;
|
|
2854
|
+
var num2 = (v) => typeof v === "number" ? v : null;
|
|
2512
2855
|
var strs = (v) => Array.isArray(v) ? v.filter((x) => typeof x === "string") : [];
|
|
2513
2856
|
var scope = (id) => id === null ? null : id >= FEIS_LOCAL_ID_FLOOR2 ? "per-release" : "stable";
|
|
2514
2857
|
var TEAM_TABLES = [
|
|
@@ -2563,9 +2906,9 @@ var teamsIndex = {
|
|
|
2563
2906
|
const ey = new Map;
|
|
2564
2907
|
const putEy = out.prepare("INSERT OR IGNORE INTO event_year VALUES (?, ?, ?)");
|
|
2565
2908
|
for (const r of t.event_years) {
|
|
2566
|
-
const k =
|
|
2567
|
-
const event =
|
|
2568
|
-
const year =
|
|
2909
|
+
const k = str2(r.event_year);
|
|
2910
|
+
const event = str2(r.event);
|
|
2911
|
+
const year = num2(r.year);
|
|
2569
2912
|
if (k === null || event === null || year === null)
|
|
2570
2913
|
continue;
|
|
2571
2914
|
ey.set(k, { event, year });
|
|
@@ -2574,19 +2917,19 @@ var teamsIndex = {
|
|
|
2574
2917
|
const putR = out.prepare("INSERT OR IGNORE INTO result VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
|
|
2575
2918
|
let ord = 0;
|
|
2576
2919
|
for (const r of t.team_results)
|
|
2577
|
-
putR.run(
|
|
2920
|
+
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
2921
|
const putT = out.prepare("INSERT OR IGNORE INTO roster_team VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
|
|
2579
2922
|
for (const r of t.roster_teams) {
|
|
2580
|
-
const e = ey.get(
|
|
2581
|
-
putT.run(
|
|
2923
|
+
const e = ey.get(str2(r.event_year) ?? "");
|
|
2924
|
+
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
2925
|
}
|
|
2583
2926
|
const putM = out.prepare("INSERT INTO roster_member VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
|
|
2584
2927
|
for (const r of t.roster_members)
|
|
2585
|
-
putM.run(
|
|
2928
|
+
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
2929
|
const putJ = out.prepare("INSERT INTO result_roster VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
|
|
2587
2930
|
for (const r of t.team_result_rosters) {
|
|
2588
|
-
const e = ey.get(
|
|
2589
|
-
putJ.run(
|
|
2931
|
+
const e = ey.get(str2(r.event_year) ?? "");
|
|
2932
|
+
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
2933
|
}
|
|
2591
2934
|
for (const s of TEAMS_INDEXES)
|
|
2592
2935
|
out.run(s);
|
|
@@ -2606,11 +2949,11 @@ var eventsIndex = {
|
|
|
2606
2949
|
out.run(EVENTS_SCHEMA);
|
|
2607
2950
|
const put = out.prepare("INSERT OR IGNORE INTO event_year VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)");
|
|
2608
2951
|
for (const r of rows) {
|
|
2609
|
-
const event =
|
|
2610
|
-
const year =
|
|
2952
|
+
const event = str2(r.event);
|
|
2953
|
+
const year = num2(r.year);
|
|
2611
2954
|
if (event === null || year === null)
|
|
2612
2955
|
continue;
|
|
2613
|
-
put.run(event, year,
|
|
2956
|
+
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
2957
|
}
|
|
2615
2958
|
out.run("CREATE INDEX event_year_event ON event_year(event COLLATE NOCASE)");
|
|
2616
2959
|
}
|
|
@@ -3238,7 +3581,7 @@ var FEATURES2 = [
|
|
|
3238
3581
|
feature: "schools.lineage",
|
|
3239
3582
|
needs: ["school-lineage.jsonl"],
|
|
3240
3583
|
since: 184,
|
|
3241
|
-
calls: "schools.links and schools.
|
|
3584
|
+
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
3585
|
},
|
|
3243
3586
|
{
|
|
3244
3587
|
feature: "results.stream",
|
|
@@ -3396,6 +3739,94 @@ var FEATURES2 = [
|
|
|
3396
3739
|
since: 260,
|
|
3397
3740
|
calls: "events.years (the events index)"
|
|
3398
3741
|
},
|
|
3742
|
+
{
|
|
3743
|
+
feature: "upcoming.feises",
|
|
3744
|
+
needs: [
|
|
3745
|
+
"occurrence_id",
|
|
3746
|
+
"occurrence_ids",
|
|
3747
|
+
"name_printed",
|
|
3748
|
+
"date_lo",
|
|
3749
|
+
"date_hi",
|
|
3750
|
+
"year",
|
|
3751
|
+
"hosts",
|
|
3752
|
+
"feis_brand_id",
|
|
3753
|
+
"feis_instance_id",
|
|
3754
|
+
"series_basis",
|
|
3755
|
+
"brand_candidates",
|
|
3756
|
+
"captured_id",
|
|
3757
|
+
"results_state"
|
|
3758
|
+
].map((c) => `results:upcoming_feises.${c}`),
|
|
3759
|
+
since: 285,
|
|
3760
|
+
calls: "upcoming.feises, the `next` of feises.series"
|
|
3761
|
+
},
|
|
3762
|
+
{
|
|
3763
|
+
feature: "upcoming.fields",
|
|
3764
|
+
needs: [
|
|
3765
|
+
"field_id",
|
|
3766
|
+
"feis_id",
|
|
3767
|
+
"source",
|
|
3768
|
+
"host_id",
|
|
3769
|
+
"competition_code",
|
|
3770
|
+
"count_only",
|
|
3771
|
+
"occurrence_id",
|
|
3772
|
+
"name_printed",
|
|
3773
|
+
"date_lo",
|
|
3774
|
+
"date_hi",
|
|
3775
|
+
"year",
|
|
3776
|
+
"feis_brand_id",
|
|
3777
|
+
"comp_arm",
|
|
3778
|
+
"comp_source",
|
|
3779
|
+
"comp_kind",
|
|
3780
|
+
"level",
|
|
3781
|
+
"feis_level",
|
|
3782
|
+
"age",
|
|
3783
|
+
"population",
|
|
3784
|
+
"comp_title",
|
|
3785
|
+
"comp_why",
|
|
3786
|
+
"state",
|
|
3787
|
+
"results_competitions",
|
|
3788
|
+
"results_feis_ids",
|
|
3789
|
+
"version",
|
|
3790
|
+
"versions",
|
|
3791
|
+
"captured_date",
|
|
3792
|
+
"sha256",
|
|
3793
|
+
"limits",
|
|
3794
|
+
"entrants",
|
|
3795
|
+
"stated_rows",
|
|
3796
|
+
"printed_total"
|
|
3797
|
+
].map((c) => `results:upcoming_fields.${c}`),
|
|
3798
|
+
since: 291,
|
|
3799
|
+
calls: "upcoming.fields (285 and 290 carry the table empty)"
|
|
3800
|
+
},
|
|
3801
|
+
{
|
|
3802
|
+
feature: "upcoming.entrants",
|
|
3803
|
+
needs: [
|
|
3804
|
+
"feis_id",
|
|
3805
|
+
"captured_id",
|
|
3806
|
+
"row_id",
|
|
3807
|
+
"source",
|
|
3808
|
+
"host_id",
|
|
3809
|
+
"row_kind",
|
|
3810
|
+
"count_only",
|
|
3811
|
+
"n",
|
|
3812
|
+
"name_printed",
|
|
3813
|
+
"school_printed",
|
|
3814
|
+
"school_id",
|
|
3815
|
+
"school_rung",
|
|
3816
|
+
"school_candidates",
|
|
3817
|
+
"competitions",
|
|
3818
|
+
"field_ids",
|
|
3819
|
+
"level_counts",
|
|
3820
|
+
"yob",
|
|
3821
|
+
"asked",
|
|
3822
|
+
"arm",
|
|
3823
|
+
"candidate_ids",
|
|
3824
|
+
"candidates",
|
|
3825
|
+
"flags"
|
|
3826
|
+
].map((c) => `results:upcoming_entrants.${c}`),
|
|
3827
|
+
since: 291,
|
|
3828
|
+
calls: "upcoming.entrants (285 and 290 carry the table empty)"
|
|
3829
|
+
},
|
|
3399
3830
|
{
|
|
3400
3831
|
feature: "staff",
|
|
3401
3832
|
needs: [
|
|
@@ -3407,17 +3838,102 @@ var FEATURES2 = [
|
|
|
3407
3838
|
],
|
|
3408
3839
|
since: 260,
|
|
3409
3840
|
calls: "staff.teacher, staff.adjudicator (the staff index)"
|
|
3841
|
+
},
|
|
3842
|
+
{ feature: "tabs", needs: TAB_NEEDS, since: 184, calls: "tabs.query, tabs.stream" },
|
|
3843
|
+
{
|
|
3844
|
+
feature: "panels",
|
|
3845
|
+
needs: [
|
|
3846
|
+
"slug",
|
|
3847
|
+
"panel",
|
|
3848
|
+
"round",
|
|
3849
|
+
"seat_index",
|
|
3850
|
+
"address",
|
|
3851
|
+
"judge_name_printed",
|
|
3852
|
+
"judge_clrg",
|
|
3853
|
+
"judge_id",
|
|
3854
|
+
"judge_unmatched"
|
|
3855
|
+
].map((c) => `results:panels.${c}`),
|
|
3856
|
+
since: 184,
|
|
3857
|
+
calls: "panels.query"
|
|
3858
|
+
},
|
|
3859
|
+
{
|
|
3860
|
+
feature: "feis-panels",
|
|
3861
|
+
needs: [
|
|
3862
|
+
"address",
|
|
3863
|
+
"platform",
|
|
3864
|
+
"round",
|
|
3865
|
+
"seat_index",
|
|
3866
|
+
"panel_size",
|
|
3867
|
+
"panel_kind",
|
|
3868
|
+
"judge_name_printed",
|
|
3869
|
+
"judge_state_printed",
|
|
3870
|
+
"judge_clrg",
|
|
3871
|
+
"judge_id",
|
|
3872
|
+
"judge_unmatched",
|
|
3873
|
+
"judge_basis"
|
|
3874
|
+
].map((c) => `results:feis_panels.${c}`),
|
|
3875
|
+
since: 260,
|
|
3876
|
+
calls: "feisPanels.query"
|
|
3877
|
+
},
|
|
3878
|
+
{
|
|
3879
|
+
feature: "staff.adjudicators",
|
|
3880
|
+
needs: [
|
|
3881
|
+
"judge_clrg",
|
|
3882
|
+
"year",
|
|
3883
|
+
"cat",
|
|
3884
|
+
"name_printed",
|
|
3885
|
+
"country",
|
|
3886
|
+
"country_printed",
|
|
3887
|
+
"country_code",
|
|
3888
|
+
"region",
|
|
3889
|
+
"region_printed",
|
|
3890
|
+
"region_code",
|
|
3891
|
+
"geohash",
|
|
3892
|
+
"src"
|
|
3893
|
+
].map((c) => `results:adjudicators.${c}`),
|
|
3894
|
+
since: 230,
|
|
3895
|
+
calls: "staff.adjudicators"
|
|
3896
|
+
},
|
|
3897
|
+
{
|
|
3898
|
+
feature: "schools.registry",
|
|
3899
|
+
needs: ["school-registry.jsonl"],
|
|
3900
|
+
since: 260,
|
|
3901
|
+
calls: "schools.list"
|
|
3902
|
+
},
|
|
3903
|
+
{
|
|
3904
|
+
feature: "schools.prints",
|
|
3905
|
+
needs: [
|
|
3906
|
+
"results:results.school_printed",
|
|
3907
|
+
"results:results.school_id",
|
|
3908
|
+
"results:results.competition_line",
|
|
3909
|
+
"results:competitions.event",
|
|
3910
|
+
"results:competitions.year"
|
|
3911
|
+
],
|
|
3912
|
+
since: 184,
|
|
3913
|
+
calls: "schools.prints"
|
|
3914
|
+
},
|
|
3915
|
+
{
|
|
3916
|
+
feature: "schools.redirects",
|
|
3917
|
+
needs: ["school-redirects.jsonl"],
|
|
3918
|
+
since: 184,
|
|
3919
|
+
calls: "schools.redirects"
|
|
3920
|
+
},
|
|
3921
|
+
{
|
|
3922
|
+
feature: "schools.associations",
|
|
3923
|
+
needs: ["observed-associations.jsonl"],
|
|
3924
|
+
since: 215,
|
|
3925
|
+
calls: "schools.associations"
|
|
3410
3926
|
}
|
|
3411
3927
|
];
|
|
3412
3928
|
async function hasNeed(probe, n) {
|
|
3413
|
-
const t = /^table:([A-Za-z_]
|
|
3929
|
+
const t = /^table:([A-Za-z_]\w*)(?:\.([A-Za-z_]\w*))?$/.exec(n);
|
|
3414
3930
|
if (t !== null) {
|
|
3415
3931
|
if (probe.tableColumns === undefined)
|
|
3416
3932
|
return false;
|
|
3417
3933
|
const cols = await probe.tableColumns(t[1]);
|
|
3418
3934
|
return t[2] === undefined ? cols.size > 0 : cols.has(t[2]);
|
|
3419
3935
|
}
|
|
3420
|
-
const m = /^(results|majors):([A-Za-z_]
|
|
3936
|
+
const m = /^(results|majors):([A-Za-z_]\w*)(?:\.([A-Za-z_]\w*))?$/.exec(n);
|
|
3421
3937
|
if (m === null)
|
|
3422
3938
|
return probe.publishes(n);
|
|
3423
3939
|
const cols = columnsOf2(await probe.db(m[1]), m[2]);
|
|
@@ -3434,6 +3950,186 @@ function needsRelease2(tag, c) {
|
|
|
3434
3950
|
return new Error(`archive-client: ${tag} is too old for ${c.feature} (${c.calls}): it lacks ${c.missing.join(", ")}. Open a release of cut ${c.since} or later`);
|
|
3435
3951
|
}
|
|
3436
3952
|
|
|
3953
|
+
var FIELD_STATES2 = ["pending", "results", "passed", "withdrawn"];
|
|
3954
|
+
var json = (s, empty) => typeof s === "string" && s !== "" ? JSON.parse(s) : empty;
|
|
3955
|
+
function fieldOf(r) {
|
|
3956
|
+
const countOnly = r.count_only === 1;
|
|
3957
|
+
return {
|
|
3958
|
+
field_id: r.field_id,
|
|
3959
|
+
feis_id: r.feis_id,
|
|
3960
|
+
source: r.source,
|
|
3961
|
+
host_id: r.host_id,
|
|
3962
|
+
competition_code: r.competition_code ?? null,
|
|
3963
|
+
count_only: countOnly,
|
|
3964
|
+
occurrence_id: r.occurrence_id ?? null,
|
|
3965
|
+
name_printed: r.name_printed,
|
|
3966
|
+
date_lo: r.date_lo ?? null,
|
|
3967
|
+
date_hi: r.date_hi ?? null,
|
|
3968
|
+
year: r.year,
|
|
3969
|
+
feis_brand_id: r.feis_brand_id ?? null,
|
|
3970
|
+
comp: r.comp_arm === null ? null : {
|
|
3971
|
+
arm: r.comp_arm,
|
|
3972
|
+
source: r.comp_source ?? null,
|
|
3973
|
+
kind: r.comp_kind ?? null,
|
|
3974
|
+
level: r.level ?? null,
|
|
3975
|
+
feis_level: r.feis_level ?? null,
|
|
3976
|
+
age: r.age ?? null,
|
|
3977
|
+
population: r.population ?? null,
|
|
3978
|
+
title: r.comp_title ?? null,
|
|
3979
|
+
why: r.comp_why ?? null
|
|
3980
|
+
},
|
|
3981
|
+
state: r.state,
|
|
3982
|
+
results_competitions: json(r.results_competitions, []),
|
|
3983
|
+
results_feis_ids: json(r.results_feis_ids, []),
|
|
3984
|
+
version: r.version,
|
|
3985
|
+
versions: json(r.versions, []),
|
|
3986
|
+
captured_date: r.captured_date,
|
|
3987
|
+
sha256: r.sha256,
|
|
3988
|
+
limits: json(r.limits, []),
|
|
3989
|
+
entrants: r.entrants,
|
|
3990
|
+
stated_rows: r.stated_rows ?? null,
|
|
3991
|
+
printed_total: json(r.printed_total, null)
|
|
3992
|
+
};
|
|
3993
|
+
}
|
|
3994
|
+
function entrantOf(r) {
|
|
3995
|
+
return {
|
|
3996
|
+
feis_id: r.feis_id,
|
|
3997
|
+
captured_id: r.captured_id,
|
|
3998
|
+
row_id: r.row_id,
|
|
3999
|
+
source: r.source,
|
|
4000
|
+
host_id: r.host_id,
|
|
4001
|
+
row_kind: r.row_kind,
|
|
4002
|
+
count_only: r.count_only === 1,
|
|
4003
|
+
n: r.n,
|
|
4004
|
+
name_printed: r.name_printed ?? null,
|
|
4005
|
+
school_printed: r.school_printed ?? null,
|
|
4006
|
+
school_id: r.school_id ?? null,
|
|
4007
|
+
school_rung: r.school_rung,
|
|
4008
|
+
school_candidates: json(r.school_candidates, []),
|
|
4009
|
+
competitions: json(r.competitions, []),
|
|
4010
|
+
field_ids: json(r.field_ids, []),
|
|
4011
|
+
level_counts: json(r.level_counts, null),
|
|
4012
|
+
yob: r.yob ?? null,
|
|
4013
|
+
asked: json(r.asked, null),
|
|
4014
|
+
arm: r.arm ?? null,
|
|
4015
|
+
candidates: json(r.candidates, []),
|
|
4016
|
+
flags: json(r.flags, [])
|
|
4017
|
+
};
|
|
4018
|
+
}
|
|
4019
|
+
function feisOf(r) {
|
|
4020
|
+
return {
|
|
4021
|
+
occurrence_id: r.occurrence_id,
|
|
4022
|
+
occurrence_ids: json(r.occurrence_ids, []),
|
|
4023
|
+
name_printed: r.name_printed,
|
|
4024
|
+
date_lo: r.date_lo,
|
|
4025
|
+
date_hi: r.date_hi ?? null,
|
|
4026
|
+
year: r.year,
|
|
4027
|
+
hosts: json(r.hosts, []),
|
|
4028
|
+
feis_brand_id: r.feis_brand_id ?? null,
|
|
4029
|
+
feis_instance_id: r.feis_instance_id ?? null,
|
|
4030
|
+
series_basis: r.series_basis,
|
|
4031
|
+
brand_candidates: json(r.brand_candidates, []),
|
|
4032
|
+
captured_id: r.captured_id,
|
|
4033
|
+
state: r.results_state
|
|
4034
|
+
};
|
|
4035
|
+
}
|
|
4036
|
+
|
|
4037
|
+
class UpcomingFinder2 {
|
|
4038
|
+
rel;
|
|
4039
|
+
constructor(rel) {
|
|
4040
|
+
this.rel = rel;
|
|
4041
|
+
}
|
|
4042
|
+
async db(feature) {
|
|
4043
|
+
await this.rel.fetch("results");
|
|
4044
|
+
await this.rel.require(feature);
|
|
4045
|
+
return this.rel.db("results");
|
|
4046
|
+
}
|
|
4047
|
+
async feises(q = {}) {
|
|
4048
|
+
const db = await this.db("upcoming.feises");
|
|
4049
|
+
const where = [];
|
|
4050
|
+
const args = [];
|
|
4051
|
+
if (q.state !== undefined) {
|
|
4052
|
+
where.push("results_state = ?");
|
|
4053
|
+
args.push(q.state);
|
|
4054
|
+
}
|
|
4055
|
+
if (q.brand !== undefined) {
|
|
4056
|
+
where.push("feis_brand_id = ?");
|
|
4057
|
+
args.push(q.brand);
|
|
4058
|
+
}
|
|
4059
|
+
if (q.from !== undefined) {
|
|
4060
|
+
where.push("date_lo >= ?");
|
|
4061
|
+
args.push(q.from);
|
|
4062
|
+
}
|
|
4063
|
+
if (q.to !== undefined) {
|
|
4064
|
+
where.push("date_lo <= ?");
|
|
4065
|
+
args.push(q.to);
|
|
4066
|
+
}
|
|
4067
|
+
const sql = `SELECT * FROM upcoming_feises${where.length > 0 ? ` WHERE ${where.join(" AND ")}` : ""} ORDER BY date_lo, occurrence_id`;
|
|
4068
|
+
const rows = db.query(sql).all(...args);
|
|
4069
|
+
return { tag: this.rel.tag, feises: rows.map(feisOf) };
|
|
4070
|
+
}
|
|
4071
|
+
async fields(q = {}) {
|
|
4072
|
+
const db = await this.db("upcoming.fields");
|
|
4073
|
+
const where = [];
|
|
4074
|
+
const args = [];
|
|
4075
|
+
if (q.state !== undefined) {
|
|
4076
|
+
const states = typeof q.state === "string" ? [q.state] : [...q.state];
|
|
4077
|
+
if (states.length === 0)
|
|
4078
|
+
return { tag: this.rel.tag, fields: [] };
|
|
4079
|
+
where.push(`state IN (${states.map(() => "?").join(", ")})`);
|
|
4080
|
+
args.push(...states);
|
|
4081
|
+
}
|
|
4082
|
+
if (q.feis !== undefined) {
|
|
4083
|
+
where.push("(feis_id = ? OR feis_brand_id = ? OR occurrence_id = ?)");
|
|
4084
|
+
args.push(q.feis, q.feis, q.feis);
|
|
4085
|
+
}
|
|
4086
|
+
if (q.field_id !== undefined) {
|
|
4087
|
+
where.push("field_id = ?");
|
|
4088
|
+
args.push(q.field_id);
|
|
4089
|
+
}
|
|
4090
|
+
if (q.from !== undefined) {
|
|
4091
|
+
where.push("date_lo >= ?");
|
|
4092
|
+
args.push(q.from);
|
|
4093
|
+
}
|
|
4094
|
+
if (q.to !== undefined) {
|
|
4095
|
+
where.push("date_lo <= ?");
|
|
4096
|
+
args.push(q.to);
|
|
4097
|
+
}
|
|
4098
|
+
const sql = `SELECT * FROM upcoming_fields${where.length > 0 ? ` WHERE ${where.join(" AND ")}` : ""} ORDER BY date_lo, feis_id, field_id`;
|
|
4099
|
+
const rows = db.query(sql).all(...args);
|
|
4100
|
+
return { tag: this.rel.tag, fields: rows.map(fieldOf) };
|
|
4101
|
+
}
|
|
4102
|
+
async entrants(q) {
|
|
4103
|
+
const [field] = (await this.fields({ field_id: q.field_id })).fields;
|
|
4104
|
+
const db = await this.db("upcoming.entrants");
|
|
4105
|
+
if (field === undefined)
|
|
4106
|
+
return {
|
|
4107
|
+
tag: this.rel.tag,
|
|
4108
|
+
field: null,
|
|
4109
|
+
version: null,
|
|
4110
|
+
entrants: [],
|
|
4111
|
+
why: `the release holds no field "${q.field_id}"`
|
|
4112
|
+
};
|
|
4113
|
+
const version = q.version ?? field.version;
|
|
4114
|
+
if (!field.versions.includes(version))
|
|
4115
|
+
return {
|
|
4116
|
+
tag: this.rel.tag,
|
|
4117
|
+
field,
|
|
4118
|
+
version,
|
|
4119
|
+
entrants: [],
|
|
4120
|
+
why: `${field.field_id} has no version ${version} (versions ${field.versions.join(", ")})`
|
|
4121
|
+
};
|
|
4122
|
+
const rows = db.query("SELECT * FROM upcoming_entrants WHERE feis_id = ? AND captured_id = ? ORDER BY row_id").all(field.feis_id, version).map(entrantOf).filter((e) => e.field_ids.includes(field.field_id));
|
|
4123
|
+
return {
|
|
4124
|
+
tag: this.rel.tag,
|
|
4125
|
+
field,
|
|
4126
|
+
version,
|
|
4127
|
+
entrants: rows,
|
|
4128
|
+
...rows.length === 0 ? { why: `${field.field_id} lists no row in version ${version}` } : {}
|
|
4129
|
+
};
|
|
4130
|
+
}
|
|
4131
|
+
}
|
|
4132
|
+
|
|
3437
4133
|
function tagDir(root, tag) {
|
|
3438
4134
|
if (parseArchiveTag2(tag) === null)
|
|
3439
4135
|
throw new Error(`archive-client: "${tag}" is not a release tag (archive-YYYY.MM.DD[-N[.k]])`);
|
|
@@ -3490,6 +4186,10 @@ class Release2 {
|
|
|
3490
4186
|
registrations;
|
|
3491
4187
|
teams;
|
|
3492
4188
|
events;
|
|
4189
|
+
upcoming;
|
|
4190
|
+
tabs;
|
|
4191
|
+
panels;
|
|
4192
|
+
feisPanels;
|
|
3493
4193
|
opts;
|
|
3494
4194
|
handles = new Map;
|
|
3495
4195
|
remoteAssets = null;
|
|
@@ -3512,6 +4212,10 @@ class Release2 {
|
|
|
3512
4212
|
this.registrations = new RegistrationResolver2(this, this.comps, opts.dancerResolver);
|
|
3513
4213
|
this.teams = new TeamFinder2(this);
|
|
3514
4214
|
this.events = new EventFinder2(this);
|
|
4215
|
+
this.upcoming = new UpcomingFinder2(this);
|
|
4216
|
+
this.tabs = new TabFinder2(this);
|
|
4217
|
+
this.panels = new PanelFinder2(this);
|
|
4218
|
+
this.feisPanels = new FeisPanelFinder2(this);
|
|
3515
4219
|
}
|
|
3516
4220
|
receipt() {
|
|
3517
4221
|
return readReceipt(this.dir) ?? { tag: this.tag, source: "unknown", files: {} };
|
|
@@ -4232,4 +4936,4 @@ function staleWarning2(answered, latest, floor, tags = [], command = "idq") {
|
|
|
4232
4936
|
return `answered from ${answered}. ${floorTag ?? `cut ${floor.cut}`} is required${why}: run \`${command} use ${floor.cut}\` to get it`;
|
|
4233
4937
|
}
|
|
4234
4938
|
|
|
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 };
|
|
4939
|
+
export { DATABASES2, planAsset2, sha256File2, unzstdTo2, NAME_LEVELS2, nameLevel2, NO_CALENDAR2, NO_UPCOMING2, 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, FIELD_STATES2, UpcomingFinder2, 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 };
|