Skip to content
Merged
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
129 changes: 120 additions & 9 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/local/test/e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ describe("network end to end", function () {
);

const data = await db
.prepare(`SELECT * FROM ${res.meta.txn?.name as string};`)
.prepare(`SELECT * FROM ${res.txn?.name as string};`)
.all();
expect(data.results).to.eql([]);
});
Expand Down
3 changes: 2 additions & 1 deletion packages/sdk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@
"@databases/sql": "^3.2.0",
"@ethersproject/experimental": "^5.7.0",
"@playwright/test": "^1.30.0",
"d1-orm": "^0.7.1",
"d1-orm": "^0.9.0",
"drizzle-orm": "^0.28.6",
"openapi-typescript": "6.2.4",
"typedoc": "^0.25.0"
},
Expand Down
16 changes: 9 additions & 7 deletions packages/sdk/src/database.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { type NormalizedStatement } from "@tableland/sqlparser";
import { type Result, type Runnable } from "./registry/index.js";
import { wrapResult } from "./registry/utils.js";
import {
type Result,
type ExecResult,
type Runnable,
} from "./registry/index.js";
import { wrapResult, wrapExecResult } from "./registry/utils.js";
import {
type Config,
type AutoWaitConfig,
Expand Down Expand Up @@ -194,16 +198,14 @@ export class Database<D = unknown> {
async exec<T = D>(
statementStrings: string,
controller?: PollingController
): Promise<Result<T>> {
): Promise<ExecResult<T>> {
// TODO: Note that this method appears to be the wrong return type in practice.
try {
const { statements } = await normalize(statementStrings);
const count = statements.length;
const statement = this.prepare(statementStrings);
const result = await statement.run({ controller });
// Adds a count property which isn't typed
result.meta.count = count;
return result;
const result = await statement.run<T>({ controller });
return wrapExecResult(result, count);
Comment thread
dtbuchholz marked this conversation as resolved.
} catch (cause: any) {
if (cause.message.startsWith("RUN_ERROR") === true) {
throw errorWithCause("EXEC_ERROR", cause.cause);
Expand Down
16 changes: 16 additions & 0 deletions packages/sdk/src/helpers/await.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,3 +150,19 @@ export async function getAsyncPoller<T = unknown>(
};
return await new Promise<T>(checkCondition);
}

/**
* Check if an argument is a valid {@link PollingController}.
* @param arg The argument to check.
* @returns An assertion/boolean, indicating if the argument is valid.
*/
export function isPollingController(arg: any): arg is PollingController {
return (
arg != null &&
arg.signal instanceof AbortSignal &&
typeof arg.abort === "function" &&
typeof arg.interval === "number" &&
typeof arg.cancel === "function" &&
typeof arg.timeout === "number"
);
}
1 change: 1 addition & 0 deletions packages/sdk/src/registry/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {

export {
type Result,
type ExecResult,
type Metadata,
type WaitableTransactionReceipt,
type Named,
Expand Down
54 changes: 50 additions & 4 deletions packages/sdk/src/registry/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,12 @@ function isTransactionReceipt(arg: any): arg is WaitableTransactionReceipt {
);
}

/**
* Wrap results for a Statement `run` or `all` call, or a Database `batch` call.
* @param resultsOrReceipt Either query results or the transaction receipt.
* @param duration Total client-side duration of the async call.
* @returns Wrapped results with metadata.
*/
export function wrapResult<T = unknown>(
resultsOrReceipt: T[] | WaitableTransactionReceipt,
duration: number
Expand All @@ -95,13 +101,36 @@ export function wrapResult<T = unknown>(
meta,
success: true,
results: [],
error: undefined,
};
if (isTransactionReceipt(resultsOrReceipt)) {
return { ...result, meta: { ...meta, txn: resultsOrReceipt } };
}
return { ...result, results: resultsOrReceipt };
}

/**
* Wrap results for a Database `exec` call.
* @param result The result of the a {@link wrapResult} call, made by `exec` under the hood.
* @param count The count of executed statements.
* @returns Wrapped {@link ExecResult} with metadata and transaction
* receipt or query results.
*/
export function wrapExecResult<T = unknown>(
result: Result<T>,
count: number
): ExecResult<T> {
const { duration } = result.meta;
const execResult: ExecResult<T> = {
count,
duration,
};
if (result.meta.txn != null) {
return { ...execResult, txn: result.meta.txn };
}
return { ...execResult, results: result.results };
}

/**
* Metadata represents meta information about an executed statement/transaction.
*/
Expand All @@ -111,11 +140,11 @@ export interface Metadata {
*/
duration: number;
/**
* The optional transactionn information receipt.
* The optional transaction information receipt.
*/
txn?: WaitableTransactionReceipt;
/**
* Metadata may contrain additional arbitrary key/values pairs.
* Metadata may constrain additional arbitrary key/values pairs.
*/
[key: string]: any;
}
Expand All @@ -131,17 +160,34 @@ export interface Result<T = unknown> {
/**
* Whether the query or transaction was successful.
*/
success: boolean; // almost always true
success: true; // TODO: this is a bug in D1, but if we want to be compatible
// we have to type it like this :<
// https://github.com/cloudflare/workerd/issues/940
/**
* If there was an error, this will contain the error string.
*/
error?: string;
error: undefined;
/**
* Additional meta information.
*/
meta: Metadata;
}

/**
* ExecResult represents the return result for executed Database statements via `exec()`.
*/
export interface ExecResult<T = unknown>
Comment thread
dtbuchholz marked this conversation as resolved.
extends Pick<Metadata, "duration" | "txn"> {
/**
* The count of executed statements.
*/
count: number;
/**
* The optional list of query results.
*/
results?: T[];
}

export async function extractReadonly(
conn: Config,
{ tables, type }: Omit<ExtractedStatement, "sql">
Expand Down
Loading