@observablehq/notebook-kit 1.1.0 → 1.2.0-rc.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/bin/query.js +24 -15
- package/dist/package.json +6 -1
- package/dist/src/databases/bigquery.d.ts +5 -0
- package/dist/src/databases/bigquery.js +59 -0
- package/dist/src/databases/index.d.ts +12 -1
- package/dist/src/databases/index.js +10 -0
- package/dist/src/databases/snowflake.d.ts +3 -0
- package/dist/src/databases/snowflake.js +6 -0
- package/package.json +6 -1
package/dist/bin/query.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
2
4
|
import { parseArgs } from "node:util";
|
|
3
5
|
import { getDatabase, getDatabaseConfig, getQueryCachePath } from "../src/databases/index.js";
|
|
4
|
-
import {
|
|
5
|
-
import { mkdir, writeFile } from "node:fs/promises";
|
|
6
|
-
import { join } from "node:path";
|
|
6
|
+
import { getReplacer } from "../src/databases/index.js";
|
|
7
7
|
if (process.argv[1] === import.meta.filename)
|
|
8
8
|
run();
|
|
9
9
|
export default async function run(args) {
|
|
@@ -43,17 +43,26 @@ export default async function run(args) {
|
|
|
43
43
|
else
|
|
44
44
|
strings.push(positionals[i]);
|
|
45
45
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
46
|
+
try {
|
|
47
|
+
process.chdir(values.root);
|
|
48
|
+
const cachePath = await getQueryCachePath(".", values.database, strings, ...params);
|
|
49
|
+
const config = await getDatabaseConfig(".", values.database);
|
|
50
|
+
const database = await getDatabase(config);
|
|
51
|
+
const results = await database.call(null, strings, ...params);
|
|
52
|
+
await mkdir(dirname(cachePath), { recursive: true });
|
|
53
|
+
await writeFile(cachePath, JSON.stringify(results, await getReplacer(config)));
|
|
54
|
+
console.log(join(values.root, cachePath));
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
console.error(getErrorMessage(error));
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
54
60
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
61
|
+
function getErrorMessage(error) {
|
|
62
|
+
return error instanceof Error &&
|
|
63
|
+
"errors" in error && // AggregateError
|
|
64
|
+
Array.isArray(error.errors) &&
|
|
65
|
+
error.errors.length > 0
|
|
66
|
+
? String(error.errors[0])
|
|
67
|
+
: String(error);
|
|
59
68
|
}
|
package/dist/package.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/observablehq/notebook-kit.git"
|
|
7
7
|
},
|
|
8
|
-
"version": "1.
|
|
8
|
+
"version": "1.2.0-rc.1",
|
|
9
9
|
"type": "module",
|
|
10
10
|
"scripts": {
|
|
11
11
|
"test": "vitest",
|
|
@@ -65,6 +65,7 @@
|
|
|
65
65
|
"devDependencies": {
|
|
66
66
|
"@duckdb/node-api": "^1.3.2-alpha.26",
|
|
67
67
|
"@eslint/js": "^9.29.0",
|
|
68
|
+
"@google-cloud/bigquery": "^8.1.1",
|
|
68
69
|
"@types/jsdom": "^21.1.7",
|
|
69
70
|
"@types/markdown-it": "^14.1.2",
|
|
70
71
|
"bun-types": "^1.2.20",
|
|
@@ -80,6 +81,7 @@
|
|
|
80
81
|
},
|
|
81
82
|
"peerDependencies": {
|
|
82
83
|
"@duckdb/node-api": "^1.3.2-alpha.26",
|
|
84
|
+
"@google-cloud/bigquery": "^8.1.1",
|
|
83
85
|
"postgres": "^3.4.7",
|
|
84
86
|
"snowflake-sdk": "^2.1.3"
|
|
85
87
|
},
|
|
@@ -87,6 +89,9 @@
|
|
|
87
89
|
"@duckdb/node-api": {
|
|
88
90
|
"optional": true
|
|
89
91
|
},
|
|
92
|
+
"@google-cloud/bigquery": {
|
|
93
|
+
"optional": true
|
|
94
|
+
},
|
|
90
95
|
"postgres": {
|
|
91
96
|
"optional": true
|
|
92
97
|
},
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { BigQueryConfig, QueryTemplateFunction } from "./index.js";
|
|
2
|
+
export default function bigquery({ type, ...options }: BigQueryConfig): QueryTemplateFunction;
|
|
3
|
+
export declare function replacer(this: {
|
|
4
|
+
[key: string]: unknown;
|
|
5
|
+
}, key: string, value: unknown): unknown;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { BigQuery } from "@google-cloud/bigquery";
|
|
2
|
+
import { BigQueryDate, BigQueryDatetime, BigQueryTimestamp } from "@google-cloud/bigquery";
|
|
3
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
4
|
+
export default function bigquery({ type, ...options }) {
|
|
5
|
+
return async (strings, ...params) => {
|
|
6
|
+
const bigquery = new BigQuery(options);
|
|
7
|
+
const date = new Date();
|
|
8
|
+
const [job] = await bigquery.createQueryJob({ query: strings.join("?"), params });
|
|
9
|
+
const [rows, , response] = await job.getQueryResults();
|
|
10
|
+
return { rows, schema: getTableSchema(response.schema), duration: Date.now() - +date, date };
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
function getTableSchema({ fields }) {
|
|
14
|
+
return fields.map(getColumnSchema);
|
|
15
|
+
}
|
|
16
|
+
function getColumnSchema(field) {
|
|
17
|
+
return { name: field.name, type: getColumnType(field) };
|
|
18
|
+
}
|
|
19
|
+
function getColumnType({ type, mode }) {
|
|
20
|
+
switch (mode) {
|
|
21
|
+
case "REPEATED":
|
|
22
|
+
return "array";
|
|
23
|
+
}
|
|
24
|
+
switch (type) {
|
|
25
|
+
case "DATE":
|
|
26
|
+
case "DATETIME":
|
|
27
|
+
case "TIMESTAMP":
|
|
28
|
+
return "date";
|
|
29
|
+
case "BOOL":
|
|
30
|
+
case "BOOLEAN":
|
|
31
|
+
return "boolean";
|
|
32
|
+
case "STRUCT":
|
|
33
|
+
case "RECORD":
|
|
34
|
+
case "GEOGRAPHY":
|
|
35
|
+
return "object";
|
|
36
|
+
case "BYTES":
|
|
37
|
+
return "buffer";
|
|
38
|
+
case "FLOAT":
|
|
39
|
+
case "FLOAT64":
|
|
40
|
+
return "number";
|
|
41
|
+
case "INT64":
|
|
42
|
+
case "INTEGER":
|
|
43
|
+
return "number";
|
|
44
|
+
case "NUMERIC":
|
|
45
|
+
return "number";
|
|
46
|
+
case "STRING":
|
|
47
|
+
case "TIME":
|
|
48
|
+
default:
|
|
49
|
+
return "string";
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
export function replacer(key, value) {
|
|
53
|
+
const v = this[key];
|
|
54
|
+
return v instanceof BigQueryDate ||
|
|
55
|
+
v instanceof BigQueryDatetime ||
|
|
56
|
+
v instanceof BigQueryTimestamp
|
|
57
|
+
? new Date(v.value).toJSON()
|
|
58
|
+
: value;
|
|
59
|
+
}
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import type { ColumnSchema, QueryParam } from "../runtime/index.js";
|
|
2
|
-
export type DatabaseConfig = DuckDBConfig | SQLiteConfig | SnowflakeConfig | PostgresConfig;
|
|
2
|
+
export type DatabaseConfig = BigQueryConfig | DuckDBConfig | SQLiteConfig | SnowflakeConfig | PostgresConfig;
|
|
3
|
+
export type BigQueryConfig = {
|
|
4
|
+
type: "bigquery";
|
|
5
|
+
apiKey?: string;
|
|
6
|
+
keyFilename?: string;
|
|
7
|
+
keyFile?: string;
|
|
8
|
+
projectId?: string;
|
|
9
|
+
};
|
|
3
10
|
export type DuckDBConfig = {
|
|
4
11
|
type: "duckdb";
|
|
5
12
|
path?: string;
|
|
@@ -39,4 +46,8 @@ export type SerializableQueryResult = {
|
|
|
39
46
|
};
|
|
40
47
|
export declare function getDatabaseConfig(sourcePath: string, databaseName: string): Promise<DatabaseConfig>;
|
|
41
48
|
export declare function getDatabase(config: DatabaseConfig): Promise<QueryTemplateFunction>;
|
|
49
|
+
export type Replacer = (this: {
|
|
50
|
+
[key: string]: unknown;
|
|
51
|
+
}, key: string, value: unknown) => unknown;
|
|
52
|
+
export declare function getReplacer(config: DatabaseConfig): Promise<Replacer | undefined>;
|
|
42
53
|
export declare function getQueryCachePath(sourcePath: string, databaseName: string, strings: readonly string[], ...params: unknown[]): Promise<string>;
|
|
@@ -34,6 +34,8 @@ export async function getDatabaseConfig(sourcePath, databaseName) {
|
|
|
34
34
|
}
|
|
35
35
|
export async function getDatabase(config) {
|
|
36
36
|
switch (config.type) {
|
|
37
|
+
case "bigquery":
|
|
38
|
+
return (await import("./bigquery.js")).default(config);
|
|
37
39
|
case "duckdb":
|
|
38
40
|
return (await import("./duckdb.js")).default(config);
|
|
39
41
|
case "sqlite":
|
|
@@ -46,6 +48,14 @@ export async function getDatabase(config) {
|
|
|
46
48
|
throw new Error(`unsupported database type: ${config["type"]}`);
|
|
47
49
|
}
|
|
48
50
|
}
|
|
51
|
+
export async function getReplacer(config) {
|
|
52
|
+
switch (config.type) {
|
|
53
|
+
case "bigquery":
|
|
54
|
+
return (await import("./bigquery.js")).replacer;
|
|
55
|
+
case "snowflake":
|
|
56
|
+
return (await import("./snowflake.js")).replacer;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
49
59
|
export async function getQueryCachePath(sourcePath, databaseName, strings, ...params) {
|
|
50
60
|
const sourceDir = dirname(sourcePath);
|
|
51
61
|
const cacheName = `${await getNameHash(databaseName)}-${await getQueryHash(strings, ...params)}.json`;
|
|
@@ -100,3 +100,9 @@ function getColumnType(column) {
|
|
|
100
100
|
return "other";
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
|
+
// Force dates to be serialized as ISO 8601 UTC, undoing this:
|
|
104
|
+
// https://github.com/snowflakedb/snowflake-connector-nodejs/blob/a9174fb7/lib/connection/result/sf_timestamp.js#L177-L179
|
|
105
|
+
export function replacer(key, value) {
|
|
106
|
+
const v = this[key];
|
|
107
|
+
return v instanceof Date ? Date.prototype.toJSON.call(v) : value;
|
|
108
|
+
}
|
package/package.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/observablehq/notebook-kit.git"
|
|
7
7
|
},
|
|
8
|
-
"version": "1.
|
|
8
|
+
"version": "1.2.0-rc.1",
|
|
9
9
|
"type": "module",
|
|
10
10
|
"scripts": {
|
|
11
11
|
"test": "vitest",
|
|
@@ -65,6 +65,7 @@
|
|
|
65
65
|
"devDependencies": {
|
|
66
66
|
"@duckdb/node-api": "^1.3.2-alpha.26",
|
|
67
67
|
"@eslint/js": "^9.29.0",
|
|
68
|
+
"@google-cloud/bigquery": "^8.1.1",
|
|
68
69
|
"@types/jsdom": "^21.1.7",
|
|
69
70
|
"@types/markdown-it": "^14.1.2",
|
|
70
71
|
"bun-types": "^1.2.20",
|
|
@@ -80,6 +81,7 @@
|
|
|
80
81
|
},
|
|
81
82
|
"peerDependencies": {
|
|
82
83
|
"@duckdb/node-api": "^1.3.2-alpha.26",
|
|
84
|
+
"@google-cloud/bigquery": "^8.1.1",
|
|
83
85
|
"postgres": "^3.4.7",
|
|
84
86
|
"snowflake-sdk": "^2.1.3"
|
|
85
87
|
},
|
|
@@ -87,6 +89,9 @@
|
|
|
87
89
|
"@duckdb/node-api": {
|
|
88
90
|
"optional": true
|
|
89
91
|
},
|
|
92
|
+
"@google-cloud/bigquery": {
|
|
93
|
+
"optional": true
|
|
94
|
+
},
|
|
90
95
|
"postgres": {
|
|
91
96
|
"optional": true
|
|
92
97
|
},
|