Skip to content

Commit

Permalink
Tweaked TS generation of DO SQlite types
Browse files Browse the repository at this point in the history
  • Loading branch information
geelen committed Sep 18, 2024
1 parent 0b073a7 commit aa9ebcb
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 6 deletions.
24 changes: 18 additions & 6 deletions src/workerd/api/sql.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,22 +33,23 @@ class SqlStorage final: public jsg::Object, private SqliteDatabase::Regulator {
JSG_RESOURCE_TYPE(SqlStorage, CompatibilityFlags::Reader flags) {
JSG_METHOD(exec);

// Prepared statement API is experimental-only and deprecated. exec() will automatically
// handle caching prepared statements, so apps don't need to worry about it.
if (flags.getWorkerdExperimental()) {
// Prepared statement API is experimental-only and deprecated. exec() will automatically
// handle caching prepared statements, so apps don't need to worry about it.
JSG_METHOD(prepare);
}

// Make sure that the 'ingest' function is still experimental-only if and when
// the SQL API becomes publicly available.
if (flags.getWorkerdExperimental()) {
// 'ingest' functionality is still experimental-only
JSG_METHOD(ingest);
}

JSG_READONLY_PROTOTYPE_PROPERTY(databaseSize, getDatabaseSize);

JSG_NESTED_TYPE(Cursor);
JSG_NESTED_TYPE(Statement);

JSG_TS_OVERRIDE({
exec<T extends Record<string, SqlStorageValue>>(query: string, ...bindings: any[]): SqlStorageCursor<T>
});
}

void visitForMemoryInfo(jsg::MemoryTracker& tracker) const;
Expand Down Expand Up @@ -125,6 +126,12 @@ class SqlStorage::Cursor final: public jsg::Object {
JSG_READONLY_PROTOTYPE_PROPERTY(columnNames, getColumnNames);
JSG_READONLY_PROTOTYPE_PROPERTY(rowsRead, getRowsRead);
JSG_READONLY_PROTOTYPE_PROPERTY(rowsWritten, getRowsWritten);

JSG_TS_DEFINE(type SqlStorageValue = ArrayBuffer | string | number | null);
JSG_TS_OVERRIDE(<T extends Record<string, SqlStorageValue>> {
[Symbol.iterator](): IterableIterator<T>;
raw<U extends SqlStorageValue[]>(): IterableIterator<U>;
});
}

// One value returned from SQL. Note that we intentionally return StringPtr instead of String
Expand Down Expand Up @@ -274,6 +281,11 @@ struct SqlStorage::IngestResult {
double statementCount;

JSG_STRUCT(remainder, rowsRead, rowsWritten, statementCount);
JSG_STRUCT_TS_OVERRIDE_DYNAMIC(CompatibilityFlags::Reader flags) {
if(!flags.getWorkerdExperimental()) {
JSG_STRUCT_TS_OVERRIDE(type IngestResult = never);
}
}
};

#define EW_SQL_ISOLATE_TYPES \
Expand Down
37 changes: 37 additions & 0 deletions types/test/types/do.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { DurableObject } from "cloudflare:workers";
import { expectTypeOf } from "expect-type";

// Aliased as SqlStorageValue, but let's assert it includes the raw types we expect
type Value = ArrayBuffer | string | number | null;

class TestDOSql extends DurableObject {
test() {
const db = this.ctx.storage.sql;

expectTypeOf<SqlStorage>(db);

expectTypeOf<number>(db.databaseSize);

// Verify default row type of exec
for (const row of db.exec("...")) {
expectTypeOf<Record<string, Value>>(row);
}

// Verify scoped row type of exec
for (const row of db.exec<{ name: string; phone: number }>("...")) {
expectTypeOf<{ name: string; phone: number }>(row);

// @ts-expect-error double-checking our assertions are strict
expectTypeOf<{ name: string; phone: string }>(row);
// @ts-expect-error double-checking our assertions are strict
expectTypeOf<Record<string, number>>(row);
}

const cursor = db.exec("...", 1, "two")
expectTypeOf<SqlStorageCursor<Record<string, Value>>>(cursor);

expectTypeOf<number>(cursor.rowsRead);
expectTypeOf<number>(cursor.rowsWritten);
expectTypeOf<string[]>(cursor.columnNames);
}
}

0 comments on commit aa9ebcb

Please sign in to comment.