@gscdump/cloudflare 0.21.0 → 0.21.2

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.
Files changed (2) hide show
  1. package/dist/index.mjs +46 -0
  2. package/package.json +6 -6
package/dist/index.mjs CHANGED
@@ -466,6 +466,26 @@ function orderMetricExpr(metric) {
466
466
  case "position": return "SUM(sum_position) / NULLIF(SUM(impressions), 0)";
467
467
  }
468
468
  }
469
+ const DEVICE_SUFFIXES = [
470
+ "desktop",
471
+ "mobile",
472
+ "tablet"
473
+ ];
474
+ function metricExprForSource(metric, source) {
475
+ switch (metric) {
476
+ case "clicks": return `SUM(${source.clicks}) AS clicks`;
477
+ case "impressions": return `SUM(${source.impressions}) AS impressions`;
478
+ case "ctr": return `SUM(${source.clicks}) / NULLIF(SUM(${source.impressions}), 0) AS ctr`;
479
+ case "position": return `SUM(${source.sumPosition}) / NULLIF(SUM(${source.impressions}), 0) AS position`;
480
+ }
481
+ }
482
+ function deviceSource(suffix) {
483
+ return {
484
+ clicks: `clicks_${suffix}`,
485
+ impressions: `impressions_${suffix}`,
486
+ sumPosition: `sum_position_${suffix}`
487
+ };
488
+ }
469
489
  function sqlStringLiteral(value) {
470
490
  return `'${value.replace(/'/g, "''")}'`;
471
491
  }
@@ -515,6 +535,21 @@ function buildEntityDailySparkline(q) {
515
535
  function buildTopNBreakdown(q) {
516
536
  const table = inferTable([q.dimension]);
517
537
  const w = partitionWhere(q);
538
+ if (q.dimension === "device") {
539
+ const metricList = q.metrics.includes(q.orderBy.metric) ? q.metrics : [...q.metrics, q.orderBy.metric];
540
+ const order = `${q.orderBy.metric} ${q.orderBy.dir.toUpperCase()}`;
541
+ let sql = `${DEVICE_SUFFIXES.map((suffix) => {
542
+ const source = deviceSource(suffix);
543
+ const metrics = metricList.map((m) => metricExprForSource(m, source)).join(", ");
544
+ return `SELECT '${suffix.toUpperCase()}' AS device, ${metrics} FROM ${TABLE_PLACEHOLDER} WHERE ${w.clause}`;
545
+ }).join(" UNION ALL ")} ORDER BY ${order} LIMIT ${Math.max(0, Math.floor(q.limit))}`;
546
+ if (q.offset && q.offset > 0) sql += ` OFFSET ${Math.floor(q.offset)}`;
547
+ return {
548
+ table,
549
+ params: DEVICE_SUFFIXES.flatMap(() => w.params),
550
+ sql
551
+ };
552
+ }
518
553
  const col = dimColumn(q.dimension);
519
554
  const metrics = q.metrics.map(metricExpr).join(", ");
520
555
  const order = `${orderMetricExpr(q.orderBy.metric)} ${q.orderBy.dir.toUpperCase()}`;
@@ -547,6 +582,17 @@ function buildSingleRowLookup(q) {
547
582
  function buildMultiSeriesStackedDaily(q) {
548
583
  const table = inferTable([q.seriesDimension]);
549
584
  const w = partitionWhere(q);
585
+ if (q.seriesDimension === "device") {
586
+ const selects = DEVICE_SUFFIXES.map((suffix) => {
587
+ const source = deviceSource(suffix);
588
+ return `SELECT date, '${suffix.toUpperCase()}' AS device, ${metricExprForSource(q.metric, source)} FROM ${TABLE_PLACEHOLDER} WHERE ${w.clause} GROUP BY date`;
589
+ });
590
+ return {
591
+ table,
592
+ params: DEVICE_SUFFIXES.flatMap(() => w.params),
593
+ sql: `${selects.join(" UNION ALL ")} ORDER BY date ASC, device ASC`
594
+ };
595
+ }
550
596
  const col = dimColumn(q.seriesDimension);
551
597
  return {
552
598
  table,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@gscdump/cloudflare",
3
3
  "type": "module",
4
- "version": "0.21.0",
4
+ "version": "0.21.2",
5
5
  "description": "Cloudflare-Workers-flavored helpers for the gscdump analytics stack: AnalyticsEnv binding contract, R2 SigV4 presigner, size-hint HMAC, DuckDB Workers shims, engine factory.",
6
6
  "author": {
7
7
  "name": "Harlan Wilton",
@@ -41,11 +41,11 @@
41
41
  "dependencies": {
42
42
  "@uwdata/flechette": "^2.5.0",
43
43
  "aws4fetch": "^1.0.20",
44
- "@gscdump/contracts": "0.21.0",
45
- "@gscdump/engine-sqlite": "0.21.0",
46
- "gscdump": "0.21.0",
47
- "@gscdump/sdk": "0.21.0",
48
- "@gscdump/engine": "0.21.0"
44
+ "@gscdump/contracts": "0.21.2",
45
+ "@gscdump/engine": "0.21.2",
46
+ "@gscdump/engine-sqlite": "0.21.2",
47
+ "@gscdump/sdk": "0.21.2",
48
+ "gscdump": "0.21.2"
49
49
  },
50
50
  "devDependencies": {
51
51
  "@cloudflare/workers-types": "^4.20260520.1",