ga4-export-fixer 0.6.1 → 0.6.2-dev.0
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 +60 -1
- package/createTable.js +35 -2
- package/package.json +1 -1
- package/tables/ga4EventsEnhanced/assertions/dailyQuality.js +1 -1
- package/tables/ga4EventsEnhanced/assertions/index.js +6 -2
- package/tables/ga4EventsEnhanced/assertions/itemRevenue.js +1 -1
- package/tables/ga4EventsEnhanced/index.js +3 -2
package/README.md
CHANGED
|
@@ -20,6 +20,7 @@ The goal of the package is to **speed up development** when building data models
|
|
|
20
20
|
- [Usage](#usage)
|
|
21
21
|
- [Create GA4 Events Enhanced Table](#create-ga4-events-enhanced-table)
|
|
22
22
|
- [Configuration Object](#configuration-object)
|
|
23
|
+
- [Assertions](#assertions)
|
|
23
24
|
- [Creating Incremental Downstream Tables from ga4_events_enhanced](#creating-incremental-downstream-tables-from-ga4_events_enhanced)
|
|
24
25
|
- [Helpers](#helpers)
|
|
25
26
|
- [License](#license)
|
|
@@ -411,6 +412,7 @@ The boundary between fresh and intraday is timestamp-based because the fresh exp
|
|
|
411
412
|
| `preOperations.incrementalEndOverride` | string (SQL date) | `undefined` | Override the incremental end date to re-process a specific range |
|
|
412
413
|
| `preOperations.numberOfDaysToProcess` | integer | `undefined` | Limit each run to N days of data. When set, the end date becomes `start + N - 1` (capped at `current_date()`). When `undefined`, `dateRangeEnd` is used as-is. `incrementalEndOverride` takes priority |
|
|
413
414
|
|
|
415
|
+
Date fields (`dateRangeStart`, `dateRangeEnd`, etc.) accept string dates in `YYYYMMDD` or `YYYY-MM-DD` format, or BigQuery SQL expressions (e.g. `'current_date()'`, `'date(2026, 1, 1)'`).
|
|
414
416
|
|
|
415
417
|
<a id="eventParamsToColumns"></a>
|
|
416
418
|
|
|
@@ -443,7 +445,64 @@ itemListAttribution: { lookbackType: 'TIME', lookbackTimeMs: 86400000 }
|
|
|
443
445
|
|
|
444
446
|
> **Note:** This feature adds a compute-heavy CTE with a window function over unnested items. Only enable it if you need item list attribution for ecommerce analysis.
|
|
445
447
|
|
|
446
|
-
|
|
448
|
+
### Assertions
|
|
449
|
+
|
|
450
|
+
The package includes built-in data quality assertions that can be automatically created alongside the enhanced events table. Pass Dataform's `assert` function as the third argument to `createTable`:
|
|
451
|
+
|
|
452
|
+
```javascript
|
|
453
|
+
ga4EventsEnhanced.createTable(publish, config, { assert });
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
This creates the table and the following assertions using the same configuration:
|
|
457
|
+
|
|
458
|
+
| Assertion | Name | Description |
|
|
459
|
+
| --------- | ---- | ----------- |
|
|
460
|
+
| `dailyQuality` | `{tableName}_daily_quality` | Compares session count, event count, and item revenue per day between the enhanced table and raw export. Detects missing days, count mismatches, and non-final data inflation |
|
|
461
|
+
| `itemRevenue` | `{tableName}_item_revenue` | Reconciles item_revenue at the (event_date, item_id) grain between the enhanced table and raw export |
|
|
462
|
+
|
|
463
|
+
Assertions inherit the table's schema and tags from `dataformTableConfig`. Each assertion queries the last 5 days of data.
|
|
464
|
+
|
|
465
|
+
#### Selective Assertions
|
|
466
|
+
|
|
467
|
+
Disable individual assertions by setting them to `false`:
|
|
468
|
+
|
|
469
|
+
```javascript
|
|
470
|
+
ga4EventsEnhanced.createTable(publish, config, {
|
|
471
|
+
assert,
|
|
472
|
+
assertions: { dailyQuality: true, itemRevenue: false },
|
|
473
|
+
});
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
#### Assertion Config Overrides
|
|
477
|
+
|
|
478
|
+
Override the assertion's Dataform configuration (name, schema, tags):
|
|
479
|
+
|
|
480
|
+
```javascript
|
|
481
|
+
ga4EventsEnhanced.createTable(publish, config, {
|
|
482
|
+
assert,
|
|
483
|
+
assertions: {
|
|
484
|
+
dailyQuality: { tags: ['data_quality', 'ga4_export_fixer'] },
|
|
485
|
+
},
|
|
486
|
+
});
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
#### Standalone Assertions (SQLX Deployment)
|
|
490
|
+
|
|
491
|
+
For SQLX deployments or when you need full control, assertions can also be used as standalone SQL generators:
|
|
492
|
+
|
|
493
|
+
```javascript
|
|
494
|
+
const { ga4EventsEnhanced } = require('ga4-export-fixer');
|
|
495
|
+
|
|
496
|
+
assert('daily_quality_check', {
|
|
497
|
+
schema: 'analytics_123456789',
|
|
498
|
+
tags: ['ga4_export_fixer'],
|
|
499
|
+
}).query(ctx => {
|
|
500
|
+
return ga4EventsEnhanced.assertions.dailyQuality(
|
|
501
|
+
ctx.ref('ga4_events_enhanced_123456789'),
|
|
502
|
+
{ ...config, sourceTable: ctx.ref(config.sourceTable) }
|
|
503
|
+
);
|
|
504
|
+
});
|
|
505
|
+
```
|
|
447
506
|
|
|
448
507
|
### Creating Incremental Downstream Tables from ga4_events_enhanced
|
|
449
508
|
|
package/createTable.js
CHANGED
|
@@ -17,9 +17,15 @@ const preOperations = require('./preOperations.js');
|
|
|
17
17
|
* @param {Function} tableModule.generateSql - (mergedConfig) => string.
|
|
18
18
|
* @param {Function} tableModule.getColumnDescriptions - (mergedConfig) => Dataform columns object.
|
|
19
19
|
* @param {Function} tableModule.getTableDescription - (mergedConfig) => string.
|
|
20
|
+
* @param {Object} [tableModule.assertions] - Optional assertion definitions keyed by name.
|
|
21
|
+
* Each value: { generate: (tableRef, mergedConfig) => string, defaultName: string }.
|
|
22
|
+
* @param {Object} [options] - Optional Dataform runtime options.
|
|
23
|
+
* @param {Function} [options.assert] - Dataform assert() function. When provided, creates assertions for the table.
|
|
24
|
+
* @param {Object} [options.assertions] - Per-assertion overrides. Set a key to false to disable,
|
|
25
|
+
* or to an object to override assertion Dataform config (name, schema, tags).
|
|
20
26
|
* @returns {Object} The Dataform publish() object for the table.
|
|
21
27
|
*/
|
|
22
|
-
const createTable = (dataformPublish, userConfig, tableModule) => {
|
|
28
|
+
const createTable = (dataformPublish, userConfig, tableModule, options) => {
|
|
23
29
|
const mergedConfig = utils.mergeSQLConfigurations(tableModule.defaultConfig, userConfig);
|
|
24
30
|
tableModule.validate(mergedConfig, { skipDataformContextFields: true });
|
|
25
31
|
|
|
@@ -48,11 +54,38 @@ const createTable = (dataformPublish, userConfig, tableModule) => {
|
|
|
48
54
|
}
|
|
49
55
|
|
|
50
56
|
// Create the table using Dataform publish()
|
|
51
|
-
|
|
57
|
+
const tableResult = dataformPublish(dataformTableConfig.name, dataformTableConfig).preOps(ctx => {
|
|
52
58
|
return preOperations.setPreOperations(utils.setDataformContext(ctx, mergedConfig));
|
|
53
59
|
}).query(ctx => {
|
|
54
60
|
return tableModule.generateSql(utils.setDataformContext(ctx, mergedConfig));
|
|
55
61
|
});
|
|
62
|
+
|
|
63
|
+
// Create assertions when options.assert is provided and the table module defines assertions
|
|
64
|
+
if (options?.assert && tableModule.assertions) {
|
|
65
|
+
const tableName = dataformTableConfig.name;
|
|
66
|
+
|
|
67
|
+
for (const [key, assertionDef] of Object.entries(tableModule.assertions)) {
|
|
68
|
+
const assertionOption = options.assertions?.[key];
|
|
69
|
+
if (assertionOption === false) continue;
|
|
70
|
+
|
|
71
|
+
const assertionName = `${tableName}_${assertionDef.defaultName}`;
|
|
72
|
+
const assertionDataformConfig = {
|
|
73
|
+
schema: dataformTableConfig.schema,
|
|
74
|
+
tags: dataformTableConfig.tags || [],
|
|
75
|
+
...(typeof assertionOption === 'object' ? assertionOption : {}),
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
options.assert(assertionDataformConfig.name || assertionName, assertionDataformConfig).query(ctx => {
|
|
79
|
+
const resolvedConfig = { ...mergedConfig };
|
|
80
|
+
if (utils.isDataformTableReferenceObject(resolvedConfig.sourceTable)) {
|
|
81
|
+
resolvedConfig.sourceTable = ctx.ref(resolvedConfig.sourceTable);
|
|
82
|
+
}
|
|
83
|
+
return assertionDef.generate(ctx.ref(tableName), resolvedConfig);
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return tableResult;
|
|
56
89
|
};
|
|
57
90
|
|
|
58
91
|
module.exports = { createTable };
|
package/package.json
CHANGED
|
@@ -160,4 +160,4 @@ const generateDailyQualityAssertionSql = (tableRef, config) => {
|
|
|
160
160
|
return _generateDailyQualityAssertionSql(tableRef, mergedConfig);
|
|
161
161
|
};
|
|
162
162
|
|
|
163
|
-
module.exports = { generateDailyQualityAssertionSql };
|
|
163
|
+
module.exports = { generateDailyQualityAssertionSql, _generateDailyQualityAssertionSql };
|
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
const { generateItemRevenueAssertionSql } = require('./itemRevenue.js');
|
|
2
|
-
const { generateDailyQualityAssertionSql } = require('./dailyQuality.js');
|
|
1
|
+
const { generateItemRevenueAssertionSql, _generateItemRevenueAssertionSql } = require('./itemRevenue.js');
|
|
2
|
+
const { generateDailyQualityAssertionSql, _generateDailyQualityAssertionSql } = require('./dailyQuality.js');
|
|
3
3
|
|
|
4
4
|
module.exports = {
|
|
5
5
|
itemRevenue: generateItemRevenueAssertionSql,
|
|
6
6
|
dailyQuality: generateDailyQualityAssertionSql,
|
|
7
|
+
_internal: {
|
|
8
|
+
dailyQuality: { generate: _generateDailyQualityAssertionSql, defaultName: 'daily_quality' },
|
|
9
|
+
itemRevenue: { generate: _generateItemRevenueAssertionSql, defaultName: 'item_revenue' },
|
|
10
|
+
},
|
|
7
11
|
};
|
|
@@ -146,4 +146,4 @@ const generateItemRevenueAssertionSql = (tableRef, config) => {
|
|
|
146
146
|
return _generateItemRevenueAssertionSql(tableRef, mergedConfig);
|
|
147
147
|
};
|
|
148
148
|
|
|
149
|
-
module.exports = { generateItemRevenueAssertionSql };
|
|
149
|
+
module.exports = { generateItemRevenueAssertionSql, _generateItemRevenueAssertionSql };
|
|
@@ -410,10 +410,11 @@ const tableModule = {
|
|
|
410
410
|
generateSql: _generateEnhancedEventsSQL,
|
|
411
411
|
getColumnDescriptions: (config) => documentation.getColumnDescriptions(config, columnMetadata),
|
|
412
412
|
getTableDescription: (config) => documentation.buildTableDescription(config, getTableDescriptionSections(config)),
|
|
413
|
+
assertions: assertions._internal,
|
|
413
414
|
};
|
|
414
415
|
|
|
415
|
-
const createEnhancedEventsTable = (dataformPublish, config) => {
|
|
416
|
-
return createTable(dataformPublish, config, tableModule);
|
|
416
|
+
const createEnhancedEventsTable = (dataformPublish, config, options) => {
|
|
417
|
+
return createTable(dataformPublish, config, tableModule, options);
|
|
417
418
|
};
|
|
418
419
|
|
|
419
420
|
// Exported wrapper: merge config, validate, then delegate to preOperations module
|