ga4-export-fixer 0.5.2-dev.2 → 0.5.2-dev.4
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/package.json
CHANGED
|
@@ -161,6 +161,9 @@ const _generateEnhancedEventsSQL = (mergedConfig) => {
|
|
|
161
161
|
|
|
162
162
|
// item list attribution config
|
|
163
163
|
const itemListAttribution = mergedConfig.itemListAttribution;
|
|
164
|
+
const ecommerceEventsFilter = itemListAttribution
|
|
165
|
+
? helpers.ga4EcommerceEvents.filter(e => e !== 'refund').map(e => `'${e}'`).join(', ')
|
|
166
|
+
: null;
|
|
164
167
|
|
|
165
168
|
// auto-adjust bufferDays for time-based item list attribution lookback
|
|
166
169
|
const effectiveBufferDays = (itemListAttribution && itemListAttribution.lookbackType === 'TIME')
|
|
@@ -225,8 +228,12 @@ const _generateEnhancedEventsSQL = (mergedConfig) => {
|
|
|
225
228
|
// ecommerce
|
|
226
229
|
ecommerce: helpers.fixEcommerceStruct('ecommerce'),
|
|
227
230
|
items: 'items',
|
|
228
|
-
// unique row id for item list attribution join
|
|
229
|
-
|
|
231
|
+
// unique row id for item list attribution join. Only computed for ecommerce events.
|
|
232
|
+
// row_number() breaks hash collisions for batched events with identical data.
|
|
233
|
+
// partition by event_name avoids a single-partition bottleneck in the window function.
|
|
234
|
+
// Non-determinism is safe: colliding rows have identical items (to_json_string(items) is in the hash),
|
|
235
|
+
// so swapping row numbers between them produces the same final result.
|
|
236
|
+
_item_list_attribution_row_id: itemListAttribution ? `if(event_name in (${ecommerceEventsFilter}), farm_fingerprint(concat(user_pseudo_id, cast(event_timestamp as string), event_name, to_json_string(items), cast(row_number() over(partition by event_name, user_pseudo_id) as string))), null)` : undefined,
|
|
230
237
|
// flag if the data is "final" and is not expected to change anymore
|
|
231
238
|
data_is_final: helpers.isFinalData(mergedConfig.dataIsFinal.detectionMethod, mergedConfig.dataIsFinal.dayThreshold),
|
|
232
239
|
export_type: helpers.getGa4ExportType('_table_suffix'),
|
|
@@ -269,12 +276,11 @@ ${excludedEventsSQL}`,
|
|
|
269
276
|
itemListAttribution.lookbackTimeMs
|
|
270
277
|
);
|
|
271
278
|
const passthroughEvents = `event_name in ('view_item_list', 'select_item', 'view_promotion', 'select_promotion')`;
|
|
272
|
-
const ecommerceFilter = helpers.ga4EcommerceEvents.filter(e => e !== 'refund').map(e => `'${e}'`).join(', ');
|
|
273
279
|
|
|
274
280
|
return {
|
|
275
281
|
name: 'item_list_data',
|
|
276
282
|
columns: {
|
|
277
|
-
'
|
|
283
|
+
'_item_list_attribution_row_id': '_item_list_attribution_row_id',
|
|
278
284
|
'items': `array_agg(
|
|
279
285
|
(select as struct item.* replace(
|
|
280
286
|
coalesce(if(${passthroughEvents}, item.item_list_name, _item_list_attr.item_list_name), '(not set)') as item_list_name,
|
|
@@ -283,19 +289,19 @@ ${excludedEventsSQL}`,
|
|
|
283
289
|
))
|
|
284
290
|
)`,
|
|
285
291
|
},
|
|
286
|
-
from: `(select
|
|
287
|
-
groupBy: ['
|
|
292
|
+
from: `(select _item_list_attribution_row_id, event_name, item, ${attrExpr} as _item_list_attr from event_data, unnest(items) as item where event_name in (${ecommerceEventsFilter}))`,
|
|
293
|
+
groupBy: ['_item_list_attribution_row_id'],
|
|
288
294
|
};
|
|
289
295
|
})() : null;
|
|
290
296
|
|
|
291
297
|
const finalColumnOrder = getFinalColumnOrder(eventDataStep, sessionDataStep);
|
|
292
298
|
|
|
293
|
-
// When item list attribution is enabled, override the items column and exclude
|
|
299
|
+
// When item list attribution is enabled, override the items column and exclude _item_list_attribution_row_id
|
|
294
300
|
// COALESCE handles events without items (not in ecommerce filter) where the LEFT JOIN returns NULL
|
|
295
301
|
const itemListOverrides = itemListDataStep ? {
|
|
296
302
|
items: 'coalesce(item_list_data.items, event_data.items)',
|
|
297
303
|
} : {};
|
|
298
|
-
const itemListExcludedColumns = itemListDataStep ? ['
|
|
304
|
+
const itemListExcludedColumns = itemListDataStep ? ['_item_list_attribution_row_id'] : [];
|
|
299
305
|
|
|
300
306
|
// Join event_data and session_data, include additional logic
|
|
301
307
|
const finalStep = {
|
|
@@ -331,7 +337,7 @@ ${excludedEventsSQL}`,
|
|
|
331
337
|
leftJoin: [
|
|
332
338
|
...(itemListDataStep ? [{
|
|
333
339
|
table: 'item_list_data',
|
|
334
|
-
condition: 'using(
|
|
340
|
+
condition: 'using(_item_list_attribution_row_id)'
|
|
335
341
|
}] : []),
|
|
336
342
|
{
|
|
337
343
|
table: 'session_data',
|