cogsbox-shape 0.5.206 → 0.5.207

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/README.md CHANGED
@@ -469,6 +469,22 @@ const user = await userView.findById(1);
469
469
  // user.posts is loaded and validated as part of the view shape
470
470
  ```
471
471
 
472
+ Cloudflare D1 uses the same SQLite schema dialect with a D1 connection helper:
473
+
474
+ ```typescript
475
+ import { connect } from "cogsbox-shape/db";
476
+ import { createD1Db } from "cogsbox-shape/db/cloudflare-d1";
477
+
478
+ export default {
479
+ async fetch(_request, env) {
480
+ const db = createD1Db(env.DB);
481
+ const bx = connect(box, db);
482
+
483
+ return Response.json(await bx.users.findMany());
484
+ },
485
+ };
486
+ ```
487
+
472
488
  Use `insert(data).ids()` when you only need the database identity, or `insert(data).full()` when you want optimistic client IDs reconciled back into the submitted client object. `create()` is kept as an alias for older code; prefer `insert()` in new code.
473
489
 
474
490
  ### 5. Nested Defaults and Form Definitions (`defaultsDefinition`)
@@ -0,0 +1,29 @@
1
+ import { Kysely } from "kysely";
2
+ import type { DatabaseIntrospector, Dialect, DialectAdapter, Driver, QueryCompiler } from "kysely";
3
+ export interface D1Result<T = Record<string, unknown>> {
4
+ success: boolean;
5
+ error?: string;
6
+ results?: T[];
7
+ meta?: {
8
+ changes?: number;
9
+ last_row_id?: number;
10
+ rows_written?: number;
11
+ };
12
+ }
13
+ export interface D1PreparedStatement {
14
+ bind(...values: unknown[]): D1PreparedStatement;
15
+ all<T = Record<string, unknown>>(): Promise<D1Result<T>>;
16
+ run<T = Record<string, unknown>>(): Promise<D1Result<T>>;
17
+ }
18
+ export interface D1Database {
19
+ prepare(query: string): D1PreparedStatement;
20
+ }
21
+ export declare class D1Dialect implements Dialect {
22
+ #private;
23
+ constructor(database: D1Database);
24
+ createDriver(): Driver;
25
+ createQueryCompiler(): QueryCompiler;
26
+ createAdapter(): DialectAdapter;
27
+ createIntrospector(db: Kysely<any>): DatabaseIntrospector;
28
+ }
29
+ export declare function createD1Db<TDb = unknown>(database: D1Database): Kysely<TDb>;
@@ -0,0 +1,100 @@
1
+ import { CompiledQuery, Kysely, SqliteAdapter, SqliteIntrospector, SqliteQueryCompiler, } from "kysely";
2
+ export class D1Dialect {
3
+ #database;
4
+ constructor(database) {
5
+ this.#database = database;
6
+ }
7
+ createDriver() {
8
+ return new D1Driver(this.#database);
9
+ }
10
+ createQueryCompiler() {
11
+ return new SqliteQueryCompiler();
12
+ }
13
+ createAdapter() {
14
+ return new SqliteAdapter();
15
+ }
16
+ createIntrospector(db) {
17
+ return new SqliteIntrospector(db);
18
+ }
19
+ }
20
+ export function createD1Db(database) {
21
+ return new Kysely({
22
+ dialect: new D1Dialect(database),
23
+ });
24
+ }
25
+ class D1Driver {
26
+ #connection;
27
+ constructor(database) {
28
+ this.#connection = new D1Connection(database);
29
+ }
30
+ async init(_options) {
31
+ // Cloudflare D1 bindings are already initialized by the Worker runtime.
32
+ }
33
+ async acquireConnection(_options) {
34
+ return this.#connection;
35
+ }
36
+ async beginTransaction(connection, _settings) {
37
+ await connection.executeQuery(CompiledQuery.raw("begin"));
38
+ }
39
+ async commitTransaction(connection) {
40
+ await connection.executeQuery(CompiledQuery.raw("commit"));
41
+ }
42
+ async rollbackTransaction(connection) {
43
+ await connection.executeQuery(CompiledQuery.raw("rollback"));
44
+ }
45
+ async releaseConnection(_connection, _options) {
46
+ // D1 exposes a stateless binding instead of pooled connections.
47
+ }
48
+ async destroy(_options) {
49
+ // Nothing to close for a Worker binding.
50
+ }
51
+ }
52
+ class D1Connection {
53
+ #database;
54
+ constructor(database) {
55
+ this.#database = database;
56
+ }
57
+ async executeQuery(compiledQuery) {
58
+ const statement = this.#prepare(compiledQuery);
59
+ const result = shouldReturnRows(compiledQuery.sql)
60
+ ? await statement.all()
61
+ : await statement.run();
62
+ assertD1Success(result, compiledQuery.sql);
63
+ return {
64
+ insertId: result.meta?.last_row_id != null
65
+ ? BigInt(result.meta.last_row_id)
66
+ : undefined,
67
+ numAffectedRows: affectedRows(result),
68
+ rows: (result.results ?? []),
69
+ };
70
+ }
71
+ async *streamQuery(compiledQuery, _chunkSize) {
72
+ const result = await this.executeQuery(compiledQuery);
73
+ for (const row of result.rows) {
74
+ yield { rows: [row] };
75
+ }
76
+ }
77
+ #prepare(compiledQuery) {
78
+ const statement = this.#database.prepare(compiledQuery.sql);
79
+ return compiledQuery.parameters.length > 0
80
+ ? statement.bind(...compiledQuery.parameters)
81
+ : statement;
82
+ }
83
+ }
84
+ function shouldReturnRows(sql) {
85
+ const trimmed = sql.trim().toLowerCase();
86
+ return (trimmed.startsWith("select") ||
87
+ trimmed.startsWith("with") ||
88
+ trimmed.startsWith("pragma") ||
89
+ trimmed.startsWith("explain") ||
90
+ /\breturning\b/i.test(sql));
91
+ }
92
+ function affectedRows(result) {
93
+ const count = result.meta?.changes ?? result.meta?.rows_written;
94
+ return count != null ? BigInt(count) : undefined;
95
+ }
96
+ function assertD1Success(result, sql) {
97
+ if (!result.success) {
98
+ throw new Error(result.error ?? `D1 query failed: ${sql}`);
99
+ }
100
+ }
@@ -0,0 +1 @@
1
+ export { createD1Db, D1Dialect, type D1Database, type D1PreparedStatement, type D1Result, } from "./d1-driver.js";
@@ -0,0 +1 @@
1
+ export { createD1Db, D1Dialect, } from "./d1-driver.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cogsbox-shape",
3
- "version": "0.5.206",
3
+ "version": "0.5.207",
4
4
  "description": "A TypeScript library for creating type-safe database schemas with Zod validation, SQL type definitions, and automatic client/server transformations. Unifies client, server, and database types through a single schema definition, with built-in support for relationships and serialization.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -37,6 +37,11 @@
37
37
  "import": "./cogsbox-shape-db/dist/sqlite/index.js",
38
38
  "default": "./cogsbox-shape-db/dist/sqlite/index.js"
39
39
  },
40
+ "./db/cloudflare-d1": {
41
+ "types": "./cogsbox-shape-db/dist/cloudflare-d1/index.d.ts",
42
+ "import": "./cogsbox-shape-db/dist/cloudflare-d1/index.js",
43
+ "default": "./cogsbox-shape-db/dist/cloudflare-d1/index.js"
44
+ },
40
45
  "./state": {
41
46
  "types": "./cogsbox-shape-state/dist/index.d.ts",
42
47
  "import": "./cogsbox-shape-state/dist/index.js",