gscdump 0.16.0 → 0.17.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/dist/index.d.mts +93 -1
- package/dist/index.mjs +1854 -155
- package/dist/query/index.d.mts +8 -1
- package/dist/query/index.mjs +322 -313
- package/dist/query/plan.mjs +1506 -0
- package/package.json +2 -2
package/dist/query/index.d.mts
CHANGED
|
@@ -245,9 +245,16 @@ declare function extractDateRange(input?: FilterInput): {
|
|
|
245
245
|
};
|
|
246
246
|
declare function extractMetricFilters(input?: FilterInput): InternalFilter[];
|
|
247
247
|
declare function extractSpecialOperatorFilters(input?: FilterInput): InternalFilter[];
|
|
248
|
+
/**
|
|
249
|
+
* Pull `searchType` out of a BuilderState filter. Returns undefined for
|
|
250
|
+
* missing/invalid shapes — callers treat that as "no scope" (cross-type read).
|
|
251
|
+
* Validated against the canonical `SearchTypes` set so unknown strings
|
|
252
|
+
* don't reach the engine.
|
|
253
|
+
*/
|
|
254
|
+
declare function extractSearchType(state: BuilderState | undefined | null): SearchType | undefined;
|
|
248
255
|
declare function dayjs(date?: _dayjs.ConfigType): Dayjs;
|
|
249
256
|
declare function currentPstDate(): string;
|
|
250
257
|
declare function dayjsPst(): Dayjs;
|
|
251
258
|
declare function today(): string;
|
|
252
259
|
declare function daysAgo(n: number): string;
|
|
253
|
-
export { type BuilderState, type Column, type ComparisonFilter, Countries, type Country, type Device, Devices, type Dimension, type DimensionValueMap, type Filter, type FilterInput, type GSCQueryBuilder, type GSCResult, type GSCRow, type InternalFilter, type JsonFilter, type JsonInternalFilter, type LogicalComparisonPlan, type LogicalDataset, type LogicalDimensionFilter, type LogicalMetricFilter, type LogicalQueryPlan, type Metric, type MetricColumn, type PlannerCapabilities, type QueryParam, type QueryParamName, type QueryParamValueMap, type SearchType, 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 };
|
|
260
|
+
export { type BuilderState, type Column, type ComparisonFilter, Countries, type Country, type Device, Devices, type Dimension, type DimensionValueMap, type Filter, type FilterInput, type GSCQueryBuilder, type GSCResult, type GSCRow, type InternalFilter, type JsonFilter, type JsonInternalFilter, type LogicalComparisonPlan, type LogicalDataset, type LogicalDimensionFilter, type LogicalMetricFilter, type LogicalQueryPlan, type Metric, type MetricColumn, type PlannerCapabilities, type QueryParam, type QueryParamName, type QueryParamValueMap, type SearchType, SearchTypes, UnsupportedLogicalCapabilityError, and, between, buildLogicalComparisonPlan, buildLogicalPlan, clicks, contains, country, ctr, currentPstDate, date, dayjs, dayjsPst, daysAgo, device, eq, extractDateRange, extractMetricFilters, extractSearchType, 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 };
|
package/dist/query/index.mjs
CHANGED
|
@@ -19,303 +19,6 @@ function toIsoDate(d) {
|
|
|
19
19
|
function addDays(dateStr, n) {
|
|
20
20
|
return toIsoDate(new Date(Date.parse(`${dateStr}T00:00:00Z`) + n * MS_PER_DAY));
|
|
21
21
|
}
|
|
22
|
-
const DATE_OPERATORS = [
|
|
23
|
-
"gte",
|
|
24
|
-
"gt",
|
|
25
|
-
"lte",
|
|
26
|
-
"lt",
|
|
27
|
-
"between"
|
|
28
|
-
];
|
|
29
|
-
const METRIC_OPERATORS = [
|
|
30
|
-
"metricGte",
|
|
31
|
-
"metricGt",
|
|
32
|
-
"metricLte",
|
|
33
|
-
"metricLt",
|
|
34
|
-
"metricBetween"
|
|
35
|
-
];
|
|
36
|
-
const SPECIAL_OPERATORS = ["topLevel"];
|
|
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
|
-
}
|
|
62
|
-
function isJsonFilter(value) {
|
|
63
|
-
return typeof value === "object" && value !== null && "_filters" in value && Array.isArray(value._filters);
|
|
64
|
-
}
|
|
65
|
-
function parseJsonFilter(json) {
|
|
66
|
-
return {
|
|
67
|
-
_constraints: {},
|
|
68
|
-
_filters: json._filters.map((f) => ({
|
|
69
|
-
dimension: f.dimension,
|
|
70
|
-
operator: f.operator,
|
|
71
|
-
expression: f.expression,
|
|
72
|
-
expression2: f.expression2
|
|
73
|
-
})),
|
|
74
|
-
_nestedGroups: json._nestedGroups?.map(parseJsonFilter),
|
|
75
|
-
_groupType: json._groupType
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
function isWireGroupType(type) {
|
|
79
|
-
return type === "and" || type === "or";
|
|
80
|
-
}
|
|
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;
|
|
90
|
-
}
|
|
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
|
-
};
|
|
111
|
-
}
|
|
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);
|
|
117
|
-
}
|
|
118
|
-
function normalizeFilter(input) {
|
|
119
|
-
if (!input) return void 0;
|
|
120
|
-
if (isWireFilter(input)) return convertWireGroup(input) ?? void 0;
|
|
121
|
-
return input;
|
|
122
|
-
}
|
|
123
|
-
function extractSpecialFilters(filter) {
|
|
124
|
-
if (!filter) return {};
|
|
125
|
-
let startDate;
|
|
126
|
-
let endDate;
|
|
127
|
-
let searchType;
|
|
128
|
-
const otherFilters = [];
|
|
129
|
-
const cleanedNestedGroups = [];
|
|
130
|
-
for (const f of filter._filters) if (f.dimension === "date" && isDateOperator(f.operator)) switch (f.operator) {
|
|
131
|
-
case "gte":
|
|
132
|
-
startDate = f.expression;
|
|
133
|
-
break;
|
|
134
|
-
case "gt":
|
|
135
|
-
startDate = addDays(f.expression, 1);
|
|
136
|
-
break;
|
|
137
|
-
case "lte":
|
|
138
|
-
endDate = f.expression;
|
|
139
|
-
break;
|
|
140
|
-
case "lt":
|
|
141
|
-
endDate = addDays(f.expression, -1);
|
|
142
|
-
break;
|
|
143
|
-
case "between":
|
|
144
|
-
startDate = f.expression;
|
|
145
|
-
endDate = f.expression2;
|
|
146
|
-
break;
|
|
147
|
-
}
|
|
148
|
-
else if (isQueryParam(f.dimension)) {
|
|
149
|
-
if (f.dimension === "searchType") searchType = f.expression;
|
|
150
|
-
} else if (isMetricOperator(f.operator) || isSpecialOperator(f.operator)) otherFilters.push(f);
|
|
151
|
-
else otherFilters.push(f);
|
|
152
|
-
if (filter._nestedGroups) for (const nested of filter._nestedGroups) {
|
|
153
|
-
const extracted = extractSpecialFilters(nested);
|
|
154
|
-
if (extracted.startDate) startDate = extracted.startDate;
|
|
155
|
-
if (extracted.endDate) endDate = extracted.endDate;
|
|
156
|
-
if (extracted.searchType) searchType = extracted.searchType;
|
|
157
|
-
if (extracted.dimensionFilter) cleanedNestedGroups.push(extracted.dimensionFilter);
|
|
158
|
-
}
|
|
159
|
-
const dimensionFilter = otherFilters.length > 0 || cleanedNestedGroups.length > 0 ? {
|
|
160
|
-
...filter,
|
|
161
|
-
_filters: otherFilters,
|
|
162
|
-
_nestedGroups: cleanedNestedGroups.length > 0 ? cleanedNestedGroups : void 0
|
|
163
|
-
} : void 0;
|
|
164
|
-
return {
|
|
165
|
-
startDate,
|
|
166
|
-
endDate,
|
|
167
|
-
searchType,
|
|
168
|
-
dimensionFilter
|
|
169
|
-
};
|
|
170
|
-
}
|
|
171
|
-
function extractDateRange(input) {
|
|
172
|
-
const { startDate, endDate } = extractSpecialFilters(normalizeFilter(input));
|
|
173
|
-
return {
|
|
174
|
-
startDate,
|
|
175
|
-
endDate
|
|
176
|
-
};
|
|
177
|
-
}
|
|
178
|
-
function extractMetricFilters(input) {
|
|
179
|
-
const filter = normalizeFilter(input);
|
|
180
|
-
if (!filter) return [];
|
|
181
|
-
const metricFilters = filter._filters.filter((f) => isMetricOperator(f.operator));
|
|
182
|
-
const nested = filter._nestedGroups?.flatMap((g) => extractMetricFilters(g)) ?? [];
|
|
183
|
-
return [...metricFilters, ...nested];
|
|
184
|
-
}
|
|
185
|
-
function extractSpecialOperatorFilters(input) {
|
|
186
|
-
const filter = normalizeFilter(input);
|
|
187
|
-
if (!filter) return [];
|
|
188
|
-
const special = filter._filters.filter((f) => isSpecialOperator(f.operator));
|
|
189
|
-
const nested = filter._nestedGroups?.flatMap((g) => extractSpecialOperatorFilters(g)) ?? [];
|
|
190
|
-
return [...special, ...nested];
|
|
191
|
-
}
|
|
192
|
-
function resolveToBody(state) {
|
|
193
|
-
const { startDate, endDate, searchType, dimensionFilter } = extractSpecialFilters(state.filter);
|
|
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)))");
|
|
195
|
-
const body = {
|
|
196
|
-
dimensions: state.dimensions,
|
|
197
|
-
startDate,
|
|
198
|
-
endDate
|
|
199
|
-
};
|
|
200
|
-
if (searchType) body.searchType = searchType;
|
|
201
|
-
if (state.rowLimit) body.rowLimit = state.rowLimit;
|
|
202
|
-
if (state.startRow) body.startRow = state.startRow;
|
|
203
|
-
const filterGroups = resolveFilter(dimensionFilter);
|
|
204
|
-
if (filterGroups.length > 0) body.dimensionFilterGroups = filterGroups;
|
|
205
|
-
return body;
|
|
206
|
-
}
|
|
207
|
-
function isApiFilter(f) {
|
|
208
|
-
return !isMetricOperator(f.operator) && !isSpecialOperator(f.operator);
|
|
209
|
-
}
|
|
210
|
-
function resolveFilter(filter) {
|
|
211
|
-
if (!filter) return [];
|
|
212
|
-
const groups = [];
|
|
213
|
-
const groupType = filter._groupType ?? "and";
|
|
214
|
-
const apiFilters = filter._filters.filter(isApiFilter);
|
|
215
|
-
if (groupType === "or") {
|
|
216
|
-
if (apiFilters.length > 0) groups.push({
|
|
217
|
-
groupType: "or",
|
|
218
|
-
filters: apiFilters.map((f) => ({
|
|
219
|
-
dimension: f.dimension,
|
|
220
|
-
operator: f.operator,
|
|
221
|
-
expression: f.expression
|
|
222
|
-
}))
|
|
223
|
-
});
|
|
224
|
-
} else if (apiFilters.length > 0) groups.push({ filters: apiFilters.map((f) => ({
|
|
225
|
-
dimension: f.dimension,
|
|
226
|
-
operator: f.operator,
|
|
227
|
-
expression: f.expression
|
|
228
|
-
})) });
|
|
229
|
-
if (filter._nestedGroups) for (const nested of filter._nestedGroups) groups.push(...resolveFilter(nested));
|
|
230
|
-
return groups;
|
|
231
|
-
}
|
|
232
|
-
function isDimensionString(v) {
|
|
233
|
-
return typeof v === "string";
|
|
234
|
-
}
|
|
235
|
-
function isMetricColumn(v) {
|
|
236
|
-
return typeof v === "object" && v !== null && "metric" in v;
|
|
237
|
-
}
|
|
238
|
-
function isDimensionColumn(v) {
|
|
239
|
-
return typeof v === "object" && v !== null && "dimension" in v && !("metric" in v);
|
|
240
|
-
}
|
|
241
|
-
function createBuilder(state) {
|
|
242
|
-
return {
|
|
243
|
-
select(...args) {
|
|
244
|
-
const dimensions = [];
|
|
245
|
-
const metrics = [];
|
|
246
|
-
for (const arg of args) if (isDimensionString(arg)) dimensions.push(arg);
|
|
247
|
-
else if (isDimensionColumn(arg)) dimensions.push(arg.dimension);
|
|
248
|
-
else if (isMetricColumn(arg)) metrics.push(arg.metric);
|
|
249
|
-
return createBuilder({
|
|
250
|
-
...state,
|
|
251
|
-
dimensions,
|
|
252
|
-
metrics: metrics.length > 0 ? metrics : void 0
|
|
253
|
-
});
|
|
254
|
-
},
|
|
255
|
-
where(filter) {
|
|
256
|
-
return createBuilder({
|
|
257
|
-
...state,
|
|
258
|
-
filter
|
|
259
|
-
});
|
|
260
|
-
},
|
|
261
|
-
prefilter(filter) {
|
|
262
|
-
return createBuilder({
|
|
263
|
-
...state,
|
|
264
|
-
prefilter: filter
|
|
265
|
-
});
|
|
266
|
-
},
|
|
267
|
-
orderBy(col, dir) {
|
|
268
|
-
const column = isMetricColumn(col) ? col.metric : col.dimension;
|
|
269
|
-
return createBuilder({
|
|
270
|
-
...state,
|
|
271
|
-
orderBy: {
|
|
272
|
-
column,
|
|
273
|
-
dir
|
|
274
|
-
}
|
|
275
|
-
});
|
|
276
|
-
},
|
|
277
|
-
limit(n) {
|
|
278
|
-
return createBuilder({
|
|
279
|
-
...state,
|
|
280
|
-
rowLimit: n
|
|
281
|
-
});
|
|
282
|
-
},
|
|
283
|
-
offset(n) {
|
|
284
|
-
return createBuilder({
|
|
285
|
-
...state,
|
|
286
|
-
startRow: n
|
|
287
|
-
});
|
|
288
|
-
},
|
|
289
|
-
toBody() {
|
|
290
|
-
return resolveToBody(state);
|
|
291
|
-
},
|
|
292
|
-
getState() {
|
|
293
|
-
return { ...state };
|
|
294
|
-
}
|
|
295
|
-
};
|
|
296
|
-
}
|
|
297
|
-
const gsc = createBuilder({ dimensions: [] });
|
|
298
|
-
function createColumn(dimension) {
|
|
299
|
-
return { dimension };
|
|
300
|
-
}
|
|
301
|
-
function createMetricColumn(metric) {
|
|
302
|
-
return { metric };
|
|
303
|
-
}
|
|
304
|
-
function createQueryParam(param) {
|
|
305
|
-
return { param };
|
|
306
|
-
}
|
|
307
|
-
const page = createColumn("page");
|
|
308
|
-
const query = createColumn("query");
|
|
309
|
-
const queryCanonical = createColumn("queryCanonical");
|
|
310
|
-
const device = createColumn("device");
|
|
311
|
-
const country = createColumn("country");
|
|
312
|
-
const searchAppearance = createColumn("searchAppearance");
|
|
313
|
-
const date = createColumn("date");
|
|
314
|
-
const clicks = createMetricColumn("clicks");
|
|
315
|
-
const impressions = createMetricColumn("impressions");
|
|
316
|
-
const ctr = createMetricColumn("ctr");
|
|
317
|
-
const position = createMetricColumn("position");
|
|
318
|
-
const searchType = createQueryParam("searchType");
|
|
319
22
|
var countries_default = [
|
|
320
23
|
{
|
|
321
24
|
"name": "Afghanistan",
|
|
@@ -1811,21 +1514,327 @@ var countries_default = [
|
|
|
1811
1514
|
"alpha-3": "ZWE",
|
|
1812
1515
|
"country-code": "716"
|
|
1813
1516
|
}
|
|
1814
|
-
];
|
|
1815
|
-
const Devices = {
|
|
1816
|
-
MOBILE: "MOBILE",
|
|
1817
|
-
DESKTOP: "DESKTOP",
|
|
1818
|
-
TABLET: "TABLET"
|
|
1819
|
-
};
|
|
1820
|
-
const SearchTypes = {
|
|
1821
|
-
WEB: "web",
|
|
1822
|
-
IMAGE: "image",
|
|
1823
|
-
VIDEO: "video",
|
|
1824
|
-
NEWS: "news",
|
|
1825
|
-
DISCOVER: "discover",
|
|
1826
|
-
GOOGLE_NEWS: "googleNews"
|
|
1827
|
-
};
|
|
1828
|
-
const Countries = Object.fromEntries(countries_default.map((c) => [c["alpha-3"], c["alpha-3"].toLowerCase()]));
|
|
1517
|
+
];
|
|
1518
|
+
const Devices = {
|
|
1519
|
+
MOBILE: "MOBILE",
|
|
1520
|
+
DESKTOP: "DESKTOP",
|
|
1521
|
+
TABLET: "TABLET"
|
|
1522
|
+
};
|
|
1523
|
+
const SearchTypes = {
|
|
1524
|
+
WEB: "web",
|
|
1525
|
+
IMAGE: "image",
|
|
1526
|
+
VIDEO: "video",
|
|
1527
|
+
NEWS: "news",
|
|
1528
|
+
DISCOVER: "discover",
|
|
1529
|
+
GOOGLE_NEWS: "googleNews"
|
|
1530
|
+
};
|
|
1531
|
+
const Countries = Object.fromEntries(countries_default.map((c) => [c["alpha-3"], c["alpha-3"].toLowerCase()]));
|
|
1532
|
+
const DATE_OPERATORS = [
|
|
1533
|
+
"gte",
|
|
1534
|
+
"gt",
|
|
1535
|
+
"lte",
|
|
1536
|
+
"lt",
|
|
1537
|
+
"between"
|
|
1538
|
+
];
|
|
1539
|
+
const METRIC_OPERATORS = [
|
|
1540
|
+
"metricGte",
|
|
1541
|
+
"metricGt",
|
|
1542
|
+
"metricLte",
|
|
1543
|
+
"metricLt",
|
|
1544
|
+
"metricBetween"
|
|
1545
|
+
];
|
|
1546
|
+
const SPECIAL_OPERATORS = ["topLevel"];
|
|
1547
|
+
const QUERY_PARAMS = ["searchType"];
|
|
1548
|
+
const FILTER_METRICS = [
|
|
1549
|
+
"clicks",
|
|
1550
|
+
"impressions",
|
|
1551
|
+
"ctr",
|
|
1552
|
+
"position"
|
|
1553
|
+
];
|
|
1554
|
+
function isDateOperator(op) {
|
|
1555
|
+
return DATE_OPERATORS.includes(op);
|
|
1556
|
+
}
|
|
1557
|
+
function isMetricOperator(op) {
|
|
1558
|
+
return METRIC_OPERATORS.includes(op);
|
|
1559
|
+
}
|
|
1560
|
+
function isSpecialOperator(op) {
|
|
1561
|
+
return SPECIAL_OPERATORS.includes(op);
|
|
1562
|
+
}
|
|
1563
|
+
function isQueryParam(value) {
|
|
1564
|
+
return QUERY_PARAMS.includes(value);
|
|
1565
|
+
}
|
|
1566
|
+
function isMetric(value) {
|
|
1567
|
+
return FILTER_METRICS.includes(value);
|
|
1568
|
+
}
|
|
1569
|
+
function isRegexOperator(op) {
|
|
1570
|
+
return op === "includingRegex" || op === "excludingRegex";
|
|
1571
|
+
}
|
|
1572
|
+
const KNOWN_SEARCH_TYPES = new Set(Object.values(SearchTypes));
|
|
1573
|
+
function isJsonFilter(value) {
|
|
1574
|
+
return typeof value === "object" && value !== null && "_filters" in value && Array.isArray(value._filters);
|
|
1575
|
+
}
|
|
1576
|
+
function parseJsonFilter(json) {
|
|
1577
|
+
return {
|
|
1578
|
+
_constraints: {},
|
|
1579
|
+
_filters: json._filters.map((f) => ({
|
|
1580
|
+
dimension: f.dimension,
|
|
1581
|
+
operator: f.operator,
|
|
1582
|
+
expression: f.expression,
|
|
1583
|
+
expression2: f.expression2
|
|
1584
|
+
})),
|
|
1585
|
+
_nestedGroups: json._nestedGroups?.map(parseJsonFilter),
|
|
1586
|
+
_groupType: json._groupType
|
|
1587
|
+
};
|
|
1588
|
+
}
|
|
1589
|
+
function isWireGroupType(type) {
|
|
1590
|
+
return type === "and" || type === "or";
|
|
1591
|
+
}
|
|
1592
|
+
function convertWireLeaf(alt) {
|
|
1593
|
+
if (!alt.column || !alt.type || isWireGroupType(alt.type)) return null;
|
|
1594
|
+
const f = {
|
|
1595
|
+
dimension: alt.column,
|
|
1596
|
+
operator: alt.type,
|
|
1597
|
+
expression: alt.type === "between" ? alt.from ?? "" : alt.value ?? ""
|
|
1598
|
+
};
|
|
1599
|
+
if (alt.type === "between" && alt.to) f.expression2 = alt.to;
|
|
1600
|
+
return f;
|
|
1601
|
+
}
|
|
1602
|
+
function convertWireGroup(alt) {
|
|
1603
|
+
if (!isWireGroupType(alt.type)) {
|
|
1604
|
+
const leaf = convertWireLeaf(alt);
|
|
1605
|
+
return leaf ? { _filters: [leaf] } : null;
|
|
1606
|
+
}
|
|
1607
|
+
const leaves = [];
|
|
1608
|
+
const nested = [];
|
|
1609
|
+
for (const child of alt.filters ?? []) if (isWireGroupType(child.type)) {
|
|
1610
|
+
const sub = convertWireGroup(child);
|
|
1611
|
+
if (sub) nested.push(sub);
|
|
1612
|
+
} else {
|
|
1613
|
+
const leaf = convertWireLeaf(child);
|
|
1614
|
+
if (leaf) leaves.push(leaf);
|
|
1615
|
+
}
|
|
1616
|
+
if (leaves.length === 0 && nested.length === 0) return null;
|
|
1617
|
+
return {
|
|
1618
|
+
_filters: leaves,
|
|
1619
|
+
_nestedGroups: nested.length > 0 ? nested : void 0,
|
|
1620
|
+
_groupType: alt.type
|
|
1621
|
+
};
|
|
1622
|
+
}
|
|
1623
|
+
function isWireFilter(input) {
|
|
1624
|
+
if (!input || typeof input !== "object") return false;
|
|
1625
|
+
const o = input;
|
|
1626
|
+
if ("_filters" in o) return false;
|
|
1627
|
+
return "type" in o && typeof o.type === "string" || "filters" in o && Array.isArray(o.filters);
|
|
1628
|
+
}
|
|
1629
|
+
function normalizeFilter(input) {
|
|
1630
|
+
if (!input) return void 0;
|
|
1631
|
+
if (isWireFilter(input)) return convertWireGroup(input) ?? void 0;
|
|
1632
|
+
return input;
|
|
1633
|
+
}
|
|
1634
|
+
function extractSpecialFilters(filter) {
|
|
1635
|
+
if (!filter) return {};
|
|
1636
|
+
let startDate;
|
|
1637
|
+
let endDate;
|
|
1638
|
+
let searchType;
|
|
1639
|
+
const otherFilters = [];
|
|
1640
|
+
const cleanedNestedGroups = [];
|
|
1641
|
+
for (const f of filter._filters) if (f.dimension === "date" && isDateOperator(f.operator)) switch (f.operator) {
|
|
1642
|
+
case "gte":
|
|
1643
|
+
startDate = f.expression;
|
|
1644
|
+
break;
|
|
1645
|
+
case "gt":
|
|
1646
|
+
startDate = addDays(f.expression, 1);
|
|
1647
|
+
break;
|
|
1648
|
+
case "lte":
|
|
1649
|
+
endDate = f.expression;
|
|
1650
|
+
break;
|
|
1651
|
+
case "lt":
|
|
1652
|
+
endDate = addDays(f.expression, -1);
|
|
1653
|
+
break;
|
|
1654
|
+
case "between":
|
|
1655
|
+
startDate = f.expression;
|
|
1656
|
+
endDate = f.expression2;
|
|
1657
|
+
break;
|
|
1658
|
+
}
|
|
1659
|
+
else if (isQueryParam(f.dimension)) {
|
|
1660
|
+
if (f.dimension === "searchType") searchType = f.expression;
|
|
1661
|
+
} else if (isMetricOperator(f.operator) || isSpecialOperator(f.operator)) otherFilters.push(f);
|
|
1662
|
+
else otherFilters.push(f);
|
|
1663
|
+
if (filter._nestedGroups) for (const nested of filter._nestedGroups) {
|
|
1664
|
+
const extracted = extractSpecialFilters(nested);
|
|
1665
|
+
if (extracted.startDate) startDate = extracted.startDate;
|
|
1666
|
+
if (extracted.endDate) endDate = extracted.endDate;
|
|
1667
|
+
if (extracted.searchType) searchType = extracted.searchType;
|
|
1668
|
+
if (extracted.dimensionFilter) cleanedNestedGroups.push(extracted.dimensionFilter);
|
|
1669
|
+
}
|
|
1670
|
+
const dimensionFilter = otherFilters.length > 0 || cleanedNestedGroups.length > 0 ? {
|
|
1671
|
+
...filter,
|
|
1672
|
+
_filters: otherFilters,
|
|
1673
|
+
_nestedGroups: cleanedNestedGroups.length > 0 ? cleanedNestedGroups : void 0
|
|
1674
|
+
} : void 0;
|
|
1675
|
+
return {
|
|
1676
|
+
startDate,
|
|
1677
|
+
endDate,
|
|
1678
|
+
searchType,
|
|
1679
|
+
dimensionFilter
|
|
1680
|
+
};
|
|
1681
|
+
}
|
|
1682
|
+
function extractDateRange(input) {
|
|
1683
|
+
const { startDate, endDate } = extractSpecialFilters(normalizeFilter(input));
|
|
1684
|
+
return {
|
|
1685
|
+
startDate,
|
|
1686
|
+
endDate
|
|
1687
|
+
};
|
|
1688
|
+
}
|
|
1689
|
+
function extractMetricFilters(input) {
|
|
1690
|
+
const filter = normalizeFilter(input);
|
|
1691
|
+
if (!filter) return [];
|
|
1692
|
+
const metricFilters = filter._filters.filter((f) => isMetricOperator(f.operator));
|
|
1693
|
+
const nested = filter._nestedGroups?.flatMap((g) => extractMetricFilters(g)) ?? [];
|
|
1694
|
+
return [...metricFilters, ...nested];
|
|
1695
|
+
}
|
|
1696
|
+
function extractSpecialOperatorFilters(input) {
|
|
1697
|
+
const filter = normalizeFilter(input);
|
|
1698
|
+
if (!filter) return [];
|
|
1699
|
+
const special = filter._filters.filter((f) => isSpecialOperator(f.operator));
|
|
1700
|
+
const nested = filter._nestedGroups?.flatMap((g) => extractSpecialOperatorFilters(g)) ?? [];
|
|
1701
|
+
return [...special, ...nested];
|
|
1702
|
+
}
|
|
1703
|
+
function extractSearchType(state) {
|
|
1704
|
+
if (!state) return void 0;
|
|
1705
|
+
const filter = state.filter;
|
|
1706
|
+
if (!filter || typeof filter !== "object") return void 0;
|
|
1707
|
+
const raw = filter.searchType;
|
|
1708
|
+
if (typeof raw !== "string" || raw.length === 0) return void 0;
|
|
1709
|
+
return KNOWN_SEARCH_TYPES.has(raw) ? raw : void 0;
|
|
1710
|
+
}
|
|
1711
|
+
function resolveToBody(state) {
|
|
1712
|
+
const { startDate, endDate, searchType, dimensionFilter } = extractSpecialFilters(state.filter);
|
|
1713
|
+
if (!startDate || !endDate) throw new Error("Date range required: use .where(between(date, start, end)) or .where(and(gte(date, start), lte(date, end)))");
|
|
1714
|
+
const body = {
|
|
1715
|
+
dimensions: state.dimensions,
|
|
1716
|
+
startDate,
|
|
1717
|
+
endDate
|
|
1718
|
+
};
|
|
1719
|
+
if (searchType) body.searchType = searchType;
|
|
1720
|
+
if (state.rowLimit) body.rowLimit = state.rowLimit;
|
|
1721
|
+
if (state.startRow) body.startRow = state.startRow;
|
|
1722
|
+
const filterGroups = resolveFilter(dimensionFilter);
|
|
1723
|
+
if (filterGroups.length > 0) body.dimensionFilterGroups = filterGroups;
|
|
1724
|
+
return body;
|
|
1725
|
+
}
|
|
1726
|
+
function isApiFilter(f) {
|
|
1727
|
+
return !isMetricOperator(f.operator) && !isSpecialOperator(f.operator);
|
|
1728
|
+
}
|
|
1729
|
+
function resolveFilter(filter) {
|
|
1730
|
+
if (!filter) return [];
|
|
1731
|
+
const groups = [];
|
|
1732
|
+
const groupType = filter._groupType ?? "and";
|
|
1733
|
+
const apiFilters = filter._filters.filter(isApiFilter);
|
|
1734
|
+
if (groupType === "or") {
|
|
1735
|
+
if (apiFilters.length > 0) groups.push({
|
|
1736
|
+
groupType: "or",
|
|
1737
|
+
filters: apiFilters.map((f) => ({
|
|
1738
|
+
dimension: f.dimension,
|
|
1739
|
+
operator: f.operator,
|
|
1740
|
+
expression: f.expression
|
|
1741
|
+
}))
|
|
1742
|
+
});
|
|
1743
|
+
} else if (apiFilters.length > 0) groups.push({ filters: apiFilters.map((f) => ({
|
|
1744
|
+
dimension: f.dimension,
|
|
1745
|
+
operator: f.operator,
|
|
1746
|
+
expression: f.expression
|
|
1747
|
+
})) });
|
|
1748
|
+
if (filter._nestedGroups) for (const nested of filter._nestedGroups) groups.push(...resolveFilter(nested));
|
|
1749
|
+
return groups;
|
|
1750
|
+
}
|
|
1751
|
+
function isDimensionString(v) {
|
|
1752
|
+
return typeof v === "string";
|
|
1753
|
+
}
|
|
1754
|
+
function isMetricColumn(v) {
|
|
1755
|
+
return typeof v === "object" && v !== null && "metric" in v;
|
|
1756
|
+
}
|
|
1757
|
+
function isDimensionColumn(v) {
|
|
1758
|
+
return typeof v === "object" && v !== null && "dimension" in v && !("metric" in v);
|
|
1759
|
+
}
|
|
1760
|
+
function createBuilder(state) {
|
|
1761
|
+
return {
|
|
1762
|
+
select(...args) {
|
|
1763
|
+
const dimensions = [];
|
|
1764
|
+
const metrics = [];
|
|
1765
|
+
for (const arg of args) if (isDimensionString(arg)) dimensions.push(arg);
|
|
1766
|
+
else if (isDimensionColumn(arg)) dimensions.push(arg.dimension);
|
|
1767
|
+
else if (isMetricColumn(arg)) metrics.push(arg.metric);
|
|
1768
|
+
return createBuilder({
|
|
1769
|
+
...state,
|
|
1770
|
+
dimensions,
|
|
1771
|
+
metrics: metrics.length > 0 ? metrics : void 0
|
|
1772
|
+
});
|
|
1773
|
+
},
|
|
1774
|
+
where(filter) {
|
|
1775
|
+
return createBuilder({
|
|
1776
|
+
...state,
|
|
1777
|
+
filter
|
|
1778
|
+
});
|
|
1779
|
+
},
|
|
1780
|
+
prefilter(filter) {
|
|
1781
|
+
return createBuilder({
|
|
1782
|
+
...state,
|
|
1783
|
+
prefilter: filter
|
|
1784
|
+
});
|
|
1785
|
+
},
|
|
1786
|
+
orderBy(col, dir) {
|
|
1787
|
+
const column = isMetricColumn(col) ? col.metric : col.dimension;
|
|
1788
|
+
return createBuilder({
|
|
1789
|
+
...state,
|
|
1790
|
+
orderBy: {
|
|
1791
|
+
column,
|
|
1792
|
+
dir
|
|
1793
|
+
}
|
|
1794
|
+
});
|
|
1795
|
+
},
|
|
1796
|
+
limit(n) {
|
|
1797
|
+
return createBuilder({
|
|
1798
|
+
...state,
|
|
1799
|
+
rowLimit: n
|
|
1800
|
+
});
|
|
1801
|
+
},
|
|
1802
|
+
offset(n) {
|
|
1803
|
+
return createBuilder({
|
|
1804
|
+
...state,
|
|
1805
|
+
startRow: n
|
|
1806
|
+
});
|
|
1807
|
+
},
|
|
1808
|
+
toBody() {
|
|
1809
|
+
return resolveToBody(state);
|
|
1810
|
+
},
|
|
1811
|
+
getState() {
|
|
1812
|
+
return { ...state };
|
|
1813
|
+
}
|
|
1814
|
+
};
|
|
1815
|
+
}
|
|
1816
|
+
const gsc = createBuilder({ dimensions: [] });
|
|
1817
|
+
function createColumn(dimension) {
|
|
1818
|
+
return { dimension };
|
|
1819
|
+
}
|
|
1820
|
+
function createMetricColumn(metric) {
|
|
1821
|
+
return { metric };
|
|
1822
|
+
}
|
|
1823
|
+
function createQueryParam(param) {
|
|
1824
|
+
return { param };
|
|
1825
|
+
}
|
|
1826
|
+
const page = createColumn("page");
|
|
1827
|
+
const query = createColumn("query");
|
|
1828
|
+
const queryCanonical = createColumn("queryCanonical");
|
|
1829
|
+
const device = createColumn("device");
|
|
1830
|
+
const country = createColumn("country");
|
|
1831
|
+
const searchAppearance = createColumn("searchAppearance");
|
|
1832
|
+
const date = createColumn("date");
|
|
1833
|
+
const clicks = createMetricColumn("clicks");
|
|
1834
|
+
const impressions = createMetricColumn("impressions");
|
|
1835
|
+
const ctr = createMetricColumn("ctr");
|
|
1836
|
+
const position = createMetricColumn("position");
|
|
1837
|
+
const searchType = createQueryParam("searchType");
|
|
1829
1838
|
function leafFilter(dimension, operator, expression, expression2) {
|
|
1830
1839
|
const filter = {
|
|
1831
1840
|
dimension,
|
|
@@ -2076,4 +2085,4 @@ function today() {
|
|
|
2076
2085
|
function daysAgo(n) {
|
|
2077
2086
|
return dayjsPst().subtract(n, "day").format("YYYY-MM-DD");
|
|
2078
2087
|
}
|
|
2079
|
-
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 };
|
|
2088
|
+
export { Countries, Devices, SearchTypes, UnsupportedLogicalCapabilityError, and, between, buildLogicalComparisonPlan, buildLogicalPlan, clicks, contains, country, ctr, currentPstDate, date, dayjs, dayjsPst, daysAgo, device, eq, extractDateRange, extractMetricFilters, extractSearchType, 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 };
|