class D1Adapter
implements IDatabaseAdapter
Since 0.2.0

A database backend over a Cloudflare D1 binding.

Constructed by the application from its own binding and handed to DatabasePlugin({ type: 'custom', adapter }) — the same wiring KvSessionStore uses, and for the same reason: DatabasePlugin's options are read when the plugin is constructed, which happens before any application exists, so an adapter published in the service registry could never reach it.

Transactions

D1 has no interactive transaction. BEGIN TRANSACTION is rejected by the platform outright, and batch() — which runs a pre-declared list of statements as one SQL transaction, rolling the whole sequence back if any statement fails — is its only unit of atomicity.

beginTransaction() therefore buffers every write and flushes the whole buffer as one batch() at commit(); rollback() discards the buffer and sends nothing. Two consequences, both deliberate and both under test:

  • No read-your-own-writes inside a transaction. Reads run immediately against committed state, so a row written earlier in the same transaction is not visible to a later read in it.
  • create() inside a transaction requires an explicit primary key, and throws naming the constraint when one is absent. A deferred INSERT cannot report a generated key to a caller that awaits create() before the flush. Outside a transaction create() uses RETURNING * and returns the real persisted row, generated columns included.

Examples

Example 1

import { env } from 'cloudflare:workers';
import { DatabasePlugin } from '@setu-ts/database-plugin';
import { D1Adapter, type ID1Database } from '@setu-ts/cloudflare-plugin';

app.register(DatabasePlugin({
  type: 'custom',
  adapter: new D1Adapter(env.DB as ID1Database, {
    tables: { User: { table: 'users' } },
  }),
}));

Constructors

D1Adapter()
Parameters

The D1 binding, from the Worker's env

optional
options: D1AdapterOptions

Entity mapping overrides

Properties

readonly
transactionIsolationLevels: readonly TransactionIsolationLevel[]

D1's deferred batch transaction has no isolation-level surface.

Methods

beginTransaction(options?: TransactionOptions): Promise<IAdapterTransaction>

Begin a transaction, returning a handle that can open transaction-scoped data sources as well as commit and roll back.

connect(): Promise<void>
createDataSource(entity: string): IDataSource

Open a non-transactional data source for the named entity.

disconnect(): Promise<void>
isReady(): boolean
rawQuery<T>(
sql: string,
params?: unknown[]
): Promise<T[]>

Execute a raw query in the backend's own dialect.

See