From a19786d813be7055f426a0a47ca645a2bff3c2b5 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 16 Sep 2026 02:21:42 +0000 Subject: [PATCH] =?UTF-8?q?=E2=9A=99=EF=B8=8F=20Engine:=20Pre-computed=20H?= =?UTF-8?q?ashtable=20Column=20Indexing=20for=20PostHog=20API=20Parsing?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: alehar9320 <5390430+alehar9320@users.noreply.github.com> --- .Jules/engine.md | 6 +++++ src/utils/visit-stats.test.ts | 33 ++++++++++++++++++++++- src/utils/visit-stats.ts | 51 ++++++++++++++++++++++------------- 3 files changed, 70 insertions(+), 20 deletions(-) diff --git a/.Jules/engine.md b/.Jules/engine.md index a7eaba32..6889c6a4 100644 --- a/.Jules/engine.md +++ b/.Jules/engine.md @@ -29,3 +29,9 @@ - **Edge Memory & Performance:** Refactored `splitReleaseBody` in `src/utils/github-releases.ts` and `toVisitorReleaseBody` in `src/utils/visitor-changelog.ts` to use pointer-based line scanning (`indexOf('\n', startPos)`), eliminating dynamic `body.split('\n')` string array allocations during SSR and API execution. - **Sentence Counting Optimization:** Refactored `sentenceCount` in `src/utils/release-summary.ts` from regex lookbehind `.split(/(?<=[.!?])\s+/)` into a single-pass character scanning loop. Added whitespace-aware sentence boundary detection to safely ignore dots inside version strings (`2026.08.15.1714`). - **Verification:** Added Vitest unit test cases across `release-summary.test.ts`, `visitor-changelog.test.ts`, and `github-releases.test.ts` covering version numbers, CRLF line endings, multiple trailing punctuation, and whitespace handling. + +## 2025-06-18 - Pre-Computed Hashtable Indexing for Tabular API Column Parsing + +- **Edge Performance:** Pre-computed a `Record` column lookup map in `parseVisitGlance` (`src/utils/visit-stats.ts`) prior to row extraction from PostHog HogQL API results. +- **O(1) Property Lookups:** Replaced repeated $O(N)$ `columns.indexOf(key)` scans across 12 metric fields with $O(1)$ constant-time property lookups on `columnIndexMap`. +- **Verification:** Added Vitest unit tests in `src/utils/visit-stats.test.ts` to confirm correct metric parsing with custom header index orderings and fallback behavior. diff --git a/src/utils/visit-stats.test.ts b/src/utils/visit-stats.test.ts index b6051e21..7e98e9b3 100644 --- a/src/utils/visit-stats.test.ts +++ b/src/utils/visit-stats.test.ts @@ -87,7 +87,38 @@ describe('parseVisitGlance', () => { expect(glance?.uniqueVisitorsYoY).toBeNull(); }); - it('reads a column-ordered array row', () => { + it('reads a column-ordered array row with custom header ordering via hashtable lookup', () => { + const glance = parseVisitGlance({ + columns: [ + 'unique_visitors', + 'pageviews', + 'first_seen', + 'unique_visitors_7d', + 'pageviews_7d', + 'unique_visitors_1d', + 'unique_visitors_1d_prev', + 'unique_visitors_7d_prev', + 'unique_visitors_30d', + 'unique_visitors_30d_prev', + 'unique_visitors_365d', + 'unique_visitors_365d_prev', + ], + results: [[12, 94, '2026-08-14T07:03:00.000Z', 8, 20, 5, 4, 8, 10, 5, 20, 10]], + }); + expect(glance).toEqual({ + pageviews: 94, + uniqueVisitors: 12, + firstSeen: '2026-08-14T07:03:00.000Z', + pageviews7d: 20, + uniqueVisitors7d: 8, + uniqueVisitorsDoD: 25, + uniqueVisitorsWoW: 0, + uniqueVisitorsMoM: 100, + uniqueVisitorsYoY: 100, + }); + }); + + it('reads a column-ordered array row with standard column headers', () => { const glance = parseVisitGlance({ columns: ['pageviews', 'unique_visitors', 'first_seen', 'pageviews_7d', 'unique_visitors_7d'], results: [[94, 12, '2026-08-14T07:03:00.000Z', 20, 8]], diff --git a/src/utils/visit-stats.ts b/src/utils/visit-stats.ts index 17e005d0..3b233caf 100644 --- a/src/utils/visit-stats.ts +++ b/src/utils/visit-stats.ts @@ -47,16 +47,16 @@ function asIsoTimestamp(raw: unknown): string | null { function valueFromRow( row: unknown, - columns: string[] | undefined, + columnIndexMap: Record | undefined, key: string, index: number ): unknown { if (row && typeof row === 'object' && !Array.isArray(row) && key in row) { return (row as Record)[key]; } - if (Array.isArray(row) && columns) { - const colIndex = columns.indexOf(key); - if (colIndex >= 0) return row[colIndex]; + if (Array.isArray(row) && columnIndexMap) { + const colIndex = columnIndexMap[key]; + if (colIndex !== undefined && colIndex >= 0) return row[colIndex]; } if (Array.isArray(row)) return row[index]; return undefined; @@ -76,26 +76,39 @@ export function parseVisitGlance(payload: unknown): VisitGlance | null { if (!Array.isArray(results) || results.length === 0) return null; const columns = (payload as { columns?: unknown }).columns; - const columnNames = Array.isArray(columns) - ? columns.filter((c): c is string => typeof c === 'string') - : undefined; + let columnIndexMap: Record | undefined; + if (Array.isArray(columns)) { + columnIndexMap = {}; + for (let i = 0; i < columns.length; i++) { + const col = columns[i]; + if (typeof col === 'string') { + columnIndexMap[col] = i; + } + } + } const row = results[0]; - const pageviews = asFiniteNumber(valueFromRow(row, columnNames, 'pageviews', 0)); - const uniqueVisitors = asFiniteNumber(valueFromRow(row, columnNames, 'unique_visitors', 1)); - const firstSeen = asIsoTimestamp(valueFromRow(row, columnNames, 'first_seen', 2)); - const pageviews7d = asFiniteNumber(valueFromRow(row, columnNames, 'pageviews_7d', 3)); - const uniqueVisitors7d = asFiniteNumber(valueFromRow(row, columnNames, 'unique_visitors_7d', 4)); - const unique1d = asFiniteNumber(valueFromRow(row, columnNames, 'unique_visitors_1d', 5)); - const unique1dPrev = asFiniteNumber(valueFromRow(row, columnNames, 'unique_visitors_1d_prev', 6)); - const unique7dPrev = asFiniteNumber(valueFromRow(row, columnNames, 'unique_visitors_7d_prev', 7)); - const unique30d = asFiniteNumber(valueFromRow(row, columnNames, 'unique_visitors_30d', 8)); + const pageviews = asFiniteNumber(valueFromRow(row, columnIndexMap, 'pageviews', 0)); + const uniqueVisitors = asFiniteNumber(valueFromRow(row, columnIndexMap, 'unique_visitors', 1)); + const firstSeen = asIsoTimestamp(valueFromRow(row, columnIndexMap, 'first_seen', 2)); + const pageviews7d = asFiniteNumber(valueFromRow(row, columnIndexMap, 'pageviews_7d', 3)); + const uniqueVisitors7d = asFiniteNumber( + valueFromRow(row, columnIndexMap, 'unique_visitors_7d', 4) + ); + const unique1d = asFiniteNumber(valueFromRow(row, columnIndexMap, 'unique_visitors_1d', 5)); + const unique1dPrev = asFiniteNumber( + valueFromRow(row, columnIndexMap, 'unique_visitors_1d_prev', 6) + ); + const unique7dPrev = asFiniteNumber( + valueFromRow(row, columnIndexMap, 'unique_visitors_7d_prev', 7) + ); + const unique30d = asFiniteNumber(valueFromRow(row, columnIndexMap, 'unique_visitors_30d', 8)); const unique30dPrev = asFiniteNumber( - valueFromRow(row, columnNames, 'unique_visitors_30d_prev', 9) + valueFromRow(row, columnIndexMap, 'unique_visitors_30d_prev', 9) ); - const unique365d = asFiniteNumber(valueFromRow(row, columnNames, 'unique_visitors_365d', 10)); + const unique365d = asFiniteNumber(valueFromRow(row, columnIndexMap, 'unique_visitors_365d', 10)); const unique365dPrev = asFiniteNumber( - valueFromRow(row, columnNames, 'unique_visitors_365d_prev', 11) + valueFromRow(row, columnIndexMap, 'unique_visitors_365d_prev', 11) ); if (