@gscdump/engine-duckdb-wasm 0.40.2 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -10
- package/dist/index.d.mts +23 -45
- package/dist/index.mjs +3 -65
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -23,19 +23,14 @@ import {
|
|
|
23
23
|
attachParquetUrlTables,
|
|
24
24
|
bootDuckDBWasm,
|
|
25
25
|
createInsightRunner,
|
|
26
|
-
resolveWindow,
|
|
27
|
-
scopeFor,
|
|
28
|
-
strikingMomentum,
|
|
29
26
|
} from '@gscdump/engine-duckdb-wasm'
|
|
30
27
|
|
|
31
28
|
const { db, conn } = await bootDuckDBWasm()
|
|
32
29
|
await attachParquetUrlTables(conn, { tables: [{ name: 'queries', url: '/r2/queries.parquet' }] })
|
|
33
30
|
|
|
34
|
-
const runner = createInsightRunner({ db, conn })
|
|
35
|
-
const
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
const rows = await strikingMomentum(runner, { ...scope, limit: 50 })
|
|
31
|
+
const runner = await createInsightRunner({ db, conn })
|
|
32
|
+
const client = await runner.client
|
|
33
|
+
const rows = await client.query('SELECT query, clicks, impressions FROM queries LIMIT 50')
|
|
39
34
|
```
|
|
40
35
|
|
|
41
36
|
## Browser Parquet Attachment Strategy
|
|
@@ -73,7 +68,6 @@ instead.
|
|
|
73
68
|
- `createInsightRunner({ db, conn })` — drizzle-orm handle for typed `.select()` / window functions, with `sql\`...\`` raw escape hatch.
|
|
74
69
|
- `bootDuckDBWasm()` / `attachParquetTables()` / `attachParquetUrlTables()` / `attachSingleTable()` / `createBrowserAnalysisRuntime()` / `createDuckDBBundlesFromBase()` / `listAttachedTables()` — browser runtime primitives.
|
|
75
70
|
- `attachOpfsParquetTables()` / `readOpfsSnapshotFile()` / `estimateOpfsStorage()` / `requestPersistentStorage()` / `clearOpfsSnapshotCache()` — OPFS-backed parquet cache.
|
|
76
|
-
- `strikingMomentum(runner, options)` — first-class browser insight.
|
|
77
71
|
- `scopeFor(table, { siteId, window })` / `mergeScope()` — tenant scope predicates.
|
|
78
72
|
- `pages` / `queries` / `page_queries` / `countries` / `dates` / `hourly_pages` / `schema` — drizzle schema mirroring `gscdump/analytics` `SCHEMAS`. Drift fails loudly at module load.
|
|
79
73
|
- `compileArchetypeSql()` / `tableForArchetype()` — archetype query compilation.
|
|
@@ -83,7 +77,7 @@ instead.
|
|
|
83
77
|
## Related
|
|
84
78
|
|
|
85
79
|
- [`@gscdump/engine`](../engine) — Storage contracts + dialect-neutral resolver.
|
|
86
|
-
- [`@gscdump/analysis`](../analysis) —
|
|
80
|
+
- [`@gscdump/analysis`](../analysis) — Portable analyzer registry and browser dispatch.
|
|
87
81
|
- [`@gscdump/engine-sqlite`](../engine-sqlite) — SQLite / D1 counterpart.
|
|
88
82
|
|
|
89
83
|
## License
|
package/dist/index.d.mts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Assume, DrizzleConfig, entityKind } from "drizzle-orm";
|
|
2
2
|
import { PgAsyncDatabase, PgAsyncPreparedQuery, PgAsyncSession, PgDialect, PgQueryResultHKT } from "drizzle-orm/pg-core";
|
|
3
3
|
import { AnyRelations, EmptyRelations, ExtractTablesWithRelations, Schema as Schema$1 } from "drizzle-orm/relations";
|
|
4
|
-
import { DrizzleSchema as Schema, countries, dates, drizzleSchema as schema, hourly_pages, page_queries, pages, queries } from "@gscdump/engine/schema";
|
|
5
4
|
import { ScopedRunnerOptions, TableScope } from "@gscdump/engine/scope";
|
|
5
|
+
import { DrizzleSchema as Schema, countries, dates, drizzleSchema as schema, hourly_pages, page_queries, pages, queries } from "@gscdump/engine/schema";
|
|
6
6
|
import { AnalyzerRegistry } from "@gscdump/engine/analyzer";
|
|
7
7
|
import { Result } from "gscdump/result";
|
|
8
8
|
import { ComparisonMode, ResolveWindowOptions, ResolvedWindow, WindowPreset, resolveWindow } from "@gscdump/engine/period";
|
|
@@ -41,49 +41,6 @@ interface DuckDBWasmDrizzleDatabase<TSchema extends Schema$1 = Record<string, ne
|
|
|
41
41
|
$client: Promise<DuckDBWasmClient>;
|
|
42
42
|
}
|
|
43
43
|
declare function drizzle<TSchema extends Schema$1 = Record<string, never>, TRelations extends AnyRelations = SchemaRelations<TSchema>>(client: Promise<DuckDBWasmClient> | DuckDBWasmClient, config?: DrizzleConfig<TSchema, TRelations>): DuckDBWasmDrizzleDatabase<TSchema, TRelations>;
|
|
44
|
-
interface InsightRunnerOptions {
|
|
45
|
-
db: AsyncDuckDB;
|
|
46
|
-
conn: AsyncDuckDBConnection;
|
|
47
|
-
logger?: boolean;
|
|
48
|
-
}
|
|
49
|
-
interface InsightRunner {
|
|
50
|
-
db: DuckDBWasmDrizzleDatabase<Schema>;
|
|
51
|
-
client: Promise<DuckDBWasmClient>;
|
|
52
|
-
close: () => Promise<void>;
|
|
53
|
-
}
|
|
54
|
-
declare function createInsightRunner(opts: InsightRunnerOptions): Promise<InsightRunner>;
|
|
55
|
-
/**
|
|
56
|
-
* Build a per-table predicate set from {siteId, window}. The returned
|
|
57
|
-
* `wherePredicates` composes with user-level filters via `mergeScope`.
|
|
58
|
-
*
|
|
59
|
-
* Note: the current SCHEMAS don't include `site_id` on any table (snapshots
|
|
60
|
-
* are already per-site), so `siteId` is a no-op for now — kept in the API
|
|
61
|
-
* so consumers can add the predicate without an interface change when
|
|
62
|
-
* multi-site snapshots land.
|
|
63
|
-
*/
|
|
64
|
-
declare const scopeFor: (table: "pages" | "queries" | "countries" | "page_queries" | "dates" | "search_appearance" | "search_appearance_pages" | "search_appearance_queries" | "search_appearance_page_queries" | "hourly_pages", opts: ScopedRunnerOptions) => TableScope, mergeScope: typeof import("@gscdump/engine/scope").mergeScope;
|
|
65
|
-
interface StrikingMomentumOptions {
|
|
66
|
-
/** Anchor date (YYYY-MM-DD). Defaults to today. */
|
|
67
|
-
anchor?: string;
|
|
68
|
-
/** Width of each window in days. Default 90. */
|
|
69
|
-
windowDays?: number;
|
|
70
|
-
/** Minimum impressions in the prior window for a row to qualify. Default 10. */
|
|
71
|
-
minPriorImpressions?: number;
|
|
72
|
-
/** Minimum impressions in the recent window. Default 50. */
|
|
73
|
-
minRecentImpressions?: number;
|
|
74
|
-
/** Result limit. Default 20. */
|
|
75
|
-
limit?: number;
|
|
76
|
-
}
|
|
77
|
-
interface StrikingMomentumRow {
|
|
78
|
-
query: string;
|
|
79
|
-
url: string;
|
|
80
|
-
recent_impr: number;
|
|
81
|
-
recent_pos: number;
|
|
82
|
-
prior_impr: number;
|
|
83
|
-
prior_pos: number;
|
|
84
|
-
momentum_score: number;
|
|
85
|
-
}
|
|
86
|
-
declare function strikingMomentum(runner: InsightRunner, opts?: StrikingMomentumOptions): Promise<StrikingMomentumRow[]>;
|
|
87
44
|
/** A parquet data file to materialise into OPFS. */
|
|
88
45
|
interface OpfsParquetFile {
|
|
89
46
|
/** Same-origin URL carrying a signed size hint + short-lived access token. */
|
|
@@ -309,6 +266,27 @@ declare function overlayViewBody(args: {
|
|
|
309
266
|
overlaySelect: string | null;
|
|
310
267
|
materializeLake?: boolean;
|
|
311
268
|
}): string | null;
|
|
269
|
+
interface InsightRunnerOptions {
|
|
270
|
+
db: AsyncDuckDB;
|
|
271
|
+
conn: AsyncDuckDBConnection;
|
|
272
|
+
logger?: boolean;
|
|
273
|
+
}
|
|
274
|
+
interface InsightRunner {
|
|
275
|
+
db: DuckDBWasmDrizzleDatabase<Schema>;
|
|
276
|
+
client: Promise<DuckDBWasmClient>;
|
|
277
|
+
close: () => Promise<void>;
|
|
278
|
+
}
|
|
279
|
+
declare function createInsightRunner(opts: InsightRunnerOptions): Promise<InsightRunner>;
|
|
280
|
+
/**
|
|
281
|
+
* Build a per-table predicate set from {siteId, window}. The returned
|
|
282
|
+
* `wherePredicates` composes with user-level filters via `mergeScope`.
|
|
283
|
+
*
|
|
284
|
+
* Note: the current SCHEMAS don't include `site_id` on any table (snapshots
|
|
285
|
+
* are already per-site), so `siteId` is a no-op for now — kept in the API
|
|
286
|
+
* so consumers can add the predicate without an interface change when
|
|
287
|
+
* multi-site snapshots land.
|
|
288
|
+
*/
|
|
289
|
+
declare const scopeFor: (table: "pages" | "queries" | "countries" | "page_queries" | "dates" | "search_appearance" | "search_appearance_pages" | "search_appearance_queries" | "search_appearance_page_queries" | "hourly_pages", opts: ScopedRunnerOptions) => TableScope, mergeScope: typeof import("@gscdump/engine/scope").mergeScope;
|
|
312
290
|
interface QueryResult {
|
|
313
291
|
rows: Record<string, unknown>[];
|
|
314
292
|
queryMs: number;
|
|
@@ -514,4 +492,4 @@ declare function createBrowserAnalysisRuntime(boot: DuckDBWasmBootResult, option
|
|
|
514
492
|
version?: number | string;
|
|
515
493
|
attachedTables?: readonly string[];
|
|
516
494
|
}): BrowserAnalysisRuntime;
|
|
517
|
-
export { type AnalyzeResult, type AttachOpfsTablesOptions, type AttachParquetTablesOptions, type AttachParquetUrlTablesOptions, type AttachedTablesHandle, type BootDuckDBWasmOptions, type BrowserAnalysisRuntime, BrowserAttachBudgetExceededError, type BrowserAttachError, type BrowserParquetFile, type BrowserParquetTable, type BrowserParquetUrlTable, type ComparisonMode, type CompiledArchetypeSql, type DuckDBWasmBootResult, type DuckDBWasmClient, DuckDBWasmDatabase, type DuckDBWasmDrizzleDatabase, type InsightRunner, type InsightRunnerOptions, type OpfsAttachTiming, type OpfsAttachTimingStage, type OpfsAttachedHandle, type OpfsFileProgress, type OpfsParquetFile, type OpfsParquetTable, OpfsQuotaExceededError, type QueryResult, type ResolveWindowOptions, type ResolvedWindow, type Schema, type ScopedRunnerOptions, type
|
|
495
|
+
export { type AnalyzeResult, type AttachOpfsTablesOptions, type AttachParquetTablesOptions, type AttachParquetUrlTablesOptions, type AttachedTablesHandle, type BootDuckDBWasmOptions, type BrowserAnalysisRuntime, BrowserAttachBudgetExceededError, type BrowserAttachError, type BrowserParquetFile, type BrowserParquetTable, type BrowserParquetUrlTable, type ComparisonMode, type CompiledArchetypeSql, type DuckDBWasmBootResult, type DuckDBWasmClient, DuckDBWasmDatabase, type DuckDBWasmDrizzleDatabase, type InsightRunner, type InsightRunnerOptions, type OpfsAttachTiming, type OpfsAttachTimingStage, type OpfsAttachedHandle, type OpfsFileProgress, type OpfsParquetFile, type OpfsParquetTable, OpfsQuotaExceededError, type QueryResult, type ResolveWindowOptions, type ResolvedWindow, type Schema, type ScopedRunnerOptions, type TableScope, type WindowPreset, attachOpfsParquetTables, attachParquetTables, attachParquetUrlTables, attachParquetUrlTablesResult, bootDuckDBWasm, browserAttachErrors, clearOpfsSnapshotCache, compileArchetypeSql, countries, createBrowserAnalysisRuntime, createClient, createInsightRunner, dates, drizzle, estimateOpfsStorage, hourly_pages, isBrowserAttachError, mergeScope, overlayViewBody, page_queries, pages, queries, readOpfsSnapshotFile, requestPersistentStorage, resolveWindow, schema, scopeFor, tableForArchetype };
|
package/dist/index.mjs
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { arrowToRows } from "@gscdump/engine/arrow";
|
|
2
|
-
import { DefaultLogger, NoopLogger, entityKind
|
|
2
|
+
import { DefaultLogger, NoopLogger, entityKind } from "drizzle-orm";
|
|
3
3
|
import { PgAsyncDatabase, PgAsyncPreparedQuery, PgAsyncSession, PgDialect } from "drizzle-orm/pg-core";
|
|
4
4
|
import { buildRelations } from "drizzle-orm/relations";
|
|
5
|
-
import { toIsoDate } from "gscdump/dates";
|
|
6
|
-
import { countries, dates, drizzleSchema as schema, hourly_pages, page_queries, pages, queries } from "@gscdump/engine/schema";
|
|
7
5
|
import { createScopedHelpers } from "@gscdump/engine/scope";
|
|
6
|
+
import { countries, dates, drizzleSchema as schema, hourly_pages, page_queries, pages, queries } from "@gscdump/engine/schema";
|
|
8
7
|
import { runAnalyzerFromSource } from "@gscdump/engine/analyzer";
|
|
9
8
|
import { pgResolverAdapter } from "@gscdump/engine/resolver";
|
|
10
9
|
import { createAttachedTableSource } from "@gscdump/engine/source";
|
|
@@ -442,67 +441,6 @@ function drizzle(client, config = {}) {
|
|
|
442
441
|
db.$client = clientPromise;
|
|
443
442
|
return db;
|
|
444
443
|
}
|
|
445
|
-
async function strikingMomentum(runner, opts = {}) {
|
|
446
|
-
const windowDays = opts.windowDays ?? 90;
|
|
447
|
-
const anchor = opts.anchor ?? toIsoDate(/* @__PURE__ */ new Date());
|
|
448
|
-
const minPrior = opts.minPriorImpressions ?? 10;
|
|
449
|
-
const minRecent = opts.minRecentImpressions ?? 50;
|
|
450
|
-
const limit = opts.limit ?? 20;
|
|
451
|
-
const windowExpr = sql`
|
|
452
|
-
WITH pk AS (
|
|
453
|
-
SELECT
|
|
454
|
-
query,
|
|
455
|
-
url,
|
|
456
|
-
${page_queries.date} AS date,
|
|
457
|
-
${page_queries.impressions} AS impressions,
|
|
458
|
-
${page_queries.sum_position} AS sum_position,
|
|
459
|
-
CASE
|
|
460
|
-
WHEN ${page_queries.date} >= (DATE ${sql.raw(`'${anchor}'`)} - INTERVAL ${sql.raw(`${windowDays}`)} DAY)
|
|
461
|
-
THEN 'recent' ELSE 'prior'
|
|
462
|
-
END AS period
|
|
463
|
-
FROM ${page_queries}
|
|
464
|
-
WHERE ${page_queries.date} >= (DATE ${sql.raw(`'${anchor}'`)} - INTERVAL ${sql.raw(`${windowDays * 2}`)} DAY)
|
|
465
|
-
AND ${page_queries.date} < (DATE ${sql.raw(`'${anchor}'`)} + INTERVAL 1 DAY)
|
|
466
|
-
),
|
|
467
|
-
agg AS (
|
|
468
|
-
SELECT
|
|
469
|
-
query, url, period,
|
|
470
|
-
SUM(impressions) AS impr,
|
|
471
|
-
SUM(sum_position) / NULLIF(SUM(impressions), 0) + 1 AS weighted_pos
|
|
472
|
-
FROM pk
|
|
473
|
-
GROUP BY query, url, period
|
|
474
|
-
),
|
|
475
|
-
paired AS (
|
|
476
|
-
SELECT
|
|
477
|
-
query, url,
|
|
478
|
-
MAX(CASE WHEN period = 'recent' THEN impr END) AS recent_impr,
|
|
479
|
-
MAX(CASE WHEN period = 'recent' THEN weighted_pos END) AS recent_pos,
|
|
480
|
-
MAX(CASE WHEN period = 'prior' THEN impr END) AS prior_impr,
|
|
481
|
-
MAX(CASE WHEN period = 'prior' THEN weighted_pos END) AS prior_pos
|
|
482
|
-
FROM agg
|
|
483
|
-
GROUP BY query, url
|
|
484
|
-
),
|
|
485
|
-
best AS (
|
|
486
|
-
SELECT
|
|
487
|
-
query, url, recent_impr, recent_pos, prior_impr, prior_pos,
|
|
488
|
-
ROW_NUMBER() OVER (PARTITION BY query ORDER BY recent_impr DESC NULLS LAST) AS rn
|
|
489
|
-
FROM paired
|
|
490
|
-
WHERE prior_impr >= ${minPrior} AND recent_impr >= ${minRecent}
|
|
491
|
-
)
|
|
492
|
-
SELECT
|
|
493
|
-
query, url,
|
|
494
|
-
recent_impr, recent_pos, prior_impr, prior_pos,
|
|
495
|
-
(prior_pos - recent_pos)
|
|
496
|
-
* LN(recent_impr + 1)
|
|
497
|
-
* CASE WHEN recent_pos BETWEEN 8 AND 20 THEN 1.5 ELSE 1.0 END
|
|
498
|
-
AS momentum_score
|
|
499
|
-
FROM best
|
|
500
|
-
WHERE rn = 1
|
|
501
|
-
ORDER BY momentum_score DESC NULLS LAST
|
|
502
|
-
LIMIT ${limit}
|
|
503
|
-
`;
|
|
504
|
-
return await runner.db.execute(windowExpr);
|
|
505
|
-
}
|
|
506
444
|
function createOpfsHandleRegistry(backend) {
|
|
507
445
|
const entries = /* @__PURE__ */ new Map();
|
|
508
446
|
const pending = /* @__PURE__ */ new Map();
|
|
@@ -1616,4 +1554,4 @@ function createBrowserAnalysisRuntime(boot, options = {}) {
|
|
|
1616
1554
|
}
|
|
1617
1555
|
};
|
|
1618
1556
|
}
|
|
1619
|
-
export { BrowserAttachBudgetExceededError, DuckDBWasmDatabase, OpfsQuotaExceededError, attachOpfsParquetTables, attachParquetTables, attachParquetUrlTables, attachParquetUrlTablesResult, bootDuckDBWasm, browserAttachErrors, clearOpfsSnapshotCache, compileArchetypeSql, countries, createBrowserAnalysisRuntime, createClient, createInsightRunner, dates, drizzle, estimateOpfsStorage, hourly_pages, isBrowserAttachError, mergeScope, overlayViewBody, page_queries, pages, queries, readOpfsSnapshotFile, requestPersistentStorage, resolveWindow, schema, scopeFor,
|
|
1557
|
+
export { BrowserAttachBudgetExceededError, DuckDBWasmDatabase, OpfsQuotaExceededError, attachOpfsParquetTables, attachParquetTables, attachParquetUrlTables, attachParquetUrlTablesResult, bootDuckDBWasm, browserAttachErrors, clearOpfsSnapshotCache, compileArchetypeSql, countries, createBrowserAnalysisRuntime, createClient, createInsightRunner, dates, drizzle, estimateOpfsStorage, hourly_pages, isBrowserAttachError, mergeScope, overlayViewBody, page_queries, pages, queries, readOpfsSnapshotFile, requestPersistentStorage, resolveWindow, schema, scopeFor, tableForArchetype };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gscdump/engine-duckdb-wasm",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "1.0.1",
|
|
5
5
|
"description": "DuckDB-WASM engine adapter for @gscdump/analysis — typed browser analytics against parquet via R2.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Harlan Wilton",
|
|
@@ -33,10 +33,10 @@
|
|
|
33
33
|
"dist"
|
|
34
34
|
],
|
|
35
35
|
"engines": {
|
|
36
|
-
"node": ">=
|
|
36
|
+
"node": ">=22"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
|
-
"@duckdb/duckdb-wasm": "^1.
|
|
39
|
+
"@duckdb/duckdb-wasm": "^1.33.1-dev57.0"
|
|
40
40
|
},
|
|
41
41
|
"peerDependenciesMeta": {
|
|
42
42
|
"@duckdb/duckdb-wasm": {
|
|
@@ -45,12 +45,12 @@
|
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
47
|
"drizzle-orm": "1.0.0-rc.3",
|
|
48
|
-
"gscdump": "0.
|
|
49
|
-
"@gscdump/engine": "0.
|
|
50
|
-
"
|
|
48
|
+
"@gscdump/contracts": "^1.0.1",
|
|
49
|
+
"@gscdump/engine": "^1.0.1",
|
|
50
|
+
"gscdump": "^1.0.1"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
|
-
"@duckdb/duckdb-wasm": "
|
|
53
|
+
"@duckdb/duckdb-wasm": "1.33.1-dev57.0",
|
|
54
54
|
"@vitest/browser": "^4.1.10",
|
|
55
55
|
"@vitest/browser-playwright": "^4.1.10",
|
|
56
56
|
"playwright": "^1.61.1",
|