gscdump 0.4.0 → 0.6.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 +7 -5
- package/dist/contracts.d.mts +136 -0
- package/dist/contracts.mjs +1 -0
- package/dist/driver.d.mts +78 -0
- package/dist/driver.mjs +1 -0
- package/dist/index.d.mts +158 -89
- package/dist/index.mjs +389 -257
- package/dist/normalize.d.mts +2 -0
- package/dist/normalize.mjs +16 -0
- package/dist/query/index.d.mts +73 -33
- package/dist/query/index.mjs +238 -190
- package/dist/query/plan.d.mts +130 -0
- package/dist/query/plan.mjs +296 -0
- package/dist/sitemap.d.mts +13 -0
- package/dist/sitemap.mjs +31 -0
- package/dist/tenant.d.mts +18 -0
- package/dist/tenant.mjs +18 -0
- package/dist/url.d.mts +9 -0
- package/dist/url.mjs +6 -0
- package/package.json +43 -9
- package/dist/analysis/index.d.mts +0 -513
- package/dist/analysis/index.mjs +0 -872
package/dist/query/index.mjs
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import _dayjs from "dayjs";
|
|
2
2
|
import timezone from "dayjs/plugin/timezone.js";
|
|
3
3
|
import utc from "dayjs/plugin/utc.js";
|
|
4
|
-
|
|
5
|
-
//#region src/query/utils/dayjs.ts
|
|
6
4
|
_dayjs.extend(utc);
|
|
7
5
|
_dayjs.extend(timezone);
|
|
8
|
-
function dayjs(date
|
|
9
|
-
return _dayjs(date
|
|
6
|
+
function dayjs(date) {
|
|
7
|
+
return _dayjs(date);
|
|
10
8
|
}
|
|
11
9
|
function currentPstDate() {
|
|
12
10
|
return dayjs().tz("America/Los_Angeles").hour(12).minute(0).second(0).format("YYYY-MM-DD");
|
|
@@ -14,9 +12,13 @@ function currentPstDate() {
|
|
|
14
12
|
function dayjsPst() {
|
|
15
13
|
return dayjs().tz("America/Los_Angeles").hour(12).minute(0).second(0);
|
|
16
14
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
const MS_PER_DAY = 864e5;
|
|
16
|
+
function toIsoDate(d) {
|
|
17
|
+
return d.toISOString().slice(0, 10);
|
|
18
|
+
}
|
|
19
|
+
function addDays(dateStr, n) {
|
|
20
|
+
return toIsoDate(new Date(Date.parse(`${dateStr}T00:00:00Z`) + n * MS_PER_DAY));
|
|
21
|
+
}
|
|
20
22
|
const DATE_OPERATORS = [
|
|
21
23
|
"gte",
|
|
22
24
|
"gt",
|
|
@@ -33,6 +35,30 @@ const METRIC_OPERATORS = [
|
|
|
33
35
|
];
|
|
34
36
|
const SPECIAL_OPERATORS = ["topLevel"];
|
|
35
37
|
const QUERY_PARAMS = ["searchType"];
|
|
38
|
+
const FILTER_METRICS = [
|
|
39
|
+
"clicks",
|
|
40
|
+
"impressions",
|
|
41
|
+
"ctr",
|
|
42
|
+
"position"
|
|
43
|
+
];
|
|
44
|
+
function isDateOperator(op) {
|
|
45
|
+
return DATE_OPERATORS.includes(op);
|
|
46
|
+
}
|
|
47
|
+
function isMetricOperator(op) {
|
|
48
|
+
return METRIC_OPERATORS.includes(op);
|
|
49
|
+
}
|
|
50
|
+
function isSpecialOperator(op) {
|
|
51
|
+
return SPECIAL_OPERATORS.includes(op);
|
|
52
|
+
}
|
|
53
|
+
function isQueryParam(value) {
|
|
54
|
+
return QUERY_PARAMS.includes(value);
|
|
55
|
+
}
|
|
56
|
+
function isMetric(value) {
|
|
57
|
+
return FILTER_METRICS.includes(value);
|
|
58
|
+
}
|
|
59
|
+
function isRegexOperator(op) {
|
|
60
|
+
return op === "includingRegex" || op === "excludingRegex";
|
|
61
|
+
}
|
|
36
62
|
function isJsonFilter(value) {
|
|
37
63
|
return typeof value === "object" && value !== null && "_filters" in value && Array.isArray(value._filters);
|
|
38
64
|
}
|
|
@@ -49,32 +75,56 @@ function parseJsonFilter(json) {
|
|
|
49
75
|
_groupType: json._groupType
|
|
50
76
|
};
|
|
51
77
|
}
|
|
52
|
-
function
|
|
53
|
-
|
|
54
|
-
return input;
|
|
78
|
+
function isWireGroupType(type) {
|
|
79
|
+
return type === "and" || type === "or";
|
|
55
80
|
}
|
|
56
|
-
function
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
81
|
+
function convertWireLeaf(alt) {
|
|
82
|
+
if (!alt.column || !alt.type || isWireGroupType(alt.type)) return null;
|
|
83
|
+
const f = {
|
|
84
|
+
dimension: alt.column,
|
|
85
|
+
operator: alt.type,
|
|
86
|
+
expression: alt.type === "between" ? alt.from ?? "" : alt.value ?? ""
|
|
87
|
+
};
|
|
88
|
+
if (alt.type === "between" && alt.to) f.expression2 = alt.to;
|
|
89
|
+
return f;
|
|
61
90
|
}
|
|
62
|
-
function
|
|
63
|
-
|
|
91
|
+
function convertWireGroup(alt) {
|
|
92
|
+
if (!isWireGroupType(alt.type)) {
|
|
93
|
+
const leaf = convertWireLeaf(alt);
|
|
94
|
+
return leaf ? { _filters: [leaf] } : null;
|
|
95
|
+
}
|
|
96
|
+
const leaves = [];
|
|
97
|
+
const nested = [];
|
|
98
|
+
for (const child of alt.filters ?? []) if (isWireGroupType(child.type)) {
|
|
99
|
+
const sub = convertWireGroup(child);
|
|
100
|
+
if (sub) nested.push(sub);
|
|
101
|
+
} else {
|
|
102
|
+
const leaf = convertWireLeaf(child);
|
|
103
|
+
if (leaf) leaves.push(leaf);
|
|
104
|
+
}
|
|
105
|
+
if (leaves.length === 0 && nested.length === 0) return null;
|
|
106
|
+
return {
|
|
107
|
+
_filters: leaves,
|
|
108
|
+
_nestedGroups: nested.length > 0 ? nested : void 0,
|
|
109
|
+
_groupType: alt.type
|
|
110
|
+
};
|
|
64
111
|
}
|
|
65
|
-
function
|
|
66
|
-
|
|
112
|
+
function isWireFilter(input) {
|
|
113
|
+
if (!input || typeof input !== "object") return false;
|
|
114
|
+
const o = input;
|
|
115
|
+
if ("_filters" in o) return false;
|
|
116
|
+
return "type" in o && typeof o.type === "string" || "filters" in o && Array.isArray(o.filters);
|
|
67
117
|
}
|
|
68
|
-
function
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
return
|
|
118
|
+
function normalizeFilter(input) {
|
|
119
|
+
if (!input) return void 0;
|
|
120
|
+
if (isWireFilter(input)) return convertWireGroup(input) ?? void 0;
|
|
121
|
+
return input;
|
|
72
122
|
}
|
|
73
123
|
function extractSpecialFilters(filter) {
|
|
74
124
|
if (!filter) return {};
|
|
75
125
|
let startDate;
|
|
76
126
|
let endDate;
|
|
77
|
-
let searchType
|
|
127
|
+
let searchType;
|
|
78
128
|
const otherFilters = [];
|
|
79
129
|
const cleanedNestedGroups = [];
|
|
80
130
|
for (const f of filter._filters) if (f.dimension === "date" && isDateOperator(f.operator)) switch (f.operator) {
|
|
@@ -96,14 +146,14 @@ function extractSpecialFilters(filter) {
|
|
|
96
146
|
break;
|
|
97
147
|
}
|
|
98
148
|
else if (isQueryParam(f.dimension)) {
|
|
99
|
-
if (f.dimension === "searchType") searchType
|
|
149
|
+
if (f.dimension === "searchType") searchType = f.expression;
|
|
100
150
|
} else if (isMetricOperator(f.operator) || isSpecialOperator(f.operator)) otherFilters.push(f);
|
|
101
151
|
else otherFilters.push(f);
|
|
102
152
|
if (filter._nestedGroups) for (const nested of filter._nestedGroups) {
|
|
103
153
|
const extracted = extractSpecialFilters(nested);
|
|
104
154
|
if (extracted.startDate) startDate = extracted.startDate;
|
|
105
155
|
if (extracted.endDate) endDate = extracted.endDate;
|
|
106
|
-
if (extracted.searchType) searchType
|
|
156
|
+
if (extracted.searchType) searchType = extracted.searchType;
|
|
107
157
|
if (extracted.dimensionFilter) cleanedNestedGroups.push(extracted.dimensionFilter);
|
|
108
158
|
}
|
|
109
159
|
const dimensionFilter = otherFilters.length > 0 || cleanedNestedGroups.length > 0 ? {
|
|
@@ -114,7 +164,7 @@ function extractSpecialFilters(filter) {
|
|
|
114
164
|
return {
|
|
115
165
|
startDate,
|
|
116
166
|
endDate,
|
|
117
|
-
searchType
|
|
167
|
+
searchType,
|
|
118
168
|
dimensionFilter
|
|
119
169
|
};
|
|
120
170
|
}
|
|
@@ -140,14 +190,14 @@ function extractSpecialOperatorFilters(input) {
|
|
|
140
190
|
return [...special, ...nested];
|
|
141
191
|
}
|
|
142
192
|
function resolveToBody(state) {
|
|
143
|
-
const { startDate, endDate, searchType
|
|
193
|
+
const { startDate, endDate, searchType, dimensionFilter } = extractSpecialFilters(state.filter);
|
|
144
194
|
if (!startDate || !endDate) throw new Error("Date range required: use .where(between(date, start, end)) or .where(and(gte(date, start), lte(date, end)))");
|
|
145
195
|
const body = {
|
|
146
196
|
dimensions: state.dimensions,
|
|
147
197
|
startDate,
|
|
148
198
|
endDate
|
|
149
199
|
};
|
|
150
|
-
if (searchType
|
|
200
|
+
if (searchType) body.searchType = searchType;
|
|
151
201
|
if (state.rowLimit) body.rowLimit = state.rowLimit;
|
|
152
202
|
if (state.startRow) body.startRow = state.startRow;
|
|
153
203
|
const filterGroups = resolveFilter(dimensionFilter);
|
|
@@ -179,9 +229,6 @@ function resolveFilter(filter) {
|
|
|
179
229
|
if (filter._nestedGroups) for (const nested of filter._nestedGroups) groups.push(...resolveFilter(nested));
|
|
180
230
|
return groups;
|
|
181
231
|
}
|
|
182
|
-
|
|
183
|
-
//#endregion
|
|
184
|
-
//#region src/query/builder.ts
|
|
185
232
|
function isDimensionString(v) {
|
|
186
233
|
return typeof v === "string";
|
|
187
234
|
}
|
|
@@ -242,9 +289,6 @@ function createBuilder(state) {
|
|
|
242
289
|
};
|
|
243
290
|
}
|
|
244
291
|
const gsc = createBuilder({ dimensions: [] });
|
|
245
|
-
|
|
246
|
-
//#endregion
|
|
247
|
-
//#region src/query/columns.ts
|
|
248
292
|
function createColumn(dimension) {
|
|
249
293
|
return { dimension };
|
|
250
294
|
}
|
|
@@ -266,9 +310,6 @@ const impressions = createMetricColumn("impressions");
|
|
|
266
310
|
const ctr = createMetricColumn("ctr");
|
|
267
311
|
const position = createMetricColumn("position");
|
|
268
312
|
const searchType = createQueryParam("searchType");
|
|
269
|
-
|
|
270
|
-
//#endregion
|
|
271
|
-
//#region src/query/utils/countries.ts
|
|
272
313
|
var countries_default = [
|
|
273
314
|
{
|
|
274
315
|
"name": "Afghanistan",
|
|
@@ -1765,9 +1806,6 @@ var countries_default = [
|
|
|
1765
1806
|
"country-code": "716"
|
|
1766
1807
|
}
|
|
1767
1808
|
];
|
|
1768
|
-
|
|
1769
|
-
//#endregion
|
|
1770
|
-
//#region src/query/constants.ts
|
|
1771
1809
|
const Devices = {
|
|
1772
1810
|
MOBILE: "MOBILE",
|
|
1773
1811
|
DESKTOP: "DESKTOP",
|
|
@@ -1777,31 +1815,31 @@ const SearchTypes = {
|
|
|
1777
1815
|
WEB: "web",
|
|
1778
1816
|
IMAGE: "image",
|
|
1779
1817
|
VIDEO: "video",
|
|
1780
|
-
NEWS: "news"
|
|
1818
|
+
NEWS: "news",
|
|
1819
|
+
DISCOVER: "discover",
|
|
1820
|
+
GOOGLE_NEWS: "googleNews"
|
|
1781
1821
|
};
|
|
1782
1822
|
const Countries = Object.fromEntries(countries_default.map((c) => [c["alpha-3"], c["alpha-3"].toLowerCase()]));
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1823
|
+
function leafFilter(dimension, operator, expression, expression2) {
|
|
1824
|
+
const filter = {
|
|
1825
|
+
dimension,
|
|
1826
|
+
operator,
|
|
1827
|
+
expression
|
|
1828
|
+
};
|
|
1829
|
+
if (expression2 !== void 0) filter.expression2 = expression2;
|
|
1787
1830
|
return {
|
|
1788
1831
|
_constraints: {},
|
|
1789
|
-
_filters: [
|
|
1790
|
-
dimension: "dimension" in columnOrParam ? columnOrParam.dimension : columnOrParam.param,
|
|
1791
|
-
operator: "equals",
|
|
1792
|
-
expression: String(value)
|
|
1793
|
-
}]
|
|
1832
|
+
_filters: [filter]
|
|
1794
1833
|
};
|
|
1795
1834
|
}
|
|
1835
|
+
function metricOrDimFilter(column, metricOp, dimOp, expression, expression2) {
|
|
1836
|
+
return "metric" in column ? leafFilter(column.metric, metricOp, expression, expression2) : leafFilter(column.dimension, dimOp, expression, expression2);
|
|
1837
|
+
}
|
|
1838
|
+
function eq(columnOrParam, value) {
|
|
1839
|
+
return leafFilter("dimension" in columnOrParam ? columnOrParam.dimension : columnOrParam.param, "equals", String(value));
|
|
1840
|
+
}
|
|
1796
1841
|
function ne(column, value) {
|
|
1797
|
-
return
|
|
1798
|
-
_constraints: {},
|
|
1799
|
-
_filters: [{
|
|
1800
|
-
dimension: column.dimension,
|
|
1801
|
-
operator: "notEquals",
|
|
1802
|
-
expression: String(value)
|
|
1803
|
-
}]
|
|
1804
|
-
};
|
|
1842
|
+
return leafFilter(column.dimension, "notEquals", String(value));
|
|
1805
1843
|
}
|
|
1806
1844
|
function inArray(column, values) {
|
|
1807
1845
|
return {
|
|
@@ -1815,44 +1853,16 @@ function inArray(column, values) {
|
|
|
1815
1853
|
};
|
|
1816
1854
|
}
|
|
1817
1855
|
function contains(column, pattern) {
|
|
1818
|
-
return
|
|
1819
|
-
_constraints: {},
|
|
1820
|
-
_filters: [{
|
|
1821
|
-
dimension: column.dimension,
|
|
1822
|
-
operator: "contains",
|
|
1823
|
-
expression: pattern
|
|
1824
|
-
}]
|
|
1825
|
-
};
|
|
1856
|
+
return leafFilter(column.dimension, "contains", pattern);
|
|
1826
1857
|
}
|
|
1827
1858
|
function like(column, pattern) {
|
|
1828
|
-
return
|
|
1829
|
-
_constraints: {},
|
|
1830
|
-
_filters: [{
|
|
1831
|
-
dimension: column.dimension,
|
|
1832
|
-
operator: "contains",
|
|
1833
|
-
expression: pattern.replace(/%/g, "")
|
|
1834
|
-
}]
|
|
1835
|
-
};
|
|
1859
|
+
return leafFilter(column.dimension, "contains", pattern.replace(/%/g, ""));
|
|
1836
1860
|
}
|
|
1837
1861
|
function regex(column, pattern) {
|
|
1838
|
-
return
|
|
1839
|
-
_constraints: {},
|
|
1840
|
-
_filters: [{
|
|
1841
|
-
dimension: column.dimension,
|
|
1842
|
-
operator: "includingRegex",
|
|
1843
|
-
expression: typeof pattern === "string" ? pattern : pattern.source
|
|
1844
|
-
}]
|
|
1845
|
-
};
|
|
1862
|
+
return leafFilter(column.dimension, "includingRegex", typeof pattern === "string" ? pattern : pattern.source);
|
|
1846
1863
|
}
|
|
1847
1864
|
function notRegex(column, pattern) {
|
|
1848
|
-
return
|
|
1849
|
-
_constraints: {},
|
|
1850
|
-
_filters: [{
|
|
1851
|
-
dimension: column.dimension,
|
|
1852
|
-
operator: "excludingRegex",
|
|
1853
|
-
expression: typeof pattern === "string" ? pattern : pattern.source
|
|
1854
|
-
}]
|
|
1855
|
-
};
|
|
1865
|
+
return leafFilter(column.dimension, "excludingRegex", typeof pattern === "string" ? pattern : pattern.source);
|
|
1856
1866
|
}
|
|
1857
1867
|
function and(...filters) {
|
|
1858
1868
|
const flatFilters = [];
|
|
@@ -1876,17 +1886,10 @@ function or(...filters) {
|
|
|
1876
1886
|
_groupType: "or"
|
|
1877
1887
|
};
|
|
1878
1888
|
}
|
|
1879
|
-
const DATE_OPS = [
|
|
1880
|
-
"gte",
|
|
1881
|
-
"gt",
|
|
1882
|
-
"lte",
|
|
1883
|
-
"lt",
|
|
1884
|
-
"between"
|
|
1885
|
-
];
|
|
1886
1889
|
function not(filter) {
|
|
1887
1890
|
return {
|
|
1888
1891
|
_constraints: {},
|
|
1889
|
-
_filters: filter._filters.filter((f) => !
|
|
1892
|
+
_filters: filter._filters.filter((f) => !DATE_OPERATORS.includes(f.operator)).map((f) => ({
|
|
1890
1893
|
...f,
|
|
1891
1894
|
operator: invertOperator(f.operator)
|
|
1892
1895
|
}))
|
|
@@ -1903,116 +1906,161 @@ function invertOperator(op) {
|
|
|
1903
1906
|
}[op];
|
|
1904
1907
|
}
|
|
1905
1908
|
function gte(column, value) {
|
|
1906
|
-
|
|
1907
|
-
_constraints: {},
|
|
1908
|
-
_filters: [{
|
|
1909
|
-
dimension: column.metric,
|
|
1910
|
-
operator: "metricGte",
|
|
1911
|
-
expression: String(value)
|
|
1912
|
-
}]
|
|
1913
|
-
};
|
|
1914
|
-
return {
|
|
1915
|
-
_constraints: {},
|
|
1916
|
-
_filters: [{
|
|
1917
|
-
dimension: column.dimension,
|
|
1918
|
-
operator: "gte",
|
|
1919
|
-
expression: String(value)
|
|
1920
|
-
}]
|
|
1921
|
-
};
|
|
1909
|
+
return metricOrDimFilter(column, "metricGte", "gte", String(value));
|
|
1922
1910
|
}
|
|
1923
1911
|
function gt(column, value) {
|
|
1924
|
-
|
|
1925
|
-
_constraints: {},
|
|
1926
|
-
_filters: [{
|
|
1927
|
-
dimension: column.metric,
|
|
1928
|
-
operator: "metricGt",
|
|
1929
|
-
expression: String(value)
|
|
1930
|
-
}]
|
|
1931
|
-
};
|
|
1932
|
-
return {
|
|
1933
|
-
_constraints: {},
|
|
1934
|
-
_filters: [{
|
|
1935
|
-
dimension: column.dimension,
|
|
1936
|
-
operator: "gt",
|
|
1937
|
-
expression: String(value)
|
|
1938
|
-
}]
|
|
1939
|
-
};
|
|
1912
|
+
return metricOrDimFilter(column, "metricGt", "gt", String(value));
|
|
1940
1913
|
}
|
|
1941
1914
|
function lte(column, value) {
|
|
1942
|
-
|
|
1943
|
-
_constraints: {},
|
|
1944
|
-
_filters: [{
|
|
1945
|
-
dimension: column.metric,
|
|
1946
|
-
operator: "metricLte",
|
|
1947
|
-
expression: String(value)
|
|
1948
|
-
}]
|
|
1949
|
-
};
|
|
1950
|
-
return {
|
|
1951
|
-
_constraints: {},
|
|
1952
|
-
_filters: [{
|
|
1953
|
-
dimension: column.dimension,
|
|
1954
|
-
operator: "lte",
|
|
1955
|
-
expression: String(value)
|
|
1956
|
-
}]
|
|
1957
|
-
};
|
|
1915
|
+
return metricOrDimFilter(column, "metricLte", "lte", String(value));
|
|
1958
1916
|
}
|
|
1959
1917
|
function lt(column, value) {
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1918
|
+
return metricOrDimFilter(column, "metricLt", "lt", String(value));
|
|
1919
|
+
}
|
|
1920
|
+
function between(column, start, end) {
|
|
1921
|
+
return metricOrDimFilter(column, "metricBetween", "between", String(start), String(end));
|
|
1922
|
+
}
|
|
1923
|
+
function topLevel(column) {
|
|
1924
|
+
return leafFilter(column.dimension, "topLevel", "");
|
|
1925
|
+
}
|
|
1926
|
+
var UnsupportedLogicalCapabilityError = class extends Error {
|
|
1927
|
+
constructor(capability, context) {
|
|
1928
|
+
super(`${context} requires ${capability} capability`);
|
|
1929
|
+
this.name = "UnsupportedLogicalCapabilityError";
|
|
1930
|
+
}
|
|
1931
|
+
};
|
|
1932
|
+
function collectInternalFilters(filter) {
|
|
1933
|
+
if (!filter || !("_filters" in filter)) return [];
|
|
1934
|
+
const flat = filter._filters;
|
|
1935
|
+
const nested = filter._nestedGroups?.flatMap((group) => collectInternalFilters(group)) ?? [];
|
|
1936
|
+
return [...flat, ...nested];
|
|
1937
|
+
}
|
|
1938
|
+
function inferDataset(dimensions, filterDims = []) {
|
|
1939
|
+
const allDims = new Set([...dimensions, ...filterDims]);
|
|
1940
|
+
const has = (dimension) => allDims.has(dimension);
|
|
1941
|
+
if (has("searchAppearance")) return "search_appearance";
|
|
1942
|
+
if (has("page") && (has("query") || has("queryCanonical"))) return "page_keywords";
|
|
1943
|
+
if (has("query") || has("queryCanonical")) return "keywords";
|
|
1944
|
+
if (has("page")) return "pages";
|
|
1945
|
+
if (has("country")) return "countries";
|
|
1946
|
+
if (has("device")) return "devices";
|
|
1947
|
+
return "keywords";
|
|
1948
|
+
}
|
|
1949
|
+
function requireCapability(capabilities, capability, enabled, context) {
|
|
1950
|
+
if (enabled && !capabilities?.[capability]) throw new UnsupportedLogicalCapabilityError(capability, context);
|
|
1951
|
+
}
|
|
1952
|
+
function isDimensionLeaf(filter) {
|
|
1953
|
+
if (isMetric(filter.dimension)) return false;
|
|
1954
|
+
if (filter.dimension === "date" && isDateOperator(filter.operator)) return false;
|
|
1955
|
+
if (filter.operator === "topLevel" || filter.operator.startsWith("metric")) return false;
|
|
1956
|
+
if (isQueryParam(filter.dimension)) return false;
|
|
1957
|
+
return true;
|
|
1958
|
+
}
|
|
1959
|
+
function toLogicalDimensionFilter(filter) {
|
|
1968
1960
|
return {
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
expression: String(value)
|
|
1974
|
-
}]
|
|
1961
|
+
dimension: filter.dimension,
|
|
1962
|
+
operator: filter.operator,
|
|
1963
|
+
expression: filter.expression,
|
|
1964
|
+
expression2: filter.expression2
|
|
1975
1965
|
};
|
|
1976
1966
|
}
|
|
1977
|
-
function
|
|
1978
|
-
if ("
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1967
|
+
function buildDimensionFilterTree(filter, capabilities) {
|
|
1968
|
+
if (!filter || !("_filters" in filter)) return void 0;
|
|
1969
|
+
const groupType = filter._groupType ?? "and";
|
|
1970
|
+
const children = [];
|
|
1971
|
+
for (const f of filter._filters) {
|
|
1972
|
+
if (!isDimensionLeaf(f)) continue;
|
|
1973
|
+
requireCapability(capabilities, "regex", isRegexOperator(f.operator), "logical plan");
|
|
1974
|
+
children.push({
|
|
1975
|
+
kind: "leaf",
|
|
1976
|
+
filter: toLogicalDimensionFilter(f)
|
|
1977
|
+
});
|
|
1978
|
+
}
|
|
1979
|
+
for (const g of filter._nestedGroups ?? []) {
|
|
1980
|
+
const sub = buildDimensionFilterTree(g, capabilities);
|
|
1981
|
+
if (sub) children.push(sub);
|
|
1982
|
+
}
|
|
1983
|
+
if (children.length === 0) return void 0;
|
|
1984
|
+
if (children.length === 1) return children[0];
|
|
1985
|
+
return {
|
|
1986
|
+
kind: "group",
|
|
1987
|
+
groupType,
|
|
1988
|
+
children
|
|
1986
1989
|
};
|
|
1990
|
+
}
|
|
1991
|
+
function buildLogicalPlan(state, capabilities = {}) {
|
|
1992
|
+
const normalizedFilter = normalizeFilter(state.filter);
|
|
1993
|
+
const { startDate, endDate } = extractDateRange(normalizedFilter);
|
|
1994
|
+
if (!startDate || !endDate) throw new Error("logical plan requires date range (use between(date, ...) or gte/lte)");
|
|
1995
|
+
const allFilters = collectInternalFilters(normalizedFilter);
|
|
1996
|
+
const metricFilters = extractMetricFilters(normalizedFilter);
|
|
1997
|
+
const specialFilters = extractSpecialOperatorFilters(normalizedFilter);
|
|
1998
|
+
const queryParams = {};
|
|
1999
|
+
const dimensionFilters = [];
|
|
2000
|
+
for (const filter of allFilters) {
|
|
2001
|
+
if (isMetric(filter.dimension)) continue;
|
|
2002
|
+
if (filter.dimension === "date" && isDateOperator(filter.operator)) continue;
|
|
2003
|
+
if (filter.operator === "topLevel" || filter.operator.startsWith("metric")) continue;
|
|
2004
|
+
if (isQueryParam(filter.dimension)) {
|
|
2005
|
+
queryParams[filter.dimension] = filter.expression;
|
|
2006
|
+
continue;
|
|
2007
|
+
}
|
|
2008
|
+
const operator = filter.operator;
|
|
2009
|
+
requireCapability(capabilities, "regex", isRegexOperator(operator), "logical plan");
|
|
2010
|
+
dimensionFilters.push({
|
|
2011
|
+
dimension: filter.dimension,
|
|
2012
|
+
operator,
|
|
2013
|
+
expression: filter.expression,
|
|
2014
|
+
expression2: filter.expression2
|
|
2015
|
+
});
|
|
2016
|
+
}
|
|
2017
|
+
const dimensionFilterTree = buildDimensionFilterTree(normalizedFilter, capabilities);
|
|
2018
|
+
const filterDims = dimensionFilters.map((filter) => filter.dimension);
|
|
1987
2019
|
return {
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
2020
|
+
dataset: inferDataset(state.dimensions, filterDims),
|
|
2021
|
+
dimensions: [...state.dimensions],
|
|
2022
|
+
groupByDimensions: state.dimensions.filter((d) => d !== "date"),
|
|
2023
|
+
hasDate: state.dimensions.includes("date"),
|
|
2024
|
+
metrics: state.metrics ? [...state.metrics] : [
|
|
2025
|
+
"clicks",
|
|
2026
|
+
"impressions",
|
|
2027
|
+
"ctr",
|
|
2028
|
+
"position"
|
|
2029
|
+
],
|
|
2030
|
+
dateRange: {
|
|
2031
|
+
startDate,
|
|
2032
|
+
endDate
|
|
2033
|
+
},
|
|
2034
|
+
dimensionFilters,
|
|
2035
|
+
dimensionFilterTree,
|
|
2036
|
+
metricFilters: metricFilters.map((filter) => ({
|
|
2037
|
+
metric: filter.dimension,
|
|
2038
|
+
operator: filter.operator,
|
|
2039
|
+
expression: Number(filter.expression),
|
|
2040
|
+
expression2: filter.expression2 == null ? void 0 : Number(filter.expression2)
|
|
2041
|
+
})),
|
|
2042
|
+
specialFilters: { topLevel: specialFilters.some((filter) => filter.operator === "topLevel") },
|
|
2043
|
+
queryParams,
|
|
2044
|
+
orderBy: state.orderBy,
|
|
2045
|
+
rowLimit: state.rowLimit,
|
|
2046
|
+
startRow: state.startRow
|
|
1995
2047
|
};
|
|
1996
2048
|
}
|
|
1997
|
-
function
|
|
2049
|
+
function buildLogicalComparisonPlan(current, previous, capabilities = {}, comparisonFilter) {
|
|
2050
|
+
requireCapability(capabilities, "comparisonJoin", true, "logical comparison plan");
|
|
2051
|
+
const currentPlan = buildLogicalPlan(current, capabilities);
|
|
2052
|
+
const previousPlan = buildLogicalPlan(previous, capabilities);
|
|
2053
|
+
requireCapability(capabilities, "multiDataset", currentPlan.dataset !== previousPlan.dataset, "logical comparison plan");
|
|
1998
2054
|
return {
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
operator: "topLevel",
|
|
2003
|
-
expression: ""
|
|
2004
|
-
}]
|
|
2055
|
+
current: currentPlan,
|
|
2056
|
+
previous: previousPlan,
|
|
2057
|
+
comparisonFilter
|
|
2005
2058
|
};
|
|
2006
2059
|
}
|
|
2007
|
-
|
|
2008
|
-
//#endregion
|
|
2009
|
-
//#region src/query/index.ts
|
|
2010
2060
|
function today() {
|
|
2011
2061
|
return currentPstDate();
|
|
2012
2062
|
}
|
|
2013
2063
|
function daysAgo(n) {
|
|
2014
2064
|
return dayjsPst().subtract(n, "day").format("YYYY-MM-DD");
|
|
2015
2065
|
}
|
|
2016
|
-
|
|
2017
|
-
//#endregion
|
|
2018
|
-
export { Countries, Devices, SearchTypes, and, between, clicks, contains, country, ctr, currentPstDate, date, dayjs, dayjsPst, daysAgo, device, eq, extractDateRange, extractMetricFilters, extractSpecialOperatorFilters, gsc, gt, gte, impressions, inArray, isJsonFilter, like, lt, lte, ne, not, notRegex, or, page, parseJsonFilter, position, query, queryCanonical, regex, searchAppearance, searchType, today, topLevel };
|
|
2066
|
+
export { Countries, Devices, SearchTypes, UnsupportedLogicalCapabilityError, and, between, buildLogicalComparisonPlan, buildLogicalPlan, clicks, contains, country, ctr, currentPstDate, date, dayjs, dayjsPst, daysAgo, device, eq, extractDateRange, extractMetricFilters, extractSpecialOperatorFilters, gsc, gt, gte, impressions, inArray, isJsonFilter, like, lt, lte, ne, normalizeFilter, not, notRegex, or, page, parseJsonFilter, position, query, queryCanonical, regex, searchAppearance, searchType, today, topLevel };
|