Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/runtime/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ export type * from "./stdlib/fileAttachment.js";
export {FileAttachment, requireFileRegistration, registerFile} from "./stdlib/fileAttachment.js";
export type * from "./stdlib/interpreter.js";
export {Interpreter} from "./stdlib/interpreter.js";
export type * from "./stdlib/sql.js";
export {sql, SqlFragment, SqlView, SqlVariant} from "./stdlib/sql.js";

export class NotebookRuntime {
readonly runtime: Runtime & {fileAttachments: typeof fileAttachments};
Expand Down
22 changes: 18 additions & 4 deletions src/runtime/stdlib/databaseClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {hash, nameHash} from "../../lib/hash.js";
export type QueryParam = any;

/** @see https://observablehq.com/@observablehq/database-client-specification#%C2%A71 */
export type QueryResult = Record<string, any>[] & {schema: ColumnSchema[]; date: Date};
export type QueryResult<T = Record<string, any>> = T[] & {schema: ColumnSchema[]; date: Date};

/** @see https://observablehq.com/@observablehq/database-client-specification#%C2%A72.2 */
export interface ColumnSchema {
Expand Down Expand Up @@ -39,10 +39,24 @@ export interface QueryOptions extends QueryOptionsSpec {
since?: Date;
}

export type SqlDialect =
| "bigquery"
| "databricks"
| "duckdb"
| "mongosql"
| "mssql"
| "mysql"
| "oracle"
| "postgres"
| "snowflake"
| "sql"
| "sqlite";

export interface DatabaseClient {
readonly name: string;
readonly options: QueryOptions;
sql(strings: readonly string[], ...params: QueryParam[]): Promise<QueryResult>;
readonly dialect?: SqlDialect;
sql<T = Record<string, any>>(strings: readonly string[], ...params: QueryParam[]): Promise<QueryResult<T>>; // prettier-ignore
}

export const DatabaseClient = (name: string, options?: QueryOptionsSpec): DatabaseClient => {
Expand All @@ -65,11 +79,11 @@ class DatabaseClientImpl implements DatabaseClient {
options: {value: options, enumerable: true}
});
}
async sql(strings: readonly string[], ...params: QueryParam[]): Promise<QueryResult> {
async sql<T = Record<string, any>>(strings: readonly string[], ...params: QueryParam[]): Promise<QueryResult<T>> {
const path = await this.cachePath(strings, ...params);
const response = await fetch(path);
if (!response.ok) throw new Error(`failed to fetch: ${path}`);
return await response.json().then(revive);
return (await response.json().then(revive)) as QueryResult<T>;
}
async cachePath(strings: readonly string[], ...params: QueryParam[]): Promise<string> {
return `.observable/cache/${await nameHash(this.name)}-${await hash(strings, ...params)}.json`;
Expand Down
2 changes: 2 additions & 0 deletions src/runtime/stdlib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ import {Mutable} from "./mutable.js";
import * as Promises from "./promises/index.js";
import * as recommendedLibraries from "./recommendedLibraries.js";
import * as sampleDatasets from "./sampleDatasets.js";
import {sql} from "./sql.js";

export const root = document.querySelector("main") ?? document.body;

export const library = {
dark: () => Generators.dark(),
now: () => Generators.now(),
sql: () => sql,
width: () => Generators.width(root),
DatabaseClient: () => DatabaseClient,
FileAttachment: () => FileAttachment,
Expand Down
Loading