@bitcobblers/wod-wiki-wql 0.6.32 → 0.7.37
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/dist/index.cjs +309 -140
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +92 -42
- package/dist/index.d.ts +92 -42
- package/dist/index.mjs +307 -141
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -55,7 +55,7 @@ var WQL_CALC_TARGETS = [
|
|
|
55
55
|
"calc.sends"
|
|
56
56
|
];
|
|
57
57
|
var WQL_INTENSITY_TIERS = ["low", "moderate", "high"];
|
|
58
|
-
var WQL_GRAINS = ["
|
|
58
|
+
var WQL_GRAINS = ["summary", "event"];
|
|
59
59
|
var WQL_FIND_TARGETS = ["note", "block", "effort"];
|
|
60
60
|
var WQL_SCOPES = ["journal", "collections", "feeds", "all"];
|
|
61
61
|
var WQL_CONTENT_FILTER_KEYS = ["type", "text", "has", "source", "catalog", ...WQL_TAG_KEYS];
|
|
@@ -162,55 +162,62 @@ function parseWqlSuffixes(raw) {
|
|
|
162
162
|
let groupBy;
|
|
163
163
|
let last;
|
|
164
164
|
let scope;
|
|
165
|
+
const conflicts = [];
|
|
165
166
|
const isFind = text.startsWith("find:");
|
|
166
167
|
const isRows = /^rows(?=[:{]|\s|$)/.test(text);
|
|
168
|
+
const stripRepeated = (re) => {
|
|
169
|
+
const matches = [];
|
|
170
|
+
for (let m = re.exec(text); m; m = re.exec(text)) {
|
|
171
|
+
matches.unshift(m);
|
|
172
|
+
text = text.slice(0, m.index).trim();
|
|
173
|
+
}
|
|
174
|
+
return matches;
|
|
175
|
+
};
|
|
176
|
+
const conflictFrom = (label, ms) => {
|
|
177
|
+
if (ms.length > 1) {
|
|
178
|
+
conflicts.push(
|
|
179
|
+
`Duplicate '${label}' clause: '${ms[0][0].trim()}' conflicts with '${ms[ms.length - 1][0].trim()}'`
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
};
|
|
167
183
|
if (isFind || isRows) {
|
|
168
|
-
const
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
raw: lastMatch[0].trim()
|
|
174
|
-
};
|
|
175
|
-
text = text.slice(0, lastMatch.index).trim();
|
|
184
|
+
const lasts = stripRepeated(LAST_RE);
|
|
185
|
+
conflictFrom("window", lasts);
|
|
186
|
+
if (lasts.length) {
|
|
187
|
+
const m = lasts[lasts.length - 1];
|
|
188
|
+
last = { size: parseInt(m[1], 10), unit: m[2].toLowerCase(), raw: m[0].trim() };
|
|
176
189
|
}
|
|
177
190
|
if (isFind) {
|
|
178
|
-
const
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
text = text.slice(0, scopeMatch.index).trim();
|
|
182
|
-
}
|
|
191
|
+
const scopes = stripRepeated(IN_SCOPE_RE);
|
|
192
|
+
conflictFrom("scope", scopes);
|
|
193
|
+
if (scopes.length) scope = scopes[scopes.length - 1][1];
|
|
183
194
|
} else {
|
|
184
|
-
const
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
195
|
+
const rollups = stripRepeated(ROLLUP_RE);
|
|
196
|
+
conflictFrom(".rollup", rollups);
|
|
197
|
+
if (rollups.length) {
|
|
198
|
+
const m = rollups[rollups.length - 1];
|
|
199
|
+
rollup = { size: m[1] ? parseInt(m[1], 10) : 1, unit: m[2] || "", raw: m[1] + m[2] };
|
|
189
200
|
}
|
|
190
|
-
const
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
201
|
+
const bys = stripRepeated(BY_RE);
|
|
202
|
+
conflictFrom("by", bys);
|
|
203
|
+
if (bys.length) {
|
|
204
|
+
groupBy = bys[bys.length - 1][1].split(",").map((d) => d.trim()).filter(Boolean);
|
|
194
205
|
}
|
|
195
206
|
}
|
|
196
207
|
} else {
|
|
197
|
-
const
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
const size = rollupMatch[1] ? parseInt(rollupMatch[1], 10) : 1;
|
|
206
|
-
const unit = rollupMatch[2] || "";
|
|
207
|
-
rollup = { size, unit, raw: rawRollup };
|
|
208
|
-
text = text.slice(0, rollupMatch.index).trim();
|
|
208
|
+
const units = stripRepeated(DISPLAY_UNIT_RE);
|
|
209
|
+
conflictFrom("display-unit", units);
|
|
210
|
+
if (units.length) displayUnit = units[units.length - 1][1];
|
|
211
|
+
const rollups = stripRepeated(ROLLUP_RE);
|
|
212
|
+
conflictFrom(".rollup", rollups);
|
|
213
|
+
if (rollups.length) {
|
|
214
|
+
const m = rollups[rollups.length - 1];
|
|
215
|
+
rollup = { size: m[1] ? parseInt(m[1], 10) : 1, unit: m[2] || "", raw: m[1] + m[2] };
|
|
209
216
|
}
|
|
210
|
-
const
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
217
|
+
const bys = stripRepeated(BY_RE);
|
|
218
|
+
conflictFrom("by", bys);
|
|
219
|
+
if (bys.length) {
|
|
220
|
+
groupBy = bys[bys.length - 1][1].split(",").map((d) => d.trim()).filter(Boolean);
|
|
214
221
|
}
|
|
215
222
|
}
|
|
216
223
|
return {
|
|
@@ -220,6 +227,7 @@ function parseWqlSuffixes(raw) {
|
|
|
220
227
|
groupBy,
|
|
221
228
|
last,
|
|
222
229
|
scope,
|
|
230
|
+
conflicts: conflicts.length ? conflicts : void 0,
|
|
223
231
|
primaryText: text
|
|
224
232
|
};
|
|
225
233
|
}
|
|
@@ -281,6 +289,10 @@ function parseRowsQuery(raw) {
|
|
|
281
289
|
filters: [],
|
|
282
290
|
last: last ? { size: last.size, unit: last.unit } : void 0
|
|
283
291
|
};
|
|
292
|
+
if (suffixes.conflicts?.length) {
|
|
293
|
+
result.error = suffixes.conflicts.join("; ");
|
|
294
|
+
return result;
|
|
295
|
+
}
|
|
284
296
|
if (whereText || groupBy || rollup) {
|
|
285
297
|
result.error = `Rows queries return raw statements \u2014 no where / by / rollup. Got "${primaryText.trim()}"`;
|
|
286
298
|
return result;
|
|
@@ -316,9 +328,20 @@ function parseRowsQuery(raw) {
|
|
|
316
328
|
return result;
|
|
317
329
|
}
|
|
318
330
|
result.filters = extractFilters(tree.topNode, synthetic);
|
|
331
|
+
const grainError = retiredGrainRollup(result.filters);
|
|
332
|
+
if (grainError) {
|
|
333
|
+
result.error = grainError;
|
|
334
|
+
return result;
|
|
335
|
+
}
|
|
319
336
|
}
|
|
320
337
|
return result;
|
|
321
338
|
}
|
|
339
|
+
function retiredGrainRollup(filters) {
|
|
340
|
+
if (filters.some((f) => f.key === "grain" && f.values.some((v) => v.value === "rollup"))) {
|
|
341
|
+
return "grain:rollup is retired \u2014 rollup grains are never stored; compute them with the .rollup suffix";
|
|
342
|
+
}
|
|
343
|
+
return void 0;
|
|
344
|
+
}
|
|
322
345
|
function extractFilters(query, text) {
|
|
323
346
|
const out = [];
|
|
324
347
|
const filters = query.getChild(Filters);
|
|
@@ -358,6 +381,10 @@ function parseAnalyticsQuery(raw) {
|
|
|
358
381
|
displayUnit,
|
|
359
382
|
rollup: rollup ? { size: rollup.size, unit: rollup.unit } : void 0
|
|
360
383
|
};
|
|
384
|
+
if (suffixes.conflicts?.length) {
|
|
385
|
+
base.error = suffixes.conflicts.join("; ");
|
|
386
|
+
return base;
|
|
387
|
+
}
|
|
361
388
|
if (rollup && rollup.unit !== "d" && rollup.unit !== "w") {
|
|
362
389
|
base.error = cannotParse(text);
|
|
363
390
|
return base;
|
|
@@ -387,6 +414,11 @@ function parseAnalyticsQuery(raw) {
|
|
|
387
414
|
base.agg = aggText;
|
|
388
415
|
base.metric = text.slice(metricNode.from, metricNode.to);
|
|
389
416
|
base.filters = extractFilters(query, text);
|
|
417
|
+
const grainError = retiredGrainRollup(base.filters);
|
|
418
|
+
if (grainError) {
|
|
419
|
+
base.error = grainError;
|
|
420
|
+
return base;
|
|
421
|
+
}
|
|
390
422
|
if (whereText) {
|
|
391
423
|
const join = parseJoinClause(whereText);
|
|
392
424
|
if (join.error) {
|
|
@@ -414,6 +446,10 @@ function parseFindQuery(raw) {
|
|
|
414
446
|
scope,
|
|
415
447
|
last: last ? { size: last.size, unit: last.unit } : void 0
|
|
416
448
|
};
|
|
449
|
+
if (suffixes.conflicts?.length) {
|
|
450
|
+
result.error = suffixes.conflicts.join("; ");
|
|
451
|
+
return result;
|
|
452
|
+
}
|
|
417
453
|
const tree = parser.parse(text);
|
|
418
454
|
let syntaxError = false;
|
|
419
455
|
tree.iterate({ enter(node) {
|
|
@@ -438,6 +474,11 @@ function parseFindQuery(raw) {
|
|
|
438
474
|
}
|
|
439
475
|
result.target = text.slice(metricNode.from, metricNode.to);
|
|
440
476
|
result.filters = extractFilters(query, text);
|
|
477
|
+
const findGrainError = retiredGrainRollup(result.filters);
|
|
478
|
+
if (findGrainError) {
|
|
479
|
+
result.error = findGrainError;
|
|
480
|
+
return result;
|
|
481
|
+
}
|
|
441
482
|
if (whereText) {
|
|
442
483
|
const join = parseJoinClause(whereText);
|
|
443
484
|
if (join.error) {
|
|
@@ -723,9 +764,8 @@ function readGroupTags(metadata) {
|
|
|
723
764
|
const entries = Object.entries(tags).filter((pair) => typeof pair[1] === "string" && pair[1].length > 0).sort(([a], [b]) => a < b ? -1 : 1);
|
|
724
765
|
return entries.length > 0 ? Object.fromEntries(entries) : void 0;
|
|
725
766
|
}
|
|
726
|
-
function
|
|
727
|
-
const
|
|
728
|
-
const rowsByKey = /* @__PURE__ */ new Map();
|
|
767
|
+
function foldSummaryOutputs(logs) {
|
|
768
|
+
const folded = /* @__PURE__ */ new Map();
|
|
729
769
|
for (const output of logs) {
|
|
730
770
|
if (output.outputType !== "analytics") continue;
|
|
731
771
|
const label = output.metrics.find((m) => m.type === wodWikiCore.MetricType.Label);
|
|
@@ -740,32 +780,171 @@ function normalizeSummaryFacts(logs, identity) {
|
|
|
740
780
|
const grade = metadataString(value.metadata, "grade");
|
|
741
781
|
const groupTags = readGroupTags(value.metadata) ?? (effortSlug ? { effort: effortSlug } : void 0);
|
|
742
782
|
const rowKey = groupTags ? `${metricKey}:${Object.entries(groupTags).map(([k, v]) => `${k}=${v}`).join(":")}` : metricKey;
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
blockContentId: identity.blockContentId,
|
|
747
|
-
origin: identity.origin,
|
|
748
|
-
pageId: identity.pageId,
|
|
749
|
-
grain: "summary",
|
|
750
|
-
segmentId: identity.segmentId ?? "",
|
|
751
|
-
segmentVersion: identity.segmentVersion ?? 0,
|
|
752
|
-
resultId: identity.resultId,
|
|
753
|
-
type: metricKey,
|
|
783
|
+
folded.set(rowKey, {
|
|
784
|
+
projectionName,
|
|
785
|
+
metricKey,
|
|
754
786
|
value: value.value,
|
|
755
787
|
unit: value.unit,
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
...grade ? { grade } : {},
|
|
764
|
-
timestamp: identity.workoutTimestamp ?? output.timeSpan?.started ?? now,
|
|
765
|
-
createdAt: now
|
|
788
|
+
effortSlug,
|
|
789
|
+
discipline,
|
|
790
|
+
intensityTier,
|
|
791
|
+
grade,
|
|
792
|
+
groupTags,
|
|
793
|
+
rowKey,
|
|
794
|
+
started: output.timeSpan?.started
|
|
766
795
|
});
|
|
767
796
|
}
|
|
768
|
-
return
|
|
797
|
+
return folded;
|
|
798
|
+
}
|
|
799
|
+
function normalizeSummaryFacts(logs, identity) {
|
|
800
|
+
const now = Date.now();
|
|
801
|
+
return Array.from(foldSummaryOutputs(logs).values(), (f) => ({
|
|
802
|
+
id: `${identity.resultId}-${f.rowKey}-${now}`,
|
|
803
|
+
noteId: identity.noteId,
|
|
804
|
+
blockContentId: identity.blockContentId,
|
|
805
|
+
origin: identity.origin,
|
|
806
|
+
pageId: identity.pageId,
|
|
807
|
+
grain: "summary",
|
|
808
|
+
segmentId: identity.segmentId ?? "",
|
|
809
|
+
segmentVersion: identity.segmentVersion ?? 0,
|
|
810
|
+
resultId: identity.resultId,
|
|
811
|
+
type: f.metricKey,
|
|
812
|
+
value: f.value,
|
|
813
|
+
unit: f.unit,
|
|
814
|
+
label: f.projectionName,
|
|
815
|
+
metricKey: f.metricKey,
|
|
816
|
+
metricLabel: f.projectionName,
|
|
817
|
+
metricUnit: f.unit,
|
|
818
|
+
...f.effortSlug ? { effortSlug: f.effortSlug } : {},
|
|
819
|
+
...f.discipline ? { discipline: f.discipline } : {},
|
|
820
|
+
...f.intensityTier ? { intensityTier: f.intensityTier } : {},
|
|
821
|
+
...f.grade ? { grade: f.grade } : {},
|
|
822
|
+
timestamp: identity.workoutTimestamp ?? f.started ?? now,
|
|
823
|
+
createdAt: now
|
|
824
|
+
}));
|
|
825
|
+
}
|
|
826
|
+
function firstEffortSlug(metrics) {
|
|
827
|
+
const loose = metrics;
|
|
828
|
+
for (const m of loose) {
|
|
829
|
+
const slug = metadataString(m.metadata, "effortSlug");
|
|
830
|
+
if (slug) return slug;
|
|
831
|
+
}
|
|
832
|
+
return void 0;
|
|
833
|
+
}
|
|
834
|
+
function toEventRows(logs, identity) {
|
|
835
|
+
return logs.map((output, seq) => ({
|
|
836
|
+
id: `${identity.resultId}:${seq}`,
|
|
837
|
+
resultId: identity.resultId,
|
|
838
|
+
noteId: identity.noteId,
|
|
839
|
+
blockContentId: identity.blockContentId,
|
|
840
|
+
pageId: identity.pageId,
|
|
841
|
+
origin: identity.origin,
|
|
842
|
+
timestamp: identity.workoutTimestamp ?? output.timeSpan?.started ?? Date.now(),
|
|
843
|
+
grain: "event",
|
|
844
|
+
outputType: output.outputType ?? "segment",
|
|
845
|
+
effortSlug: firstEffortSlug(output.metrics),
|
|
846
|
+
metrics: output.metrics,
|
|
847
|
+
timeSpan: output.timeSpan?.started !== void 0 ? { started: output.timeSpan.started, ended: output.timeSpan.ended } : void 0,
|
|
848
|
+
sourceBlockKey: output.sourceBlockKey,
|
|
849
|
+
stackLevel: output.stackLevel,
|
|
850
|
+
completionReason: output.completionReason,
|
|
851
|
+
segmentId: identity.segmentId,
|
|
852
|
+
segmentVersion: identity.segmentVersion
|
|
853
|
+
}));
|
|
854
|
+
}
|
|
855
|
+
function toSummaryEventRows(logs, identity) {
|
|
856
|
+
const now = Date.now();
|
|
857
|
+
return Array.from(foldSummaryOutputs(logs).values(), (f) => ({
|
|
858
|
+
id: `${identity.resultId}:summary:${f.rowKey}`,
|
|
859
|
+
resultId: identity.resultId,
|
|
860
|
+
noteId: identity.noteId,
|
|
861
|
+
blockContentId: identity.blockContentId,
|
|
862
|
+
pageId: identity.pageId,
|
|
863
|
+
origin: identity.origin,
|
|
864
|
+
timestamp: identity.workoutTimestamp ?? f.started ?? now,
|
|
865
|
+
grain: "summary",
|
|
866
|
+
outputType: "analytics",
|
|
867
|
+
effortSlug: f.effortSlug,
|
|
868
|
+
metrics: [{
|
|
869
|
+
type: f.metricKey,
|
|
870
|
+
value: f.value,
|
|
871
|
+
...f.unit ? { unit: f.unit } : {},
|
|
872
|
+
metadata: {
|
|
873
|
+
canonicalKey: f.metricKey,
|
|
874
|
+
...f.effortSlug ? { effortSlug: f.effortSlug } : {},
|
|
875
|
+
...f.discipline ? { effortDiscipline: f.discipline } : {},
|
|
876
|
+
...f.intensityTier ? { effortIntensityTier: f.intensityTier } : {},
|
|
877
|
+
...f.groupTags ? { groupTags: f.groupTags } : {},
|
|
878
|
+
...f.grade ? { grade: f.grade } : {}
|
|
879
|
+
}
|
|
880
|
+
}],
|
|
881
|
+
segmentId: identity.segmentId,
|
|
882
|
+
segmentVersion: identity.segmentVersion
|
|
883
|
+
}));
|
|
884
|
+
}
|
|
885
|
+
function projectEventToFacts(record) {
|
|
886
|
+
const metrics = record.metrics;
|
|
887
|
+
if (record.grain === "summary") {
|
|
888
|
+
const m = metrics[0];
|
|
889
|
+
if (!m || typeof m.value !== "number") return [];
|
|
890
|
+
const metricKey = metadataString(m.metadata, "canonicalKey") ?? (m.type ?? "");
|
|
891
|
+
return [{
|
|
892
|
+
id: `${record.id}:0`,
|
|
893
|
+
noteId: record.noteId,
|
|
894
|
+
blockContentId: record.blockContentId,
|
|
895
|
+
origin: record.origin,
|
|
896
|
+
pageId: record.pageId,
|
|
897
|
+
grain: "summary",
|
|
898
|
+
segmentId: record.segmentId ?? "",
|
|
899
|
+
segmentVersion: record.segmentVersion ?? 0,
|
|
900
|
+
resultId: record.resultId,
|
|
901
|
+
type: metricKey,
|
|
902
|
+
value: m.value,
|
|
903
|
+
unit: m.unit,
|
|
904
|
+
label: metricKey,
|
|
905
|
+
metricKey,
|
|
906
|
+
metricLabel: metricKey,
|
|
907
|
+
metricUnit: m.unit,
|
|
908
|
+
effortSlug: metadataString(m.metadata, "effortSlug") ?? record.effortSlug,
|
|
909
|
+
discipline: metadataString(m.metadata, "effortDiscipline"),
|
|
910
|
+
intensityTier: metadataString(m.metadata, "effortIntensityTier"),
|
|
911
|
+
grade: metadataString(m.metadata, "grade"),
|
|
912
|
+
timestamp: record.timestamp,
|
|
913
|
+
createdAt: record.timestamp
|
|
914
|
+
}];
|
|
915
|
+
}
|
|
916
|
+
const label = metrics.find((m) => m.type === wodWikiCore.MetricType.Label);
|
|
917
|
+
const labelName = label ? String(label.value ?? label.image ?? "") : "";
|
|
918
|
+
const facts = [];
|
|
919
|
+
metrics.forEach((m) => {
|
|
920
|
+
if (m.type === wodWikiCore.MetricType.Label || typeof m.value !== "number") return;
|
|
921
|
+
const metricKey = metadataString(m.metadata, "canonicalKey") ?? (labelName ? resolveCanonicalMetricKey(labelName) : m.type ?? "metric");
|
|
922
|
+
const ordinal = facts.length;
|
|
923
|
+
facts.push({
|
|
924
|
+
id: `${record.id}:${ordinal}`,
|
|
925
|
+
noteId: record.noteId,
|
|
926
|
+
blockContentId: record.blockContentId,
|
|
927
|
+
origin: record.origin,
|
|
928
|
+
pageId: record.pageId,
|
|
929
|
+
grain: "event",
|
|
930
|
+
segmentId: record.segmentId ?? "",
|
|
931
|
+
segmentVersion: record.segmentVersion ?? 0,
|
|
932
|
+
resultId: record.resultId,
|
|
933
|
+
type: metricKey,
|
|
934
|
+
value: m.value,
|
|
935
|
+
unit: m.unit,
|
|
936
|
+
label: labelName || metricKey,
|
|
937
|
+
metricKey,
|
|
938
|
+
metricLabel: labelName || metricKey,
|
|
939
|
+
metricUnit: m.unit,
|
|
940
|
+
effortSlug: metadataString(m.metadata, "effortSlug") ?? record.effortSlug,
|
|
941
|
+
intensityTier: metadataString(m.metadata, "effortIntensityTier"),
|
|
942
|
+
grade: metadataString(m.metadata, "grade"),
|
|
943
|
+
timestamp: record.timestamp,
|
|
944
|
+
createdAt: record.timestamp
|
|
945
|
+
});
|
|
946
|
+
});
|
|
947
|
+
return facts;
|
|
769
948
|
}
|
|
770
949
|
|
|
771
950
|
// src/dashboard/frontmatter.ts
|
|
@@ -957,23 +1136,27 @@ function windowAnchor(selected, parsed, options2) {
|
|
|
957
1136
|
if (options2.anchor === "latest-activity" && parsed.last) return latestActivity(selected);
|
|
958
1137
|
return void 0;
|
|
959
1138
|
}
|
|
960
|
-
var
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
1139
|
+
var defaultEventStore = {
|
|
1140
|
+
getEventsByTimeRange: async () => [],
|
|
1141
|
+
getEventsByResult: async () => [],
|
|
1142
|
+
getEventsForNote: async () => [],
|
|
1143
|
+
getEventsByContent: async () => [],
|
|
1144
|
+
scanAll: async () => [],
|
|
1145
|
+
appendEvents: async () => {
|
|
1146
|
+
},
|
|
1147
|
+
finalizeSummaries: async () => {
|
|
1148
|
+
},
|
|
1149
|
+
deleteEvents: async () => {
|
|
1150
|
+
}
|
|
964
1151
|
};
|
|
965
1152
|
var defaultNoteStore = {
|
|
966
1153
|
getAllNotes: async () => [],
|
|
967
|
-
getNoteIdsForTag: async () => /* @__PURE__ */ new Set()
|
|
1154
|
+
getNoteIdsForTag: async () => /* @__PURE__ */ new Set(),
|
|
1155
|
+
getNoteTagLabels: async () => []
|
|
968
1156
|
};
|
|
969
1157
|
var defaultBlockStore = {
|
|
970
1158
|
getAllBlocks: async () => []
|
|
971
1159
|
};
|
|
972
|
-
var defaultResultStore = {
|
|
973
|
-
getResultsByContentId: async () => [],
|
|
974
|
-
getResultById: async () => void 0,
|
|
975
|
-
getResultsForNote: async () => []
|
|
976
|
-
};
|
|
977
1160
|
var defaultEffortStore = {
|
|
978
1161
|
getAllEfforts: async () => []
|
|
979
1162
|
};
|
|
@@ -1085,32 +1268,31 @@ var QueryService = class {
|
|
|
1085
1268
|
store;
|
|
1086
1269
|
noteStore;
|
|
1087
1270
|
blockStore;
|
|
1088
|
-
resultStore;
|
|
1089
1271
|
effortStore;
|
|
1090
1272
|
staticNoteStore;
|
|
1091
1273
|
staticBlockStore;
|
|
1092
|
-
constructor(
|
|
1093
|
-
if (
|
|
1094
|
-
const stores =
|
|
1095
|
-
this.store = stores.
|
|
1274
|
+
constructor(storesOrEventStore, noteStore, blockStore, effortStore, staticNoteStore, staticBlockStore) {
|
|
1275
|
+
if (storesOrEventStore && typeof storesOrEventStore === "object" && ("eventStore" in storesOrEventStore || "noteStore" in storesOrEventStore || "blockStore" in storesOrEventStore || "effortStore" in storesOrEventStore || "staticNoteStore" in storesOrEventStore || "staticBlockStore" in storesOrEventStore)) {
|
|
1276
|
+
const stores = storesOrEventStore;
|
|
1277
|
+
this.store = stores.eventStore ?? defaultEventStore;
|
|
1096
1278
|
this.noteStore = stores.noteStore ?? defaultNoteStore;
|
|
1097
1279
|
this.blockStore = stores.blockStore ?? defaultBlockStore;
|
|
1098
|
-
this.resultStore = stores.resultStore ?? defaultResultStore;
|
|
1099
1280
|
this.effortStore = stores.effortStore ?? defaultEffortStore;
|
|
1100
1281
|
this.staticNoteStore = stores.staticNoteStore;
|
|
1101
1282
|
this.staticBlockStore = stores.staticBlockStore;
|
|
1102
1283
|
} else {
|
|
1103
|
-
this.store =
|
|
1284
|
+
this.store = storesOrEventStore ?? defaultEventStore;
|
|
1104
1285
|
this.noteStore = noteStore ?? defaultNoteStore;
|
|
1105
1286
|
this.blockStore = blockStore ?? defaultBlockStore;
|
|
1106
|
-
this.resultStore = resultStore ?? defaultResultStore;
|
|
1107
1287
|
this.effortStore = effortStore ?? defaultEffortStore;
|
|
1108
1288
|
this.staticNoteStore = staticNoteStore;
|
|
1109
1289
|
this.staticBlockStore = staticBlockStore;
|
|
1110
1290
|
}
|
|
1111
1291
|
}
|
|
1292
|
+
/** Windowed flat-fact fetch — the projected view over the event store. */
|
|
1112
1293
|
async getFactsByTimeRange(start, end) {
|
|
1113
|
-
|
|
1294
|
+
const rows = await this.store.getEventsByTimeRange(start, end);
|
|
1295
|
+
return rows.flatMap(projectEventToFacts);
|
|
1114
1296
|
}
|
|
1115
1297
|
async runQuery(raw, options2 = {}) {
|
|
1116
1298
|
const parsed = parseQuery(raw);
|
|
@@ -1134,8 +1316,8 @@ var QueryService = class {
|
|
|
1134
1316
|
}
|
|
1135
1317
|
/**
|
|
1136
1318
|
* Execute a rows query (rows:{…}, #949) — the session results table plane.
|
|
1137
|
-
*
|
|
1138
|
-
*
|
|
1319
|
+
* Reads event rows directly over the unified store (ticket 003): no
|
|
1320
|
+
* WorkoutResult blob parsing; outputType narrowing hits the promoted column.
|
|
1139
1321
|
*/
|
|
1140
1322
|
async runRows(parsed, options2 = {}) {
|
|
1141
1323
|
const empty = { parsed, runs: [] };
|
|
@@ -1157,28 +1339,30 @@ var QueryService = class {
|
|
|
1157
1339
|
if (resultIds.length + blockIds.length + noteIds.length === 0) {
|
|
1158
1340
|
return { ...empty, error: "Rows query needs a scope: result:, block:, or note:." };
|
|
1159
1341
|
}
|
|
1160
|
-
const
|
|
1161
|
-
|
|
1162
|
-
const
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
}
|
|
1168
|
-
for (const
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
let
|
|
1342
|
+
const byResult = /* @__PURE__ */ new Map();
|
|
1343
|
+
const collect = (rows) => {
|
|
1344
|
+
for (const row of rows) {
|
|
1345
|
+
const bucket = byResult.get(row.resultId);
|
|
1346
|
+
if (bucket) bucket.push(row);
|
|
1347
|
+
else byResult.set(row.resultId, [row]);
|
|
1348
|
+
}
|
|
1349
|
+
};
|
|
1350
|
+
for (const id of resultIds) collect(await this.store.getEventsByResult(id));
|
|
1351
|
+
for (const blockContentId of blockIds) collect(await this.store.getEventsByContent(blockContentId));
|
|
1352
|
+
for (const noteId of noteIds) collect(await this.store.getEventsForNote(noteId));
|
|
1353
|
+
let groups = [...byResult.entries()].filter(([, rows]) => rows.length > 0);
|
|
1172
1354
|
if (parsed.last) {
|
|
1173
|
-
|
|
1174
|
-
(
|
|
1355
|
+
groups = groups.filter(
|
|
1356
|
+
([, rows]) => effectiveTimeWindow(rows[0].timestamp, parsed.last, void 0, options2.anchorNow)
|
|
1175
1357
|
);
|
|
1176
1358
|
}
|
|
1177
|
-
|
|
1178
|
-
const runs =
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1359
|
+
groups.sort((a, b) => b[1][0].timestamp - a[1][0].timestamp);
|
|
1360
|
+
const runs = groups.map(([resultId, rows]) => ({
|
|
1361
|
+
resultId,
|
|
1362
|
+
noteId: rows[0].noteId,
|
|
1363
|
+
timestamp: rows[0].timestamp,
|
|
1364
|
+
events: parsed.outputType ? rows.filter((row) => row.outputType === parsed.outputType) : rows
|
|
1365
|
+
})).filter((run) => run.events.length > 0);
|
|
1182
1366
|
return { parsed, runs };
|
|
1183
1367
|
}
|
|
1184
1368
|
/**
|
|
@@ -1367,14 +1551,11 @@ var QueryService = class {
|
|
|
1367
1551
|
};
|
|
1368
1552
|
if (parsed.error) return empty;
|
|
1369
1553
|
if (parsed.join) return this.runJoined(parsed, options2);
|
|
1370
|
-
const
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
const inRange = new Set((await this.store.getFactsByTimeRange(start, end)).map((row) => row.id));
|
|
1376
|
-
candidates = candidates.filter((row) => inRange.has(row.id));
|
|
1377
|
-
}
|
|
1554
|
+
const windowed = options2.rangeStart !== void 0 || options2.rangeEnd !== void 0;
|
|
1555
|
+
const start = options2.rangeStart ?? 0;
|
|
1556
|
+
const end = options2.rangeEnd ?? Number.MAX_SAFE_INTEGER;
|
|
1557
|
+
const eventRows = windowed ? await this.store.getEventsByTimeRange(start, end) : await this.store.scanAll();
|
|
1558
|
+
const candidates = eventRows.flatMap(projectEventToFacts).filter((row) => row.metricKey === parsed.metric);
|
|
1378
1559
|
const touchesTags = parsed.filters.some((f) => f.key === "tags") || parsed.groupBy.includes("tags");
|
|
1379
1560
|
const noteTags = await this.loadNoteTags(candidates, touchesTags);
|
|
1380
1561
|
const matched = this.applyEffortScope(
|
|
@@ -1518,29 +1699,14 @@ var QueryService = class {
|
|
|
1518
1699
|
}
|
|
1519
1700
|
return matched.some((r) => r.effortSlug === void 0) ? matched.filter((r) => r.effortSlug === void 0) : matched;
|
|
1520
1701
|
}
|
|
1521
|
-
/**
|
|
1522
|
-
*
|
|
1523
|
-
*
|
|
1702
|
+
/** Summary facts for one Canonical Metric Key across the given content ids —
|
|
1703
|
+
* the cross-store join source. Reads finalize-written summary rows straight
|
|
1704
|
+
* off the content index (ticket 003: the store is authoritative; the old
|
|
1705
|
+
* freshness re-derivation is moot). One fact row per result × rowKey. */
|
|
1524
1706
|
async deriveMetricFacts(contentIds, metricKey) {
|
|
1525
|
-
const out = [];
|
|
1526
1707
|
const ids = [...new Set(contentIds)];
|
|
1527
|
-
await Promise.all(ids.map(
|
|
1528
|
-
|
|
1529
|
-
for (const result of results) {
|
|
1530
|
-
const facts = normalizeSummaryFacts(result.data.logs ?? [], {
|
|
1531
|
-
noteId: result.noteId,
|
|
1532
|
-
resultId: result.id,
|
|
1533
|
-
segmentId: result.segmentId,
|
|
1534
|
-
segmentVersion: result.segmentVersion,
|
|
1535
|
-
blockContentId,
|
|
1536
|
-
origin: result.origin,
|
|
1537
|
-
pageId: result.pageId,
|
|
1538
|
-
workoutTimestamp: result.createdAt
|
|
1539
|
-
});
|
|
1540
|
-
for (const f of facts) if (f.metricKey === metricKey) out.push(f);
|
|
1541
|
-
}
|
|
1542
|
-
}));
|
|
1543
|
-
return out;
|
|
1708
|
+
const rows = await Promise.all(ids.map((blockContentId) => this.store.getEventsByContent(blockContentId)));
|
|
1709
|
+
return rows.flat().filter((row) => row.grain === "summary").flatMap(projectEventToFacts).filter((f) => f.metricKey === metricKey);
|
|
1544
1710
|
}
|
|
1545
1711
|
/** All content blocks across the journal + static corpus. */
|
|
1546
1712
|
async allContentBlocks() {
|
|
@@ -1580,7 +1746,7 @@ var QueryService = class {
|
|
|
1580
1746
|
const noteTags = /* @__PURE__ */ new Map();
|
|
1581
1747
|
if (!touchesTags) return noteTags;
|
|
1582
1748
|
const noteIds = [...new Set(rows.map((r) => r.noteId))];
|
|
1583
|
-
await Promise.all(noteIds.map(async (id) => noteTags.set(id, await this.
|
|
1749
|
+
await Promise.all(noteIds.map(async (id) => noteTags.set(id, await this.noteStore.getNoteTagLabels(id))));
|
|
1584
1750
|
return noteTags;
|
|
1585
1751
|
}
|
|
1586
1752
|
};
|
|
@@ -1880,13 +2046,13 @@ sum:$metric{} rollup:1w
|
|
|
1880
2046
|
}
|
|
1881
2047
|
|
|
1882
2048
|
// src/version.ts
|
|
1883
|
-
var VERSION = "0.
|
|
1884
|
-
var GIT_SHA = "
|
|
1885
|
-
var BUILD_TIME = "2026-08-
|
|
2049
|
+
var VERSION = "0.7.37";
|
|
2050
|
+
var GIT_SHA = "713c593";
|
|
2051
|
+
var BUILD_TIME = "2026-08-25T00:18:25.714Z";
|
|
1886
2052
|
var SEMVER = {
|
|
1887
|
-
version: "0.
|
|
1888
|
-
gitSha: "
|
|
1889
|
-
buildTime: "2026-08-
|
|
2053
|
+
version: "0.7.37",
|
|
2054
|
+
gitSha: "713c593",
|
|
2055
|
+
buildTime: "2026-08-25T00:18:25.714Z"
|
|
1890
2056
|
};
|
|
1891
2057
|
|
|
1892
2058
|
exports.BUILD_TIME = BUILD_TIME;
|
|
@@ -1945,6 +2111,7 @@ exports.parseFrontmatterProps = parseFrontmatterProps;
|
|
|
1945
2111
|
exports.parseQuery = parseQuery;
|
|
1946
2112
|
exports.parseQueryWidgetSuffix = parseQueryWidgetSuffix;
|
|
1947
2113
|
exports.parseWqlSuffixes = parseWqlSuffixes;
|
|
2114
|
+
exports.projectEventToFacts = projectEventToFacts;
|
|
1948
2115
|
exports.referencedTokens = referencedTokens;
|
|
1949
2116
|
exports.resolveCanonicalMetricKey = resolveCanonicalMetricKey;
|
|
1950
2117
|
exports.resolveDisplayUnit = resolveDisplayUnit;
|
|
@@ -1957,6 +2124,8 @@ exports.staticNotesFromBlocks = staticNotesFromBlocks;
|
|
|
1957
2124
|
exports.staticTagIndexFromBlocks = staticTagIndexFromBlocks;
|
|
1958
2125
|
exports.stripFrontmatter = stripFrontmatter;
|
|
1959
2126
|
exports.substituteTokens = substituteTokens;
|
|
2127
|
+
exports.toEventRows = toEventRows;
|
|
2128
|
+
exports.toSummaryEventRows = toSummaryEventRows;
|
|
1960
2129
|
exports.unknownTokensMessage = unknownTokensMessage;
|
|
1961
2130
|
exports.unknownWidgetTypeMessage = unknownWidgetTypeMessage;
|
|
1962
2131
|
exports.wql = wql;
|