google-ads-api 24.1.0 → 25.1.0-beta.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.
Files changed (76) hide show
  1. package/README.md +9 -1
  2. package/build/{src → cjs}/client.d.ts +6 -4
  3. package/build/{src → cjs}/client.js +4 -4
  4. package/build/{src → cjs}/customer.d.ts +5 -5
  5. package/build/{src → cjs}/customer.js +24 -20
  6. package/build/{src → cjs}/hooks.d.ts +2 -2
  7. package/build/cjs/index.d.ts +9 -0
  8. package/build/{src → cjs}/index.js +22 -20
  9. package/build/{src → cjs}/parser.d.ts +2 -2
  10. package/build/{src → cjs}/parser.js +5 -5
  11. package/build/{src → cjs}/parserRest.js +7 -7
  12. package/build/{src → cjs}/protos/autogen/enums.d.ts +1679 -1180
  13. package/build/{src → cjs}/protos/autogen/enums.js +1696 -1177
  14. package/build/cjs/protos/autogen/fields.d.ts +1191 -0
  15. package/build/cjs/protos/autogen/fields.js +205 -0
  16. package/build/cjs/protos/autogen/resourceNames.d.ts +1668 -0
  17. package/build/cjs/protos/autogen/resourceNames.js +1669 -0
  18. package/build/{src → cjs}/protos/autogen/serviceFactory.d.ts +206 -215
  19. package/build/{src → cjs}/protos/autogen/serviceFactory.js +483 -554
  20. package/build/cjs/protos/index.d.ts +14 -0
  21. package/build/{src → cjs}/protos/index.js +12 -12
  22. package/build/{src → cjs}/query.d.ts +2 -2
  23. package/build/{src → cjs}/query.js +5 -5
  24. package/build/{src → cjs}/service.d.ts +5 -5
  25. package/build/{src → cjs}/service.js +64 -22
  26. package/build/{src → cjs}/types.d.ts +1 -1
  27. package/build/{src → cjs}/utils.d.ts +1 -1
  28. package/build/{src → cjs}/utils.js +2 -2
  29. package/build/cjs/version.d.ts +1 -0
  30. package/build/{src → cjs}/version.js +1 -1
  31. package/build/esm/client.d.ts +19 -0
  32. package/build/esm/client.js +40 -0
  33. package/build/esm/customer.d.ts +71 -0
  34. package/build/esm/customer.js +502 -0
  35. package/build/esm/hooks.d.ts +160 -0
  36. package/build/esm/hooks.js +1 -0
  37. package/build/esm/index.d.ts +9 -0
  38. package/build/esm/index.js +10 -0
  39. package/build/esm/package.json +1 -0
  40. package/build/esm/parser.d.ts +21 -0
  41. package/build/esm/parser.js +113 -0
  42. package/build/esm/parserRest.d.ts +1 -0
  43. package/build/esm/parserRest.js +112 -0
  44. package/build/esm/protos/autogen/enums.d.ts +6002 -0
  45. package/build/esm/protos/autogen/enums.js +6401 -0
  46. package/build/esm/protos/autogen/fields.d.ts +1191 -0
  47. package/build/esm/protos/autogen/fields.js +202 -0
  48. package/build/esm/protos/autogen/resourceNames.d.ts +1668 -0
  49. package/build/esm/protos/autogen/resourceNames.js +1475 -0
  50. package/build/esm/protos/autogen/serviceFactory.d.ts +1825 -0
  51. package/build/esm/protos/autogen/serviceFactory.js +18795 -0
  52. package/build/esm/protos/index.d.ts +14 -0
  53. package/build/esm/protos/index.js +19 -0
  54. package/build/esm/query.d.ts +62 -0
  55. package/build/esm/query.js +304 -0
  56. package/build/esm/service.d.ts +47 -0
  57. package/build/esm/service.js +222 -0
  58. package/build/esm/types.d.ts +75 -0
  59. package/build/esm/types.js +14 -0
  60. package/build/esm/utils.d.ts +49 -0
  61. package/build/esm/utils.js +108 -0
  62. package/build/esm/version.d.ts +1 -0
  63. package/build/esm/version.js +1 -0
  64. package/package.json +50 -11
  65. package/build/src/index.d.ts +0 -8
  66. package/build/src/protos/autogen/fields.d.ts +0 -1122
  67. package/build/src/protos/autogen/fields.js +0 -644
  68. package/build/src/protos/autogen/resourceNames.d.ts +0 -1609
  69. package/build/src/protos/autogen/resourceNames.js +0 -1982
  70. package/build/src/protos/index.d.ts +0 -14
  71. package/build/src/testUtils.d.ts +0 -107
  72. package/build/src/testUtils.js +0 -333
  73. package/build/src/version.d.ts +0 -1
  74. /package/build/{src → cjs}/hooks.js +0 -0
  75. /package/build/{src → cjs}/parserRest.d.ts +0 -0
  76. /package/build/{src → cjs}/types.js +0 -0
@@ -0,0 +1,21 @@
1
+ import { ReportOptions } from "./types.js";
2
+ import { services } from "./protos/index.js";
3
+ export declare const ParsingError: {
4
+ NO_REPORT_OPTIONS_OR_GAQL_QUERY: string;
5
+ NO_FIELDS_IN_GAQL_QUERY: string;
6
+ NO_FIELDS_IN_REPORT_OPTIONS: string;
7
+ };
8
+ /**
9
+ @description Parse the results of a query
10
+ @example
11
+ const parsedResults = parse({ results, reportOptions })
12
+ const parsedResults = parse({ results, gaqlString })
13
+ */
14
+ export declare function parse({ results, reportOptions, gaqlString, }: {
15
+ results: services.IGoogleAdsRow[];
16
+ reportOptions?: ReportOptions;
17
+ gaqlString?: string;
18
+ }): services.IGoogleAdsRow[];
19
+ export declare function getGAQLFields(gaqlString: string): string[];
20
+ export declare function getReportOptionFields(reportOptions: ReportOptions): string[];
21
+ export declare function parseRows(rows: services.IGoogleAdsRow[], fields: string[]): services.IGoogleAdsRow[];
@@ -0,0 +1,113 @@
1
+ import long from "long";
2
+ import { services, fields } from "./protos/index.js";
3
+ import { normaliseQuery } from "./utils.js";
4
+ export const ParsingError = {
5
+ NO_REPORT_OPTIONS_OR_GAQL_QUERY: "Must provided reportOptions or gaqlString to parse results.",
6
+ NO_FIELDS_IN_GAQL_QUERY: "GAQL Query must contain at least one attribute, metric or segment.",
7
+ NO_FIELDS_IN_REPORT_OPTIONS: "Report Options must contain at least one attribute, metric or segment.",
8
+ };
9
+ /**
10
+ @description Parse the results of a query
11
+ @example
12
+ const parsedResults = parse({ results, reportOptions })
13
+ const parsedResults = parse({ results, gaqlString })
14
+ */
15
+ export function parse({ results, reportOptions, gaqlString, }) {
16
+ if (results.length === 0) {
17
+ return results;
18
+ }
19
+ if (typeof reportOptions === "undefined" &&
20
+ typeof gaqlString === "undefined") {
21
+ throw new Error(ParsingError.NO_REPORT_OPTIONS_OR_GAQL_QUERY);
22
+ }
23
+ const queryFields = reportOptions
24
+ ? getReportOptionFields(reportOptions)
25
+ : getGAQLFields(gaqlString);
26
+ // Add in all relevant resource_name fields, which are always returned by API
27
+ const entities = queryFields.map((field) => field.split(".")[0]);
28
+ const resourceNameFields = fields.resourceNames.filter((resourceNameField) => entities.includes(resourceNameField.split(".")[0]));
29
+ const allFields = [...queryFields, ...resourceNameFields];
30
+ return parseRows(results, allFields);
31
+ }
32
+ // This function assumes that a gaql query is of the format "select * * * from * ...".
33
+ // Queries that are not in this format should have thrown an error when called.
34
+ export function getGAQLFields(gaqlString) {
35
+ const normalisedQuery = normaliseQuery(gaqlString);
36
+ const fields = normalisedQuery
37
+ .toLowerCase()
38
+ .replace(/(^\s*select)|( from .*)|(\s+)/g, "")
39
+ .split(",")
40
+ .filter((field) => field.length > 0);
41
+ if (!fields.length) {
42
+ throw new Error(ParsingError.NO_FIELDS_IN_GAQL_QUERY);
43
+ }
44
+ return fields;
45
+ }
46
+ export function getReportOptionFields(reportOptions) {
47
+ const fields = [
48
+ ...(reportOptions.attributes || []),
49
+ ...(reportOptions.metrics || []),
50
+ ...(reportOptions.segments || []),
51
+ ];
52
+ if (!fields.length) {
53
+ throw new Error(ParsingError.NO_FIELDS_IN_REPORT_OPTIONS);
54
+ }
55
+ return fields;
56
+ }
57
+ export function parseRows(rows, fields) {
58
+ const fieldsPreSplit = {};
59
+ // pre-split all the field strings for performance reasons (increases speed by ~5x for large number of rows)
60
+ for (const field of fields) {
61
+ fieldsPreSplit[field] = field.split(".");
62
+ }
63
+ const newRows = [];
64
+ for (let r = 0; r < rows.length; r++) {
65
+ const newRow = {};
66
+ const originalRow = services.GoogleAdsRow.fromObject(rows[r]);
67
+ for (const split in fieldsPreSplit) {
68
+ // @ts-expect-error These are the best we can do for these types
69
+ const [parent, ...children] = fieldsPreSplit[split];
70
+ // Ignore null fields (unspecified resource names)
71
+ if (!originalRow[parent]) {
72
+ continue;
73
+ }
74
+ newRow[parent] = parseNestedValues(newRow[parent], originalRow[parent], parent, children);
75
+ }
76
+ newRows.push(newRow);
77
+ }
78
+ return newRows;
79
+ }
80
+ function convertLongsToNumbers(value) {
81
+ const isPrimitive = value === null || typeof value !== "object";
82
+ if (isPrimitive) {
83
+ return value;
84
+ }
85
+ if (long.isLong(value)) {
86
+ return value.toNumber();
87
+ }
88
+ if (Array.isArray(value)) {
89
+ return value.map(convertLongsToNumbers);
90
+ }
91
+ const isBytesField = ArrayBuffer.isView(value);
92
+ if (isBytesField) {
93
+ return value;
94
+ }
95
+ const converted = {};
96
+ for (const [key, nestedValue] of Object.entries(value)) {
97
+ converted[key] = convertLongsToNumbers(nestedValue);
98
+ }
99
+ return converted;
100
+ }
101
+ function parseNestedValues(row, data, field, paths) {
102
+ if (!data)
103
+ return null;
104
+ const [parentField, ...childFields] = paths;
105
+ if (!row)
106
+ row = {};
107
+ if (childFields.length === 0) {
108
+ row[parentField] = convertLongsToNumbers(data[parentField]);
109
+ return row;
110
+ }
111
+ row[parentField] = parseNestedValues(row[parentField], data[parentField], parentField, childFields);
112
+ return row;
113
+ }
@@ -0,0 +1 @@
1
+ export declare const decamelizeKeys: (input: any) => any;
@@ -0,0 +1,112 @@
1
+ import { parse } from "circ-json";
2
+ import { toSnakeCase } from "./utils.js";
3
+ import { fieldDataTypes as fieldDataTypesString, fields, } from "./protos/autogen/fields.js";
4
+ import { enums } from "./protos/autogen/enums.js";
5
+ const fieldDataTypes = parse(fieldDataTypesString);
6
+ const decamelizeCache = new Map();
7
+ const fieldTypeCache = new Map();
8
+ const isObject = (value) => typeof value === "object" && value !== null;
9
+ export const decamelizeKeys = (input) => {
10
+ if (!isObject(input)) {
11
+ return input;
12
+ }
13
+ return transform(input);
14
+ function transform(value, parentPath) {
15
+ if (!isObject(value)) {
16
+ return value;
17
+ }
18
+ if (Array.isArray(value)) {
19
+ const length = value.length;
20
+ const result = new Array(length);
21
+ for (let i = 0; i < length; i += 1) {
22
+ const item = value[i];
23
+ result[i] = isObject(item) ? transformObject(item, parentPath) : item;
24
+ }
25
+ return result;
26
+ }
27
+ return transformObject(value, parentPath);
28
+ }
29
+ function transformObject(obj, parentPath) {
30
+ const output = {};
31
+ for (const key of Object.keys(obj)) {
32
+ const rawValue = obj[key];
33
+ const newKey = cachedDecamelize(key);
34
+ if (isObject(rawValue)) {
35
+ const nextParentPath = parentPath === undefined ? newKey : `${parentPath}.${newKey}`;
36
+ output[newKey] = transform(rawValue, nextParentPath);
37
+ }
38
+ else {
39
+ output[newKey] = cachedValueParser(newKey, parentPath, rawValue);
40
+ }
41
+ }
42
+ return output;
43
+ }
44
+ };
45
+ const cachedDecamelize = (key) => {
46
+ const cachedResult = decamelizeCache.get(key);
47
+ if (cachedResult) {
48
+ return cachedResult;
49
+ }
50
+ const newKey = toSnakeCase(key);
51
+ decamelizeCache.set(key, newKey);
52
+ return newKey;
53
+ };
54
+ const cachedValueParser = (key, parentPath, value) => {
55
+ let newValue = value;
56
+ const fullPath = parentPath ? `${parentPath}.${key}` : key;
57
+ const megaDataType = getTypeFromPath(fullPath);
58
+ if (megaDataType === undefined && !fullPath.startsWith("@")) {
59
+ console.warn(`No data type found for ${fullPath}`);
60
+ }
61
+ else if (typeof megaDataType === "object") {
62
+ // Special handling for FieldMask types - REST API returns them as comma-separated strings
63
+ if (megaDataType.paths === "STRING" && typeof value === "string") {
64
+ // This is a FieldMask field, convert the comma-separated string to the expected format
65
+ // Also convert each path from camelCase to snake_case
66
+ newValue = {
67
+ paths: value.split(",").map((p) => {
68
+ // Handle nested paths like "ipBlock.ipAddress"
69
+ return p
70
+ .trim()
71
+ .split(".")
72
+ .map((segment) => toSnakeCase(segment))
73
+ .join(".");
74
+ }),
75
+ };
76
+ }
77
+ else {
78
+ // Normal enum handling
79
+ newValue = megaDataType[value];
80
+ }
81
+ }
82
+ else if (megaDataType === "INT64") {
83
+ newValue = Number(value);
84
+ }
85
+ else if (megaDataType === "ENUM") {
86
+ // Some enums aren't embedded in megaDataType, so we need this fallback.
87
+ // @ts-expect-error typescript doesn't like accessing items in a namespace with a string
88
+ newValue = enums[fields.enumFields[fullPath]][value]; // e.g. enums['CampaignStatus'][ENABLED] = "2"
89
+ }
90
+ return newValue;
91
+ };
92
+ const getTypeFromPath = (path) => {
93
+ const cachedResult = fieldTypeCache.get(path);
94
+ if (cachedResult) {
95
+ return cachedResult;
96
+ }
97
+ const t = get(fieldDataTypes, path);
98
+ fieldTypeCache.set(path, t);
99
+ return t;
100
+ };
101
+ // Copied from youmightnotneed.com
102
+ const get = (obj, path) => {
103
+ if (!path)
104
+ return undefined;
105
+ // Check if path is string or array. Regex : ensure that we do not have '.' and brackets.
106
+ // Regex explained: https://regexr.com/58j0k
107
+ const pathArray = path.match(/([^[.\]])+/g);
108
+ if (!pathArray)
109
+ return undefined;
110
+ // Find value
111
+ return pathArray.reduce((prevObj, key) => prevObj && prevObj[key], obj);
112
+ };