@malloydata/db-bigquery 0.0.96-dev231025215721 → 0.0.96

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.
@@ -166,5 +166,94 @@ describe('db:BigQuery', () => {
166
166
  expect(results[0]).toStrictEqual({ t: 1 });
167
167
  });
168
168
  });
169
+ describe('Caching', () => {
170
+ let getTableFieldSchema;
171
+ let getSQLBlockSchema;
172
+ beforeEach(async () => {
173
+ getTableFieldSchema = jest
174
+ .spyOn(bigquery_connection_1.BigQueryConnection.prototype, 'getTableFieldSchema')
175
+ .mockResolvedValue({
176
+ schema: {},
177
+ needsTableSuffixPseudoColumn: false,
178
+ needsPartitionTimePseudoColumn: false,
179
+ needsPartitionDatePseudoColumn: false,
180
+ });
181
+ getSQLBlockSchema = jest
182
+ .spyOn(bigquery_connection_1.BigQueryConnection.prototype, 'getSQLBlockSchema')
183
+ .mockResolvedValue({
184
+ schema: {},
185
+ needsTableSuffixPseudoColumn: false,
186
+ needsPartitionTimePseudoColumn: false,
187
+ needsPartitionDatePseudoColumn: false,
188
+ });
189
+ });
190
+ afterEach(() => {
191
+ jest.resetAllMocks();
192
+ });
193
+ it('caches table schema', async () => {
194
+ await bq.fetchSchemaForTables({ 'test1': 'table1' }, {});
195
+ expect(getTableFieldSchema).toBeCalledTimes(1);
196
+ await new Promise(resolve => setTimeout(resolve));
197
+ await bq.fetchSchemaForTables({ 'test1': 'table1' }, {});
198
+ expect(getTableFieldSchema).toBeCalledTimes(1);
199
+ });
200
+ it('refreshes table schema', async () => {
201
+ await bq.fetchSchemaForTables({ 'test2': 'table2' }, {});
202
+ expect(getTableFieldSchema).toBeCalledTimes(1);
203
+ await new Promise(resolve => setTimeout(resolve));
204
+ await bq.fetchSchemaForTables({ 'test2': 'table2' }, { refreshTimestamp: Date.now() });
205
+ expect(getTableFieldSchema).toBeCalledTimes(2);
206
+ });
207
+ it('caches sql schema', async () => {
208
+ await bq.fetchSchemaForSQLBlock(SQL_BLOCK_1, {});
209
+ expect(getSQLBlockSchema).toBeCalledTimes(1);
210
+ await new Promise(resolve => setTimeout(resolve));
211
+ await bq.fetchSchemaForSQLBlock(SQL_BLOCK_1, {});
212
+ expect(getSQLBlockSchema).toBeCalledTimes(1);
213
+ });
214
+ it('refreshes sql schema', async () => {
215
+ await bq.fetchSchemaForSQLBlock(SQL_BLOCK_2, {});
216
+ expect(getSQLBlockSchema).toBeCalledTimes(1);
217
+ await new Promise(resolve => setTimeout(resolve));
218
+ await bq.fetchSchemaForSQLBlock(SQL_BLOCK_2, {
219
+ refreshTimestamp: Date.now(),
220
+ });
221
+ expect(getSQLBlockSchema).toBeCalledTimes(2);
222
+ });
223
+ });
169
224
  });
225
+ const SQL_BLOCK_1 = {
226
+ type: 'sqlBlock',
227
+ name: 'block1',
228
+ selectStr: `
229
+ SELECT
230
+ created_at,
231
+ sale_price,
232
+ inventory_item_id
233
+ FROM 'order_items.parquet'
234
+ SELECT
235
+ id,
236
+ product_department,
237
+ product_category,
238
+ created_at AS inventory_items_created_at
239
+ FROM "inventory_items.parquet"
240
+ `,
241
+ };
242
+ const SQL_BLOCK_2 = {
243
+ type: 'sqlBlock',
244
+ name: 'block2',
245
+ selectStr: `
246
+ SELECT
247
+ created_at,
248
+ sale_price,
249
+ inventory_item_id
250
+ FROM read_parquet('order_items2.parquet', arg='value')
251
+ SELECT
252
+ id,
253
+ product_department,
254
+ product_category,
255
+ created_at AS inventory_items_created_at
256
+ FROM read_parquet("inventory_items2.parquet")
257
+ `,
258
+ };
170
259
  //# sourceMappingURL=bigquery.spec.js.map
@@ -2,6 +2,7 @@ import { RowMetadata } from '@google-cloud/bigquery';
2
2
  import bigquery from '@google-cloud/bigquery/build/src/types';
3
3
  import { ResourceStream } from '@google-cloud/paginator';
4
4
  import { Connection, MalloyQueryData, PersistSQLResults, PooledConnection, QueryData, QueryDataRow, QueryRunStats, SQLBlock, StreamingConnection, StructDef } from '@malloydata/malloy';
5
+ import { FetchSchemaOptions } from '@malloydata/malloy-interfaces';
5
6
  export interface BigQueryManagerOptions {
6
7
  credentials?: {
7
8
  clientId: string;
@@ -77,12 +78,12 @@ export declare class BigQueryConnection implements Connection, PersistSQLResults
77
78
  private addFieldsToStructDef;
78
79
  private structDefFromTableSchema;
79
80
  private structDefFromSQLSchema;
80
- fetchSchemaForTables(missing: Record<string, string>): Promise<{
81
+ fetchSchemaForTables(missing: Record<string, string>, { refreshTimestamp }: FetchSchemaOptions): Promise<{
81
82
  schemas: Record<string, StructDef>;
82
83
  errors: Record<string, string>;
83
84
  }>;
84
85
  private getSQLBlockSchema;
85
- fetchSchemaForSQLBlock(sqlRef: SQLBlock): Promise<{
86
+ fetchSchemaForSQLBlock(sqlRef: SQLBlock, { refreshTimestamp }: FetchSchemaOptions): Promise<{
86
87
  structDef: StructDef;
87
88
  error?: undefined;
88
89
  } | {
@@ -442,22 +442,25 @@ class BigQueryConnection {
442
442
  this.addFieldsToStructDef(structDef, tableFieldSchema);
443
443
  return structDef;
444
444
  }
445
- async fetchSchemaForTables(missing) {
445
+ async fetchSchemaForTables(missing, { refreshTimestamp }) {
446
446
  const schemas = {};
447
447
  const errors = {};
448
448
  for (const tableKey in missing) {
449
449
  let inCache = this.schemaCache.get(tableKey);
450
- if (!inCache) {
450
+ if (!inCache ||
451
+ (refreshTimestamp && refreshTimestamp > inCache.timestamp)) {
452
+ const timestamp = refreshTimestamp !== null && refreshTimestamp !== void 0 ? refreshTimestamp : Date.now();
451
453
  const tablePath = this.normalizeTablePath(missing[tableKey]);
452
454
  try {
453
455
  const tableFieldSchema = await this.getTableFieldSchema(tablePath);
454
456
  inCache = {
455
457
  schema: this.structDefFromTableSchema(tableKey, tablePath, tableFieldSchema),
458
+ timestamp,
456
459
  };
457
460
  this.schemaCache.set(tableKey, inCache);
458
461
  }
459
462
  catch (error) {
460
- inCache = { error: error.message };
463
+ inCache = { error: error.message, timestamp };
461
464
  }
462
465
  }
463
466
  if (inCache.schema !== undefined) {
@@ -491,18 +494,21 @@ class BigQueryConnection {
491
494
  }
492
495
  throw lastFetchError;
493
496
  }
494
- async fetchSchemaForSQLBlock(sqlRef) {
497
+ async fetchSchemaForSQLBlock(sqlRef, { refreshTimestamp }) {
495
498
  const key = sqlRef.name;
496
499
  let inCache = this.sqlSchemaCache.get(key);
497
- if (!inCache) {
500
+ if (!inCache ||
501
+ (refreshTimestamp && refreshTimestamp > inCache.timestamp)) {
502
+ const timestamp = refreshTimestamp !== null && refreshTimestamp !== void 0 ? refreshTimestamp : Date.now();
498
503
  try {
499
504
  const tableFieldSchema = await this.getSQLBlockSchema(sqlRef);
500
505
  inCache = {
501
506
  structDef: this.structDefFromSQLSchema(sqlRef, tableFieldSchema),
507
+ timestamp,
502
508
  };
503
509
  }
504
510
  catch (error) {
505
- inCache = { error: error.message };
511
+ inCache = { error: error.message, timestamp };
506
512
  }
507
513
  this.sqlSchemaCache.set(key, inCache);
508
514
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@malloydata/db-bigquery",
3
- "version": "0.0.96-dev231025215721",
3
+ "version": "0.0.96",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -25,7 +25,8 @@
25
25
  "@google-cloud/bigquery": "^5.5.0",
26
26
  "@google-cloud/common": "^3.6.0",
27
27
  "@google-cloud/paginator": "^4.0.1",
28
- "@malloydata/malloy": "^0.0.96-dev231025215721",
28
+ "@malloydata/malloy": "^0.0.96",
29
+ "@malloydata/malloy-interfaces": "^0.0.96",
29
30
  "gaxios": "^4.2.0"
30
31
  }
31
32
  }