@observablehq/notebook-kit 1.1.0-rc.15 → 1.1.0-rc.16
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/notebooks.js +6 -0
- package/dist/bin/query.d.ts +2 -0
- package/dist/bin/query.js +59 -0
- package/dist/package.json +1 -1
- package/dist/src/databases/duckdb.d.ts +2 -2
- package/dist/src/databases/duckdb.js +1 -5
- package/dist/src/databases/index.d.ts +1 -4
- package/dist/src/databases/index.js +3 -3
- package/dist/src/databases/sqlite-bun.d.ts +2 -2
- package/dist/src/databases/sqlite-bun.js +2 -3
- package/dist/src/databases/sqlite-node.d.ts +2 -2
- package/dist/src/databases/sqlite-node.js +2 -3
- package/dist/src/vite/observable.js +9 -12
- package/package.json +1 -1
package/dist/bin/notebooks.js
CHANGED
|
@@ -16,12 +16,18 @@ switch (command) {
|
|
|
16
16
|
await run(process.argv.slice(3));
|
|
17
17
|
break;
|
|
18
18
|
}
|
|
19
|
+
case "query": {
|
|
20
|
+
const { default: run } = await import("./query.js");
|
|
21
|
+
await run(process.argv.slice(3));
|
|
22
|
+
break;
|
|
23
|
+
}
|
|
19
24
|
default: {
|
|
20
25
|
console.log(`usage: notebooks <command>
|
|
21
26
|
|
|
22
27
|
preview start the preview server
|
|
23
28
|
build generate a static site
|
|
24
29
|
download download an Observable Notebook as HTML
|
|
30
|
+
query run a database query
|
|
25
31
|
help print usage information
|
|
26
32
|
version print the version
|
|
27
33
|
`);
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { parseArgs } from "node:util";
|
|
3
|
+
import { getDatabase, getDatabaseConfig, getQueryCachePath } from "../src/databases/index.js";
|
|
4
|
+
import { dirname } from "node:path/win32";
|
|
5
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
6
|
+
import { join } from "node:path";
|
|
7
|
+
if (process.argv[1] === import.meta.filename)
|
|
8
|
+
run();
|
|
9
|
+
export default async function run(args) {
|
|
10
|
+
const { values, positionals } = parseArgs({
|
|
11
|
+
args,
|
|
12
|
+
allowPositionals: true,
|
|
13
|
+
allowNegative: true,
|
|
14
|
+
options: {
|
|
15
|
+
root: {
|
|
16
|
+
type: "string",
|
|
17
|
+
default: "."
|
|
18
|
+
},
|
|
19
|
+
database: {
|
|
20
|
+
type: "string"
|
|
21
|
+
},
|
|
22
|
+
help: {
|
|
23
|
+
type: "boolean",
|
|
24
|
+
short: "h"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
if (values.help || !values.database) {
|
|
29
|
+
console.log(`usage: notebooks query <...query>
|
|
30
|
+
|
|
31
|
+
--database <name> name of the database
|
|
32
|
+
--root <dir> path to the root directory; defaults to cwd
|
|
33
|
+
-h, --help show this message
|
|
34
|
+
`);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
// Parse positionals into query template arguments.
|
|
38
|
+
const strings = [];
|
|
39
|
+
const params = [];
|
|
40
|
+
for (let i = 0; i < positionals.length; ++i) {
|
|
41
|
+
if (i & 1)
|
|
42
|
+
params.push(JSON.parse(positionals[i]));
|
|
43
|
+
else
|
|
44
|
+
strings.push(positionals[i]);
|
|
45
|
+
}
|
|
46
|
+
process.chdir(values.root);
|
|
47
|
+
const config = await getDatabaseConfig(".", values.database);
|
|
48
|
+
const database = await getDatabase(config);
|
|
49
|
+
const results = await database.call(null, strings, ...params);
|
|
50
|
+
const cachePath = await getQueryCachePath(".", values.database, strings, ...params);
|
|
51
|
+
await mkdir(dirname(cachePath), { recursive: true });
|
|
52
|
+
await writeFile(cachePath, JSON.stringify(results, replace));
|
|
53
|
+
console.log(join(values.root, cachePath));
|
|
54
|
+
}
|
|
55
|
+
// Force dates to be serialized as ISO 8601 UTC, undoing this:
|
|
56
|
+
// https://github.com/snowflakedb/snowflake-connector-nodejs/blob/a9174fb7/lib/connection/result/sf_timestamp.js#L177-L179
|
|
57
|
+
function replace(key, value) {
|
|
58
|
+
return this[key] instanceof Date ? Date.prototype.toJSON.call(this[key]) : value;
|
|
59
|
+
}
|
package/dist/package.json
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export default function duckdb({ path, options }: DuckDBConfig
|
|
1
|
+
import type { DuckDBConfig, QueryTemplateFunction } from "./index.js";
|
|
2
|
+
export default function duckdb({ path, options }: DuckDBConfig): QueryTemplateFunction;
|
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
import { DuckDBConnection, DuckDBInstance } from "@duckdb/node-api";
|
|
2
2
|
import { BIGINT, BIT, BLOB, BOOLEAN, DATE, DOUBLE, FLOAT, HUGEINT, INTEGER, INTERVAL, SMALLINT, TIME, TIMESTAMP, TIMESTAMP_MS, TIMESTAMP_NS, TIMESTAMP_S, TIMESTAMPTZ, TINYINT, UBIGINT, UHUGEINT, UINTEGER, USMALLINT, UTINYINT, UUID, VARCHAR, VARINT } from "@duckdb/node-api"; // prettier-ignore
|
|
3
|
-
|
|
4
|
-
export default function duckdb({ path, options }, context) {
|
|
5
|
-
if (path !== undefined)
|
|
6
|
-
path = join(context.cwd, path);
|
|
3
|
+
export default function duckdb({ path, options }) {
|
|
7
4
|
return async (strings, ...params) => {
|
|
8
5
|
const instance = await DuckDBInstance.create(path, options);
|
|
9
6
|
const connection = await DuckDBConnection.create(instance);
|
|
10
|
-
await connection.run(`SET file_search_path=$0`, [context.cwd]);
|
|
11
7
|
const date = new Date();
|
|
12
8
|
let result;
|
|
13
9
|
let rows;
|
|
@@ -31,9 +31,6 @@ export type PostgresConfig = {
|
|
|
31
31
|
database?: string;
|
|
32
32
|
ssl?: boolean;
|
|
33
33
|
};
|
|
34
|
-
export type DatabaseContext = {
|
|
35
|
-
cwd: string;
|
|
36
|
-
};
|
|
37
34
|
export type QueryTemplateFunction = (strings: readonly string[], ...params: QueryParam[]) => Promise<SerializableQueryResult>;
|
|
38
35
|
export type SerializableQueryResult = {
|
|
39
36
|
rows: Record<string, unknown>[];
|
|
@@ -42,5 +39,5 @@ export type SerializableQueryResult = {
|
|
|
42
39
|
date: Date;
|
|
43
40
|
};
|
|
44
41
|
export declare function getDatabaseConfig(sourcePath: string, databaseName: string): Promise<DatabaseConfig>;
|
|
45
|
-
export declare function getDatabase(config: DatabaseConfig
|
|
42
|
+
export declare function getDatabase(config: DatabaseConfig): Promise<QueryTemplateFunction>;
|
|
46
43
|
export declare function getQueryCachePath(sourcePath: string, databaseName: string, strings: readonly string[], ...params: unknown[]): Promise<string>;
|
|
@@ -33,12 +33,12 @@ export async function getDatabaseConfig(sourcePath, databaseName) {
|
|
|
33
33
|
}
|
|
34
34
|
return config;
|
|
35
35
|
}
|
|
36
|
-
export async function getDatabase(config
|
|
36
|
+
export async function getDatabase(config) {
|
|
37
37
|
switch (config.type) {
|
|
38
38
|
case "duckdb":
|
|
39
|
-
return (await import("./duckdb.js")).default(config
|
|
39
|
+
return (await import("./duckdb.js")).default(config);
|
|
40
40
|
case "sqlite":
|
|
41
|
-
return (await import(process.versions.bun ? "./sqlite-bun.js" : "./sqlite-node.js")).default(config
|
|
41
|
+
return (await import(process.versions.bun ? "./sqlite-bun.js" : "./sqlite-node.js")).default(config);
|
|
42
42
|
case "snowflake":
|
|
43
43
|
return (await import("./snowflake.js")).default(config);
|
|
44
44
|
case "postgres":
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export default function sqlite({ path }: SQLiteConfig
|
|
1
|
+
import type { SQLiteConfig, QueryTemplateFunction } from "./index.js";
|
|
2
|
+
export default function sqlite({ path }: SQLiteConfig): QueryTemplateFunction;
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import { join } from "node:path";
|
|
2
1
|
import { Database } from "bun:sqlite";
|
|
3
2
|
import { getColumnType } from "./sqlite.js";
|
|
4
|
-
export default function sqlite({ path }
|
|
3
|
+
export default function sqlite({ path = ":memory:" }) {
|
|
5
4
|
return async (strings, ...params) => {
|
|
6
5
|
const date = new Date();
|
|
7
|
-
const database = new Database(path
|
|
6
|
+
const database = new Database(path);
|
|
8
7
|
try {
|
|
9
8
|
const statement = database.prepare(strings.join("?"));
|
|
10
9
|
const rows = statement.all(...params);
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export default function sqlite({ path }: SQLiteConfig
|
|
1
|
+
import type { SQLiteConfig, QueryTemplateFunction } from "./index.js";
|
|
2
|
+
export default function sqlite({ path }: SQLiteConfig): QueryTemplateFunction;
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import { join } from "node:path";
|
|
2
1
|
import { DatabaseSync } from "node:sqlite";
|
|
3
2
|
import { getColumnType } from "./sqlite.js";
|
|
4
|
-
export default function sqlite({ path }
|
|
3
|
+
export default function sqlite({ path = ":memory:" }) {
|
|
5
4
|
return async (strings, ...params) => {
|
|
6
5
|
const date = new Date();
|
|
7
|
-
const database = new DatabaseSync(path
|
|
6
|
+
const database = new DatabaseSync(path);
|
|
8
7
|
try {
|
|
9
8
|
const statement = database.prepare(strings.join("?"));
|
|
10
9
|
const rows = statement.all(...params);
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import { fork } from "node:child_process";
|
|
1
2
|
import { existsSync } from "node:fs";
|
|
2
|
-
import {
|
|
3
|
+
import { readFile } from "node:fs/promises";
|
|
3
4
|
import { dirname, join, resolve } from "node:path";
|
|
4
5
|
import { relative } from "node:path/posix";
|
|
5
6
|
import { fileURLToPath } from "node:url";
|
|
6
7
|
import { JSDOM } from "jsdom";
|
|
7
|
-
import {
|
|
8
|
+
import { getQueryCachePath } from "../databases/index.js";
|
|
8
9
|
import { deserialize } from "../lib/serialize.js";
|
|
9
10
|
import { Sourcemap } from "../javascript/sourcemap.js";
|
|
10
11
|
import { transpile } from "../javascript/transpile.js";
|
|
@@ -69,16 +70,12 @@ export function observable({ window = new JSDOM().window, parser = new window.DO
|
|
|
69
70
|
const dir = dirname(context.filename);
|
|
70
71
|
const cachePath = await getQueryCachePath(context.filename, cell.database, [value]);
|
|
71
72
|
if (!existsSync(cachePath)) {
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
}
|
|
79
|
-
catch (error) {
|
|
80
|
-
console.error(error);
|
|
81
|
-
}
|
|
73
|
+
const args = ["--root", dir, "--database", cell.database, value];
|
|
74
|
+
const child = fork(fileURLToPath(import.meta.resolve("../../bin/query.ts")), args);
|
|
75
|
+
await new Promise((resolve, reject) => {
|
|
76
|
+
child.on("error", reject);
|
|
77
|
+
child.on("exit", resolve);
|
|
78
|
+
});
|
|
82
79
|
}
|
|
83
80
|
cell.mode = "js";
|
|
84
81
|
cell.value = `FileAttachment(${JSON.stringify(relative(dir, cachePath))}).json().then(DatabaseClient.revive)${hidden ? "" : `.then(Inputs.table)${cell.output ? ".then(view)" : ""}`}`;
|