@lightdash/warehouses 2.152.0 → 2.153.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.
@@ -28,7 +28,7 @@ export declare const getBigqueryTimestampDomain: (type: string | undefined) => T
28
28
  type TableSchema = {
29
29
  fields: SchemaFields[];
30
30
  };
31
- type SchemaFields = Required<Pick<bigquery.ITableFieldSchema, 'name' | 'type'>>;
31
+ type SchemaFields = Required<Pick<bigquery.ITableFieldSchema, 'name' | 'type'>> & Pick<bigquery.ITableFieldSchema, 'mode' | 'fields'>;
32
32
  type BigqueryError = {
33
33
  errors: bigquery.IErrorProto[];
34
34
  };
@@ -1 +1 @@
1
- {"version":3,"file":"BigqueryWarehouseClient.d.ts","sourceRoot":"","sources":["../../src/warehouseClients/BigqueryWarehouseClient.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"BigqueryWarehouseClient.d.ts","sourceRoot":"","sources":["../../src/warehouseClients/BigqueryWarehouseClient.ts"],"names":[],"mappings":"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"}
@@ -47,6 +47,34 @@ const isBigqueryDecimal = (value) => typeof value === 'object' &&
47
47
  Array.isArray(value.c) &&
48
48
  value.c.length > 0 &&
49
49
  value.c.every((digit) => typeof digit === 'number');
50
+ const isBigqueryTemporal = (cell) => cell instanceof bigquery_1.BigQueryDate ||
51
+ cell instanceof bigquery_1.BigQueryTimestamp ||
52
+ cell instanceof bigquery_1.BigQueryDatetime ||
53
+ cell instanceof bigquery_1.BigQueryTime;
54
+ const isPlainObject = (value) => typeof value === 'object' &&
55
+ value !== null &&
56
+ Object.getPrototypeOf(value) === Object.prototype;
57
+ // STRUCT and ARRAY values arrive as plain objects/arrays whose leaves are the
58
+ // same SDK wrappers as top-level cells, so leaves are normalised before the
59
+ // whole value is serialised.
60
+ const normaliseNestedValue = (value) => {
61
+ if (Array.isArray(value)) {
62
+ return value.map(normaliseNestedValue);
63
+ }
64
+ if (isBigqueryTemporal(value)) {
65
+ return value.value;
66
+ }
67
+ if (isBigqueryDecimal(value)) {
68
+ return Number(value.toFixed());
69
+ }
70
+ if (isPlainObject(value)) {
71
+ return Object.fromEntries(Object.entries(value).map(([key, nested]) => [
72
+ key,
73
+ normaliseNestedValue(nested),
74
+ ]));
75
+ }
76
+ return value;
77
+ };
50
78
  const parseCell = (cell) => {
51
79
  if (cell === undefined ||
52
80
  cell === null ||
@@ -54,15 +82,15 @@ const parseCell = (cell) => {
54
82
  typeof cell === 'number') {
55
83
  return cell;
56
84
  }
57
- if (cell instanceof bigquery_1.BigQueryDate ||
58
- cell instanceof bigquery_1.BigQueryTimestamp ||
59
- cell instanceof bigquery_1.BigQueryDatetime ||
60
- cell instanceof bigquery_1.BigQueryTime) {
85
+ if (isBigqueryTemporal(cell)) {
61
86
  return new Date(cell.value);
62
87
  }
63
88
  if (isBigqueryDecimal(cell)) {
64
89
  return Number(cell.toFixed());
65
90
  }
91
+ if (Array.isArray(cell) || isPlainObject(cell)) {
92
+ return JSON.stringify(normaliseNestedValue(cell));
93
+ }
66
94
  return `${cell}`;
67
95
  };
68
96
  const getBigqueryTimestampDomain = (type) => {
@@ -101,6 +129,28 @@ const mapFieldType = (type) => {
101
129
  };
102
130
  const isSchemaFields = (rawSchemaFields) => rawSchemaFields.every((field) => field.type && field.name);
103
131
  const isTableSchema = (schema) => !!schema && !!schema.fields && isSchemaFields(schema.fields);
132
+ const BIGQUERY_REPEATED_MODE = 'REPEATED';
133
+ const isRecordType = (type) => type === BigqueryFieldType.RECORD || type === BigqueryFieldType.STRUCT;
134
+ /**
135
+ * Walks nested RECORD fields depth-first, emitting every node under its dotted
136
+ * path. A record node is kept alongside its children so the container column
137
+ * still resolves; the shape says whether it is a struct, an array, or both.
138
+ */
139
+ const flattenSchemaFields = (fields, prefix = '') => fields.flatMap((field) => {
140
+ if (!field.name || !field.type)
141
+ return [];
142
+ const path = prefix ? `${prefix}.${field.name}` : field.name;
143
+ const repeated = field.mode === BIGQUERY_REPEATED_MODE;
144
+ const record = isRecordType(field.type);
145
+ const node = {
146
+ path,
147
+ type: field.type,
148
+ shape: repeated || record ? { repeated, record } : undefined,
149
+ };
150
+ return record
151
+ ? [node, ...flattenSchemaFields(field.fields ?? [], path)]
152
+ : [node];
153
+ });
104
154
  const parseRow = (row) => Object.fromEntries(Object.entries(row).map(([name, value]) => [name, parseCell(value)]));
105
155
  class BigquerySqlBuilder extends WarehouseBaseSqlBuilder_1.default {
106
156
  constructor() {
@@ -408,11 +458,10 @@ class BigqueryWarehouseClient extends WarehouseBaseClient_1.default {
408
458
  acc[database] = acc[database] || {};
409
459
  acc[database][schema] = acc[database][schema] || {};
410
460
  acc[database][schema][table] = {};
411
- tableSchema.fields.forEach(({ name, type }) => {
412
- if (name === undefined)
413
- return;
414
- acc[database][schema][table][name] = mapFieldType(type);
415
- (0, common_1.setCatalogTimestampDomain)(acc, database, schema, table, name, (0, exports.getBigqueryTimestampDomain)(type));
461
+ flattenSchemaFields(tableSchema.fields).forEach(({ path, type, shape }) => {
462
+ acc[database][schema][table][path] = mapFieldType(type);
463
+ (0, common_1.setCatalogTimestampDomain)(acc, database, schema, table, path, (0, exports.getBigqueryTimestampDomain)(type));
464
+ (0, common_1.setCatalogNestedColumnShape)(acc, database, schema, table, path, shape);
416
465
  });
417
466
  }
418
467
  return acc;
@@ -474,17 +523,20 @@ class BigqueryWarehouseClient extends WarehouseBaseClient_1.default {
474
523
  const dataset = new bigquery_1.Dataset(this.client, schema, {
475
524
  projectId: database,
476
525
  });
477
- const schemas = await BigqueryWarehouseClient.getTableMetadata(dataset, tableName).catch((e) => {
526
+ const [tableCatalog, tableSchema, table, metadataSchema] = await BigqueryWarehouseClient.getTableMetadata(dataset, tableName).catch((e) => {
478
527
  this.throwIfGoogleOauthTokenError(e);
479
528
  throw e;
480
529
  });
481
- return this.parseWarehouseCatalog(schemas[3].fields.map((column) => ({
482
- table_catalog: schemas[0],
483
- table_schema: schemas[1],
484
- table_name: schemas[2],
485
- column_name: column.name,
486
- data_type: column.type,
530
+ const flattenedFields = flattenSchemaFields(metadataSchema.fields);
531
+ const catalog = this.parseWarehouseCatalog(flattenedFields.map(({ path, type }) => ({
532
+ table_catalog: tableCatalog,
533
+ table_schema: tableSchema,
534
+ table_name: table,
535
+ column_name: path,
536
+ data_type: type,
487
537
  })), mapFieldType, exports.getBigqueryTimestampDomain);
538
+ flattenedFields.forEach(({ path, shape }) => (0, common_1.setCatalogNestedColumnShape)(catalog, tableCatalog, tableSchema, table, path, shape));
539
+ return catalog;
488
540
  }
489
541
  parseError(error, query = '') {
490
542
  // if the error has no reason, return a generic error
@@ -9,10 +9,35 @@ export declare const getTableResponse: {
9
9
  };
10
10
  getMetadata: import("vitest").Mock<() => {
11
11
  schema: {
12
- fields: {
12
+ fields: ({
13
13
  name: string;
14
14
  type: BigqueryFieldType;
15
- }[];
15
+ mode?: undefined;
16
+ fields?: undefined;
17
+ } | {
18
+ name: string;
19
+ type: BigqueryFieldType;
20
+ mode: string;
21
+ fields?: undefined;
22
+ } | {
23
+ name: string;
24
+ type: BigqueryFieldType;
25
+ mode: string;
26
+ fields: ({
27
+ mode?: undefined;
28
+ fields?: undefined;
29
+ name: string;
30
+ type: BigqueryFieldType;
31
+ } | {
32
+ name: string;
33
+ type: BigqueryFieldType;
34
+ mode: string;
35
+ fields: {
36
+ name: string;
37
+ type: BigqueryFieldType;
38
+ }[];
39
+ })[];
40
+ })[];
16
41
  };
17
42
  }[]>;
18
43
  };
@@ -21,10 +46,35 @@ declare const mockStreamRow: () => Readable;
21
46
  export declare const createJobResponse: {
22
47
  getQueryResults: import("vitest").Mock<() => (Record<string, any>[] | {
23
48
  schema: {
24
- fields: {
49
+ fields: ({
50
+ name: string;
51
+ type: BigqueryFieldType;
52
+ mode?: undefined;
53
+ fields?: undefined;
54
+ } | {
55
+ name: string;
56
+ type: BigqueryFieldType;
57
+ mode: string;
58
+ fields?: undefined;
59
+ } | {
25
60
  name: string;
26
61
  type: BigqueryFieldType;
27
- }[];
62
+ mode: string;
63
+ fields: ({
64
+ mode?: undefined;
65
+ fields?: undefined;
66
+ name: string;
67
+ type: BigqueryFieldType;
68
+ } | {
69
+ name: string;
70
+ type: BigqueryFieldType;
71
+ mode: string;
72
+ fields: {
73
+ name: string;
74
+ type: BigqueryFieldType;
75
+ }[];
76
+ })[];
77
+ })[];
28
78
  };
29
79
  } | undefined)[]>;
30
80
  getQueryResultsStream: import("vitest").Mock<typeof mockStreamRow>;
@@ -1 +1 @@
1
- {"version":3,"file":"BigqueryWarehouseClient.mock.d.ts","sourceRoot":"","sources":["../../src/warehouseClients/BigqueryWarehouseClient.mock.ts"],"names":[],"mappings":"AAKA,OAAO,EACH,OAAO,EACP,yBAAyB,EAE5B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAClC,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAE9D,eAAO,MAAM,WAAW,EAAE,yBAUzB,CAAC;AAyCF,eAAO,MAAM,gBAAgB;IACzB,EAAE;IACF,QAAQ;QAAI,SAAS;;IACrB,WAAW;;;;;;;;CACd,CAAC;AAwBF,eAAO,MAAM,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAUzC,CAAC;AAEF,QAAA,MAAM,aAAa,gBAOb,CAAC;AAEP,eAAO,MAAM,iBAAiB;;;;;;;;;;GAK7B,CAAC"}
1
+ {"version":3,"file":"BigqueryWarehouseClient.mock.d.ts","sourceRoot":"","sources":["../../src/warehouseClients/BigqueryWarehouseClient.mock.ts"],"names":[],"mappings":"AAKA,OAAO,EACH,OAAO,EACP,yBAAyB,EAE5B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAClC,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAE9D,eAAO,MAAM,WAAW,EAAE,yBAUzB,CAAC;AA+DF,eAAO,MAAM,gBAAgB;IACzB,EAAE;IACF,QAAQ;QAAI,SAAS;;IACrB,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CACd,CAAC;AAwBF,eAAO,MAAM,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAgBzC,CAAC;AAEF,QAAA,MAAM,aAAa,gBAOb,CAAC;AAEP,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAK7B,CAAC"}
@@ -51,6 +51,28 @@ const metadata = {
51
51
  name: 'myObjectColumn',
52
52
  type: BigqueryWarehouseClient_1.BigqueryFieldType.STRUCT,
53
53
  },
54
+ {
55
+ name: 'myRepeatedColumn',
56
+ type: BigqueryWarehouseClient_1.BigqueryFieldType.STRING,
57
+ mode: 'REPEATED',
58
+ },
59
+ {
60
+ name: 'myRecordColumn',
61
+ type: BigqueryWarehouseClient_1.BigqueryFieldType.RECORD,
62
+ mode: 'NULLABLE',
63
+ fields: [
64
+ { name: 'id', type: BigqueryWarehouseClient_1.BigqueryFieldType.INT64 },
65
+ { name: 'createdAt', type: BigqueryWarehouseClient_1.BigqueryFieldType.TIMESTAMP },
66
+ {
67
+ name: 'tags',
68
+ type: BigqueryWarehouseClient_1.BigqueryFieldType.RECORD,
69
+ mode: 'REPEATED',
70
+ fields: [
71
+ { name: 'label', type: BigqueryWarehouseClient_1.BigqueryFieldType.STRING },
72
+ ],
73
+ },
74
+ ],
75
+ },
54
76
  ],
55
77
  },
56
78
  };
@@ -85,6 +107,12 @@ exports.rows = [
85
107
  myBooleanColumn: false,
86
108
  myArrayColumn: ['1', '2', '3'],
87
109
  myObjectColumn: { test: '1', toFixed: () => '123' },
110
+ myRepeatedColumn: ['a', 'b'],
111
+ myRecordColumn: {
112
+ id: 7,
113
+ createdAt: new bigquery_1.BigQueryTimestamp('1990-03-02T08:30:00.010Z'),
114
+ tags: [{ label: 'x' }, { label: 'y' }],
115
+ },
88
116
  },
89
117
  ];
90
118
  const mockStreamRow = () => new stream_1.Readable({
@@ -13,11 +13,18 @@ describe('BigqueryWarehouseClient', () => {
13
13
  expect(results.fields).toEqual({
14
14
  ...WarehouseClient_mock_1.expectedFields,
15
15
  myBigNumberColumn: { type: 'number' },
16
+ myRepeatedColumn: { type: 'string' },
17
+ myRecordColumn: { type: 'string' },
16
18
  });
17
19
  expect(results.rows[0]).toEqual({
18
20
  ...WarehouseClient_mock_1.expectedRow,
19
21
  myNumberColumn: 100.25,
20
22
  myBigNumberColumn: 200.5,
23
+ // BigQuery serialises nested values as JSON; other clients pass them through
24
+ myArrayColumn: '["1","2","3"]',
25
+ myObjectColumn: '{"test":"1"}',
26
+ myRepeatedColumn: '["a","b"]',
27
+ myRecordColumn: '{"id":7,"createdAt":"1990-03-02T08:30:00.010Z","tags":[{"label":"x"},{"label":"y"}]}',
21
28
  });
22
29
  expect(warehouse.client.createQueryJob).toHaveBeenCalledTimes(1);
23
30
  });
@@ -46,12 +53,37 @@ describe('BigqueryWarehouseClient', () => {
46
53
  bigquery_1.Dataset.prototype.table = getTableMock;
47
54
  const warehouse = new BigqueryWarehouseClient_1.BigqueryWarehouseClient(BigqueryWarehouseClient_mock_1.credentials);
48
55
  const expectedCatalog = structuredClone(WarehouseClient_mock_1.expectedWarehouseSchemaWithAwareTimestamp);
49
- expectedCatalog.myDatabase.mySchema.myTable.myBigNumberColumn =
50
- common_1.DimensionType.NUMBER;
56
+ Object.assign(expectedCatalog.myDatabase.mySchema.myTable, {
57
+ myBigNumberColumn: common_1.DimensionType.NUMBER,
58
+ myRepeatedColumn: common_1.DimensionType.STRING,
59
+ myRecordColumn: common_1.DimensionType.STRING,
60
+ 'myRecordColumn.id': common_1.DimensionType.NUMBER,
61
+ 'myRecordColumn.createdAt': common_1.DimensionType.TIMESTAMP,
62
+ 'myRecordColumn.tags': common_1.DimensionType.STRING,
63
+ 'myRecordColumn.tags.label': common_1.DimensionType.STRING,
64
+ });
65
+ (0, common_1.setCatalogTimestampDomain)(expectedCatalog, 'myDatabase', 'mySchema', 'myTable', 'myRecordColumn.createdAt', 'aware');
66
+ const nestedShapes = {
67
+ myObjectColumn: { repeated: false, record: true },
68
+ myRepeatedColumn: { repeated: true, record: false },
69
+ myRecordColumn: { repeated: false, record: true },
70
+ 'myRecordColumn.tags': { repeated: true, record: true },
71
+ };
72
+ Object.entries(nestedShapes).forEach(([path, shape]) => (0, common_1.setCatalogNestedColumnShape)(expectedCatalog, 'myDatabase', 'mySchema', 'myTable', path, shape));
51
73
  expect(await warehouse.getCatalog(WarehouseClient_mock_1.config)).toEqual(expectedCatalog);
52
74
  expect(getTableMock).toHaveBeenCalledTimes(1);
53
75
  expect(BigqueryWarehouseClient_mock_1.getTableResponse.getMetadata).toHaveBeenCalledTimes(1);
54
76
  });
77
+ it('expect getFields to flatten nested columns with the same shapes as getCatalog', async () => {
78
+ bigquery_1.Dataset.prototype.table = vi
79
+ .fn()
80
+ .mockImplementationOnce(() => BigqueryWarehouseClient_mock_1.getTableResponse);
81
+ const warehouse = new BigqueryWarehouseClient_1.BigqueryWarehouseClient(BigqueryWarehouseClient_mock_1.credentials);
82
+ const fields = await warehouse.getFields('myTable', 'mySchema', 'myDatabase');
83
+ expect(fields.myDatabase.mySchema.myTable['myRecordColumn.id']).toBe(common_1.DimensionType.NUMBER);
84
+ expect((0, common_1.getCatalogNestedColumnShape)(fields, 'myDatabase', 'mySchema', 'myTable', 'myRecordColumn.tags')).toEqual({ repeated: true, record: true });
85
+ expect((0, common_1.getCatalogNestedColumnShape)(fields, 'myDatabase', 'mySchema', 'myTable', 'myStringColumn')).toBeUndefined();
86
+ });
55
87
  });
56
88
  describe('BigqueryWarehouseClient.getDatabases', () => {
57
89
  const createDataset = (datasetId) => new bigquery_1.Dataset(new bigquery_1.BigQuery({ projectId: 'test-project' }), datasetId, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lightdash/warehouses",
3
- "version": "2.152.0",
3
+ "version": "2.153.0",
4
4
  "description": "Warehouse connectors for Lightdash",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -28,7 +28,7 @@
28
28
  "snowflake-sdk": "2.3.4",
29
29
  "ssh2": "1.14.0",
30
30
  "trino-client": "0.2.9",
31
- "@lightdash/common": "2.152.0"
31
+ "@lightdash/common": "2.153.0"
32
32
  },
33
33
  "devDependencies": {
34
34
  "oxlint": "1.75.0",