ga4-export-fixer 0.6.1-dev.0 → 0.6.1
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 +1 -1
- package/package.json +1 -1
- package/utils.js +63 -29
package/README.md
CHANGED
package/package.json
CHANGED
package/utils.js
CHANGED
|
@@ -33,53 +33,87 @@ const mergeUniqueArrays = (...arrays) => {
|
|
|
33
33
|
* @returns {string} Generated SQL query
|
|
34
34
|
*/
|
|
35
35
|
const queryBuilder = (steps) => {
|
|
36
|
+
const INDENT = 2;
|
|
37
|
+
const pad = ' '.repeat(INDENT);
|
|
38
|
+
|
|
39
|
+
// Re-indents a multi-line SQL fragment so that continuation lines
|
|
40
|
+
// (lines after the first) have a consistent base indentation.
|
|
41
|
+
// Preserves relative indentation within the fragment.
|
|
42
|
+
const reindent = (sql, targetIndent) => {
|
|
43
|
+
if (!sql.includes('\n')) return sql;
|
|
44
|
+
const lines = sql.split('\n');
|
|
45
|
+
const continuationLines = lines.slice(1).filter(l => l.trim());
|
|
46
|
+
if (continuationLines.length === 0) return sql;
|
|
47
|
+
const minIndent = Math.min(
|
|
48
|
+
...continuationLines.map(l => l.match(/^ */)[0].length)
|
|
49
|
+
);
|
|
50
|
+
const p = ' '.repeat(targetIndent);
|
|
51
|
+
return lines[0] + '\n' + lines.slice(1)
|
|
52
|
+
.map(l => l.trim() ? p + l.slice(minIndent) : '')
|
|
53
|
+
.join('\n');
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
// Shifts an entire SQL block right by the given number of spaces.
|
|
57
|
+
// Preserves relative indentation within the block.
|
|
58
|
+
const indentBlock = (sql, spaces) => {
|
|
59
|
+
const p = ' '.repeat(spaces);
|
|
60
|
+
return sql.split('\n')
|
|
61
|
+
.map(l => l.trim() ? p + l : '')
|
|
62
|
+
.join('\n');
|
|
63
|
+
};
|
|
64
|
+
|
|
36
65
|
// Helper function to turn step.columns into SQL string
|
|
37
66
|
const columnsToSQL = (columns) => {
|
|
38
67
|
return Object.entries(columns)
|
|
39
68
|
// exclude all columns that have been explicitly set to undefined
|
|
40
69
|
.filter(([key, value]) => value !== undefined)
|
|
41
70
|
.map(([key, value]) => {
|
|
71
|
+
let entry;
|
|
42
72
|
// if the key and value are the same, return the value as is (i.e. no alias)
|
|
43
73
|
if (key === value) {
|
|
44
|
-
|
|
45
|
-
}
|
|
74
|
+
entry = value;
|
|
46
75
|
// if the key starts with '[sql]', return the value as is (i.e. no alias)
|
|
47
|
-
if (key.startsWith('[sql]')) {
|
|
48
|
-
|
|
76
|
+
} else if (key.startsWith('[sql]')) {
|
|
77
|
+
entry = value;
|
|
78
|
+
} else {
|
|
79
|
+
entry = `${value} as ${key}`;
|
|
49
80
|
}
|
|
50
|
-
return
|
|
81
|
+
return reindent(entry, INDENT);
|
|
51
82
|
})
|
|
52
|
-
.join(',\n
|
|
83
|
+
.join(',\n' + pad);
|
|
53
84
|
};
|
|
54
85
|
|
|
55
86
|
const selectSQL = (step) => {
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
${
|
|
87
|
+
const parts = [`select\n${pad}${columnsToSQL(step.columns)}`];
|
|
88
|
+
parts.push(`from\n${pad}${step.from}`);
|
|
89
|
+
|
|
90
|
+
if (step.leftJoin) {
|
|
91
|
+
step.leftJoin.forEach(join => {
|
|
92
|
+
parts.push(`left join\n${pad}${join.table} ${join.condition}`);
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (step.where) {
|
|
97
|
+
parts.push(`where\n${pad}${reindent(step.where, INDENT)}`);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (step.groupBy) {
|
|
101
|
+
parts.push(`group by\n${pad}${step.groupBy.join(', ')}`);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return parts.join('\n');
|
|
67
105
|
};
|
|
68
106
|
|
|
69
|
-
let sql = "";
|
|
70
107
|
if (steps.length === 1) {
|
|
71
|
-
|
|
72
|
-
const step = steps[0];
|
|
73
|
-
sql = selectSQL(step);
|
|
74
|
-
} else {
|
|
75
|
-
// Multiple steps, all but last are CTEs
|
|
76
|
-
const ctes = steps.slice(0, -1).map(step => {
|
|
77
|
-
return `${step.name} as (${selectSQL(step)})`;
|
|
78
|
-
});
|
|
79
|
-
const lastStep = steps[steps.length - 1];
|
|
80
|
-
sql = `with ${ctes.join(',\n ')}\n${selectSQL(lastStep)}`;
|
|
108
|
+
return selectSQL(steps[0]);
|
|
81
109
|
}
|
|
82
|
-
|
|
110
|
+
|
|
111
|
+
const ctes = steps.slice(0, -1).map(step => {
|
|
112
|
+
const body = indentBlock(selectSQL(step), INDENT);
|
|
113
|
+
return `${step.name} as (\n${body}\n)`;
|
|
114
|
+
});
|
|
115
|
+
const lastStep = steps[steps.length - 1];
|
|
116
|
+
return `with ${ctes.join(',\n')}\n${selectSQL(lastStep)}`;
|
|
83
117
|
};
|
|
84
118
|
|
|
85
119
|
/**
|