@adobe/spacecat-shared-athena-client 1.2.1 → 1.2.3

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/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ # [@adobe/spacecat-shared-athena-client-v1.2.3](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-athena-client-v1.2.2...@adobe/spacecat-shared-athena-client-v1.2.3) (2025-07-28)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * introduce filter on traffic type ([#882](https://github.com/adobe/spacecat-shared/issues/882)) ([df08c60](https://github.com/adobe/spacecat-shared/commit/df08c6066206ba43582104b6be6a6622259cbafc))
7
+
8
+ # [@adobe/spacecat-shared-athena-client-v1.2.2](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-athena-client-v1.2.1...@adobe/spacecat-shared-athena-client-v1.2.2) (2025-07-25)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * switch to js template ([#876](https://github.com/adobe/spacecat-shared/issues/876)) ([4e843c6](https://github.com/adobe/spacecat-shared/commit/4e843c66a0d5b0d7d8652c03bb184e9f4253e4ea))
14
+
1
15
  # [@adobe/spacecat-shared-athena-client-v1.2.1](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-athena-client-v1.2.0...@adobe/spacecat-shared-athena-client-v1.2.1) (2025-07-24)
2
16
 
3
17
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adobe/spacecat-shared-athena-client",
3
- "version": "1.2.1",
3
+ "version": "1.2.3",
4
4
  "description": "Shared modules of the Spacecat Services - AWS Athena Client",
5
5
  "type": "module",
6
6
  "engines": {
@@ -9,33 +9,35 @@
9
9
  * OF ANY KIND, either express or implied. See the License for the specific language
10
10
  * governing permissions and limitations under the License.
11
11
  */
12
- import { getStaticContent, getDateRanges } from '@adobe/spacecat-shared-utils';
13
- import path from 'path';
14
- import { fileURLToPath } from 'url';
15
-
16
- const currentFile = fileURLToPath(import.meta.url);
17
- const currentDir = path.dirname(currentFile);
18
-
19
- const TRAFFIC_ANALYSIS_PATH = path.resolve(currentDir, '../../static/queries/traffic-analysis.sql.tpl');
12
+ import { getDateRanges } from '@adobe/spacecat-shared-utils';
13
+ import { getTrafficAnalysisTemplate } from './traffic-analysis-template.js';
20
14
 
21
15
  /**
22
16
  * Loads the traffic analysis query template and applies placeholders.
23
17
  * @param {Object} placeholders - Key-value pairs to replace in the query template.
24
18
  * @param {Object} log - Logger (optional)
25
- * @returns {Promise<string|null>} The templated SQL string or null on error.
19
+ * @returns {string} The templated SQL string.
26
20
  */
27
- export async function getTrafficAnalysisQuery(placeholders = {}) {
28
- return getStaticContent(placeholders, TRAFFIC_ANALYSIS_PATH);
21
+ export function getTrafficAnalysisQuery(placeholders = {}) {
22
+ return getTrafficAnalysisTemplate(placeholders);
29
23
  }
30
24
 
31
25
  /**
32
- * Scans the query template and returns a sorted array of unique placeholder (strings).
33
- * @returns {Promise<string[]>} Array of unique placeholder keys found in the template.
26
+ * Returns a sorted array of unique placeholder keys used in the template.
27
+ * @returns {string[]} Array of unique placeholder keys found in the template.
34
28
  */
35
- export async function getTrafficAnalysisQueryPlaceholders() {
36
- const raw = await getStaticContent({}, TRAFFIC_ANALYSIS_PATH);
37
- const matches = raw.match(/{{\s*([\w]+)\s*}}/g);
38
- return [...new Set((matches).map((m) => m.replace(/{{\s*|\s*}}/g, '')))].sort();
29
+ export function getTrafficAnalysisQueryPlaceholders() {
30
+ // Return the known placeholders used in the template
31
+ return [
32
+ 'dimensionColumns',
33
+ 'dimensionColumnsPrefixed',
34
+ 'groupBy',
35
+ 'pageTypeCase',
36
+ 'siteId',
37
+ 'tableName',
38
+ 'temporalCondition',
39
+ 'trfTypeCondition',
40
+ ];
39
41
  }
40
42
 
41
43
  /**
@@ -66,11 +68,12 @@ export function buildPageTypeCase(pageTypes, column) {
66
68
  * @param {number} params.week - The ISO week number (1–53).
67
69
  * @param {number} params.year - The year (e.g. 2025).
68
70
  * @param {string} params.siteId - UUID of the site.
69
- * @param {string[]} [params.dimensions- Dimensions to group by (e.g. ['utm_campaign', 'device']).
71
+ * @param {string[]} [params.dimensions] - Dimensions to group by (e.g. ['utm_campaign', 'device']).
70
72
  * @param {string} params.tableName - The name of the source table.
71
- * @param {string} params.pageTypeMatchColumn - The pageTypeMatchColumn of the source table.
73
+ * @param {string} params.pageTypeMatchColumn - The pageTypeMatchColumn of the source table.
72
74
  * @param {Object|null} [params.pageTypes=null] - Optional pageType rules for CASE generation.
73
- *
75
+ * @param {string[]|null} [params.trfTypes] - Traffic type to filter by before
76
+ * grouping (e.g ['paid']).
74
77
  * @returns {Object} Template values for SQL generation.
75
78
  */
76
79
  export function getTrafficAnalysisQueryPlaceholdersFilled({
@@ -81,6 +84,7 @@ export function getTrafficAnalysisQueryPlaceholdersFilled({
81
84
  tableName,
82
85
  pageTypes = null,
83
86
  pageTypeMatchColumn = 'path',
87
+ trfTypes = null,
84
88
  }) {
85
89
  if (!week || !year || !siteId || !tableName) {
86
90
  throw new Error('Missing required parameters: week, year, siteId, or tableName');
@@ -103,6 +107,12 @@ export function getTrafficAnalysisQueryPlaceholdersFilled({
103
107
  pageTypeCase = buildPageTypeCase(pageTypes, pageTypeMatchColumn);
104
108
  }
105
109
 
110
+ let trfTypeCondition = 'TRUE';
111
+ if (trfTypes && trfTypes.length > 0) {
112
+ const quotedTypes = trfTypes.map((type) => `'${type}'`).join(', ');
113
+ trfTypeCondition = `trf_type IN (${quotedTypes})`;
114
+ }
115
+
106
116
  return {
107
117
  siteId,
108
118
  groupBy: dimensionColumns,
@@ -111,5 +121,6 @@ export function getTrafficAnalysisQueryPlaceholdersFilled({
111
121
  tableName,
112
122
  temporalCondition,
113
123
  pageTypeCase,
124
+ trfTypeCondition,
114
125
  };
115
126
  }
@@ -0,0 +1,97 @@
1
+ /*
2
+ * Copyright 2025 Adobe. All rights reserved.
3
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License. You may obtain a copy
5
+ * of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ *
7
+ * Unless required by applicable law or agreed to in writing, software distributed under
8
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ * OF ANY KIND, either express or implied. See the License for the specific language
10
+ * governing permissions and limitations under the License.
11
+ */
12
+
13
+ /**
14
+ * Generates the traffic analysis SQL query using template literals.
15
+ * @param {Object} params - Template parameters
16
+ * @param {string} params.siteId - Site ID
17
+ * @param {string} params.tableName - Table name
18
+ * @param {string} params.temporalCondition - Temporal condition
19
+ * @param {string} params.dimensionColumns - Dimension columns
20
+ * @param {string} params.groupBy - Group by clause
21
+ * @param {string} params.dimensionColumnsPrefixed - Prefixed dimension columns
22
+ * @param {string} params.pageTypeCase - Page type case statement
23
+ * @returns {string} The SQL query string
24
+ */
25
+ export function getTrafficAnalysisTemplate({
26
+ siteId,
27
+ tableName,
28
+ temporalCondition,
29
+ trfTypeCondition,
30
+ dimensionColumns,
31
+ groupBy,
32
+ dimensionColumnsPrefixed,
33
+ pageTypeCase,
34
+ }) {
35
+ return `
36
+ WITH raw AS (
37
+ SELECT
38
+ path,
39
+ ${pageTypeCase},
40
+ trf_type,
41
+ trf_channel,
42
+ trf_platform,
43
+ device,
44
+ utm_source,
45
+ utm_medium,
46
+ utm_campaign,
47
+ referrer,
48
+ consent,
49
+ notfound,
50
+ pageviews,
51
+ clicked,
52
+ engaged,
53
+ latest_scroll,
54
+ CASE WHEN latest_scroll >= 10000 THEN 1 ELSE 0 END AS engaged_scroll,
55
+ lcp,
56
+ cls,
57
+ inp
58
+ FROM ${tableName}
59
+ WHERE siteid = '${siteId}'
60
+ AND (${temporalCondition})
61
+ AND ${trfTypeCondition}
62
+ ),
63
+ agg AS (
64
+ SELECT
65
+ ${dimensionColumns},
66
+ COUNT(*) AS row_count,
67
+ CAST(SUM(pageviews) AS BIGINT) AS pageviews,
68
+ CAST(SUM(clicked) AS BIGINT) AS clicks,
69
+ CAST(SUM(engaged) AS BIGINT) AS engagements,
70
+ CAST(SUM(engaged_scroll) AS BIGINT) AS engaged_scroll,
71
+ approx_percentile(latest_scroll, 0.70) AS p70_scroll,
72
+ approx_percentile(lcp, 0.70) AS p70_lcp,
73
+ approx_percentile(cls, 0.70) AS p70_cls,
74
+ approx_percentile(inp, 0.70) AS p70_inp
75
+ FROM raw
76
+ GROUP BY ${groupBy}
77
+ ),
78
+ grand_total AS (
79
+ SELECT CAST(SUM(pageviews) AS BIGINT) AS total_pv FROM agg
80
+ )
81
+ SELECT
82
+ ${dimensionColumnsPrefixed},
83
+ a.pageviews,
84
+ CAST(a.pageviews AS DOUBLE) / NULLIF(t.total_pv, 0) AS pct_pageviews,
85
+ CAST(a.clicks AS DOUBLE) / NULLIF(a.row_count, 0) AS click_rate,
86
+ CAST(a.engagements AS DOUBLE) / NULLIF(a.row_count, 0) AS engagement_rate,
87
+ 1 - CAST(a.engagements AS DOUBLE) / NULLIF(a.row_count, 0) AS bounce_rate,
88
+ a.engaged_scroll,
89
+ a.p70_scroll,
90
+ a.p70_lcp,
91
+ a.p70_cls,
92
+ a.p70_inp
93
+ FROM agg a
94
+ CROSS JOIN grand_total t
95
+ ORDER BY a.pageviews DESC
96
+ `.trim();
97
+ }
@@ -1,59 +0,0 @@
1
- WITH raw AS (
2
- SELECT
3
- path,
4
- {{pageTypeCase}},
5
- trf_type,
6
- trf_channel,
7
- trf_platform,
8
- device,
9
- utm_source,
10
- utm_medium,
11
- utm_campaign,
12
- referrer,
13
- consent,
14
- notfound,
15
- pageviews,
16
- clicked,
17
- engaged,
18
- latest_scroll,
19
- CASE WHEN latest_scroll >= 10000 THEN 1 ELSE 0 END AS engaged_scroll,
20
- lcp,
21
- cls,
22
- inp
23
- FROM {{tableName}}
24
- WHERE siteid = '{{siteId}}'
25
- AND ({{temporalCondition}})
26
- ),
27
- agg AS (
28
- SELECT
29
- {{dimensionColumns}},
30
- COUNT(*) AS row_count,
31
- CAST(SUM(pageviews) AS BIGINT) AS pageviews,
32
- CAST(SUM(clicked) AS BIGINT) AS clicks,
33
- CAST(SUM(engaged) AS BIGINT) AS engagements,
34
- CAST(SUM(engaged_scroll) AS BIGINT) AS engaged_scroll,
35
- approx_percentile(latest_scroll, 0.70) AS p70_scroll,
36
- approx_percentile(lcp, 0.70) AS p70_lcp,
37
- approx_percentile(cls, 0.70) AS p70_cls,
38
- approx_percentile(inp, 0.70) AS p70_inp
39
- FROM raw
40
- GROUP BY {{groupBy}}
41
- ),
42
- grand_total AS (
43
- SELECT CAST(SUM(pageviews) AS BIGINT) AS total_pv FROM agg
44
- )
45
- SELECT
46
- {{dimensionColumnsPrefixed}},
47
- a.pageviews,
48
- CAST(a.pageviews AS DOUBLE) / NULLIF(t.total_pv, 0) AS pct_pageviews,
49
- CAST(a.clicks AS DOUBLE) / NULLIF(a.row_count, 0) AS click_rate,
50
- CAST(a.engagements AS DOUBLE) / NULLIF(a.row_count, 0) AS engagement_rate,
51
- 1 - CAST(a.engagements AS DOUBLE) / NULLIF(a.row_count, 0) AS bounce_rate,
52
- a.engaged_scroll,
53
- a.p70_scroll,
54
- a.p70_lcp,
55
- a.p70_cls,
56
- a.p70_inp
57
- FROM agg a
58
- CROSS JOIN grand_total t
59
- ORDER BY a.pageviews DESC