ga4-export-fixer 0.2.5-dev.0 → 0.2.5-dev.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.
package/README.md CHANGED
@@ -299,9 +299,10 @@ The `onSchemaChange: "EXTEND"` setting updates the result table schema on increm
299
299
  | ------------------------------------------ | ----------------- | -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
300
300
  | `preOperations.dateRangeStartFullRefresh` | string (SQL date) | `'date(2000, 1, 1)'` | Start date for full refresh |
301
301
  | `preOperations.dateRangeEnd` | string (SQL date) | `'current_date()'` | End date for queries |
302
- | `preOperations.numberOfPreviousDaysToScan` | integer | `10` | Number of previous days to scan from the result table when determining the incremental refresh start checkpoint. A higher value is required if the table updates have fallen behind for some reason |
302
+ | `preOperations.numberOfPreviousDaysToScan` | integer | `10` | Number of days to scan backwards from the result table's last partition when determining the incremental refresh start checkpoint. Needs to cover the number of days that can still contain not final `(data_is_final = false)` data |
303
303
  | `preOperations.incrementalStartOverride` | string (SQL date) | `undefined` | Override the incremental start date to re-process a specific range |
304
304
  | `preOperations.incrementalEndOverride` | string (SQL date) | `undefined` | Override the incremental end date to re-process a specific range |
305
+ | `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 |
305
306
 
306
307
 
307
308
  **`eventParamsToColumns`** — each item in the array is an object:
package/constants.js CHANGED
@@ -2,6 +2,7 @@ const constants = {
2
2
  DATE_RANGE_START_VARIABLE: 'date_range_start',
3
3
  INTRADAY_DATE_RANGE_START_VARIABLE: 'intraday_date_range_start',
4
4
  DATE_RANGE_END_VARIABLE: 'date_range_end',
5
+ LAST_PARTITION_DATE_VARIABLE: 'last_partition_date',
5
6
  DATE_COLUMN: 'event_date',
6
7
  DEFAULT_EVENTS_TABLE_NAME: 'ga4_events_enhanced',
7
8
  TABLE_DESCRIPTION_SUFFIX: 'Created by the ga4-export-fixer package.',
package/defaultConfig.js CHANGED
@@ -24,6 +24,7 @@ const baseConfig = {
24
24
  incrementalStartOverride: undefined,
25
25
  incrementalEndOverride: undefined,
26
26
  numberOfPreviousDaysToScan: 10,
27
+ numberOfDaysToProcess: undefined,
27
28
  },
28
29
  };
29
30
 
package/helpers.js CHANGED
@@ -196,6 +196,9 @@ const ga4ExportDateFilters = (config) => {
196
196
  return constants.DATE_RANGE_END_VARIABLE;
197
197
  }
198
198
  // full refresh
199
+ if (config.preOperations.numberOfDaysToProcess !== undefined) {
200
+ return `least(${config.preOperations.dateRangeStartFullRefresh}+${config.preOperations.numberOfDaysToProcess}-1, current_date())`;
201
+ }
199
202
  return config.preOperations.dateRangeEnd;
200
203
  };
201
204
 
@@ -274,7 +277,9 @@ const incrementalDateFilter = (config) => {
274
277
 
275
278
  // full refresh mode
276
279
  const fullRefreshStart = config?.preOperations?.dateRangeStartFullRefresh || baseConfig.preOperations.dateRangeStartFullRefresh;
277
- const fullRefreshEnd = config?.preOperations?.dateRangeEnd || baseConfig.preOperations.dateRangeEnd;
280
+ const fullRefreshEnd = config?.preOperations?.numberOfDaysToProcess !== undefined
281
+ ? `least(${fullRefreshStart}+${config.preOperations.numberOfDaysToProcess}-1, current_date())`
282
+ : (config?.preOperations?.dateRangeEnd || baseConfig.preOperations.dateRangeEnd);
278
283
 
279
284
  return setDateRange(fullRefreshStart, fullRefreshEnd);
280
285
  };
@@ -69,6 +69,12 @@ const validateBaseConfig = (config) => {
69
69
  if (typeof config.preOperations.dateRangeEnd !== 'string' || !config.preOperations.dateRangeEnd.trim()) {
70
70
  throw new Error(`config.preOperations.dateRangeEnd must be a non-empty string (SQL date expression). Received: ${JSON.stringify(config.preOperations.dateRangeEnd)}`);
71
71
  }
72
+ if (config.preOperations.numberOfDaysToProcess !== undefined) {
73
+ const nd = config.preOperations.numberOfDaysToProcess;
74
+ if (typeof nd !== 'number' || isNaN(nd) || !Number.isInteger(nd) || nd < 1) {
75
+ throw new Error(`config.preOperations.numberOfDaysToProcess must be a positive integer when defined. Received: ${JSON.stringify(nd)}`);
76
+ }
77
+ }
72
78
  if (config.preOperations.incrementalStartOverride !== undefined && config.preOperations.incrementalStartOverride !== null && config.preOperations.incrementalStartOverride !== '') {
73
79
  if (typeof config.preOperations.incrementalStartOverride !== 'string' || !config.preOperations.incrementalStartOverride.trim()) {
74
80
  throw new Error(`config.preOperations.incrementalStartOverride must be a non-empty string when provided. Received: ${JSON.stringify(config.preOperations.incrementalStartOverride)}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ga4-export-fixer",
3
- "version": "0.2.5-dev.0",
3
+ "version": "0.2.5-dev.2",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "files": [
package/preOperations.js CHANGED
@@ -6,6 +6,22 @@ const declareVariable = (variable, value) => {
6
6
  );`;
7
7
  };
8
8
 
9
+ // Get the last partition date from the result table
10
+ const getLastPartitionDate = (config) => {
11
+ const informationSchemaPath = config.self.replace(
12
+ /`?([^`]+)\.([^`]+)\.[^`]+`?$/,
13
+ '`$1.$2.INFORMATION_SCHEMA.PARTITIONS`'
14
+ );
15
+ const tableName = config.self.replace(/`/g, '').split('.').pop();
16
+
17
+ return `select
18
+ max(parse_date('%Y%m%d', partition_id))
19
+ from
20
+ ${informationSchemaPath}
21
+ where
22
+ table_name = '${tableName}' and partition_id != '__NULL__'`;
23
+ };
24
+
9
25
  // Define the date range start for incremental and full refresh
10
26
  const getDateRangeStart = (config) => {
11
27
  if (config.incremental) {
@@ -22,7 +38,9 @@ const getDateRangeStart = (config) => {
22
38
  from
23
39
  ${config.self}
24
40
  where
25
- ${constants.DATE_COLUMN} > current_date()-${config.preOperations.numberOfPreviousDaysToScan}
41
+ -- the scan is relative to the last partition date in the table
42
+ -- takes into account cases where table updates have fallen behind
43
+ ${constants.DATE_COLUMN} > ${constants.LAST_PARTITION_DATE_VARIABLE}-${config.preOperations.numberOfPreviousDaysToScan}
26
44
  group by
27
45
  ${constants.DATE_COLUMN}
28
46
  )
@@ -102,7 +120,11 @@ const getDateRangeEnd = (config) => {
102
120
  return `select ${config.preOperations.incrementalEndOverride}`;
103
121
  }
104
122
 
105
- // otherwise, use the default logic
123
+ // if a number of days to process is capped, adjust the end date accordingly
124
+ if (config.preOperations.numberOfDaysToProcess !== undefined) {
125
+ return `select least(${constants.DATE_RANGE_START_VARIABLE}+${config.preOperations.numberOfDaysToProcess}-1, current_date())`;
126
+ }
127
+
106
128
  return `select ${config.preOperations.dateRangeEnd}`;
107
129
  };
108
130
 
@@ -132,6 +154,12 @@ const setPreOperations = (config) => {
132
154
 
133
155
  // define the pre operations
134
156
  const preOperations = [
157
+ {
158
+ type: 'variable',
159
+ name: constants.LAST_PARTITION_DATE_VARIABLE,
160
+ value: config.incremental ? getLastPartitionDate(config) : undefined,
161
+ comment: `Get the last partition date from the result table. Reduces the number of rows scanned when defining the ${constants.DATE_RANGE_START_VARIABLE} variable.`,
162
+ },
135
163
  {
136
164
  type: 'variable',
137
165
  name: constants.DATE_RANGE_START_VARIABLE,