@drizzle-adapter/d1 1.0.0

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.
Files changed (51) hide show
  1. package/.wrangler/state/v3/d1/miniflare-D1DatabaseObject/6e148680931b1bfcb993e0463aced3b0a6d6cf50af24dea2dcc2c3b2e9ae9e3b.sqlite +0 -0
  2. package/.wrangler/state/v3/d1/miniflare-D1DatabaseObject/6e148680931b1bfcb993e0463aced3b0a6d6cf50af24dea2dcc2c3b2e9ae9e3b.sqlite-shm +0 -0
  3. package/.wrangler/state/v3/d1/miniflare-D1DatabaseObject/6e148680931b1bfcb993e0463aced3b0a6d6cf50af24dea2dcc2c3b2e9ae9e3b.sqlite-wal +0 -0
  4. package/LICENSE +674 -0
  5. package/README.md +260 -0
  6. package/dist/Adapter/D1DrizzleAdapter.d.ts +32 -0
  7. package/dist/Adapter/D1DrizzleAdapter.js +41 -0
  8. package/dist/Adapter/D1DrizzleConnection.d.ts +29 -0
  9. package/dist/Adapter/D1DrizzleConnection.js +39 -0
  10. package/dist/Adapter/D1DrizzleDataTypes.d.ts +3 -0
  11. package/dist/Adapter/D1DrizzleDataTypes.js +3 -0
  12. package/dist/Adapter/index.d.ts +2 -0
  13. package/dist/Adapter/index.js +2 -0
  14. package/dist/Factory/D1DrizzleAdapterFactory.d.ts +12 -0
  15. package/dist/Factory/D1DrizzleAdapterFactory.js +12 -0
  16. package/dist/Factory/index.d.ts +1 -0
  17. package/dist/Factory/index.js +1 -0
  18. package/dist/Interface/D1DrizzleClientInterface.d.ts +13 -0
  19. package/dist/Interface/D1DrizzleClientInterface.js +1 -0
  20. package/dist/Interface/index.d.ts +1 -0
  21. package/dist/Interface/index.js +1 -0
  22. package/dist/Type/Types.d.ts +5 -0
  23. package/dist/Type/Types.js +1 -0
  24. package/dist/Type/index.d.ts +1 -0
  25. package/dist/Type/index.js +1 -0
  26. package/dist/index.d.ts +6 -0
  27. package/dist/index.js +7 -0
  28. package/eslint.config.mjs +6 -0
  29. package/package.json +34 -0
  30. package/src/Adapter/D1DrizzleAdapter.ts +50 -0
  31. package/src/Adapter/D1DrizzleConnection.ts +53 -0
  32. package/src/Adapter/D1DrizzleDataTypes.ts +3 -0
  33. package/src/Adapter/index.ts +2 -0
  34. package/src/Factory/D1DrizzleAdapterFactory.ts +17 -0
  35. package/src/Factory/index.ts +1 -0
  36. package/src/Interface/D1DrizzleClientInterface.ts +15 -0
  37. package/src/Interface/index.ts +1 -0
  38. package/src/Type/Types.ts +7 -0
  39. package/src/Type/index.ts +1 -0
  40. package/src/index.ts +8 -0
  41. package/tests/Adapter/D1DrizzleAdapter.test.ts +36 -0
  42. package/tests/Adapter/D1DrizzleConnection.test.ts +40 -0
  43. package/tests/Factory/D1DrizzleAdapterFactory.test.ts +41 -0
  44. package/tests/Integration/D1DrizzleAdapter.integration.test.ts +101 -0
  45. package/tests/Integration/D1DrizzleMigrations.integration.test.ts +100 -0
  46. package/tests/test-runner.ts +51 -0
  47. package/tests/worker.ts +334 -0
  48. package/tsconfig.eslint.json +4 -0
  49. package/tsconfig.json +38 -0
  50. package/vitest.config.ts +15 -0
  51. package/wrangler.toml +8 -0
@@ -0,0 +1,334 @@
1
+ /// <reference types="@cloudflare/workers-types" />
2
+ import { D1DrizzleAdapterFactory } from '../src/Factory';
3
+ import type { D1DrizzleAdapter } from '../src/Adapter';
4
+ import { eq, sql } from 'drizzle-orm';
5
+
6
+ // Simple UUID v4 generator for worker environment
7
+ function generateUUID(): string {
8
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
9
+ const r = Math.random() * 16 | 0;
10
+ const v = c === 'x' ? r : (r & 0x3 | 0x8);
11
+ return v.toString(16);
12
+ });
13
+ }
14
+
15
+ export default {
16
+ async fetch(request: Request, env: Env): Promise<Response> {
17
+ const url = new URL(request.url);
18
+
19
+ // Test endpoints
20
+ switch (url.pathname) {
21
+ case '/test/create-record': {
22
+ try {
23
+ const factory = new D1DrizzleAdapterFactory();
24
+ const adapter = await factory.create({
25
+ DATABASE: env.DB
26
+ }) as D1DrizzleAdapter;
27
+
28
+ const connection = adapter.getConnection();
29
+ const client = await connection.getClient();
30
+
31
+ // Create table definition
32
+ const dataTypes = adapter.getDataTypes();
33
+ const tableName = `test_users_${Date.now()}_${generateUUID().replace(/-/g, '_')}`;
34
+ const users = dataTypes.dbTable(tableName, {
35
+ id: dataTypes.dbInteger('id').primaryKey({ autoIncrement: true }),
36
+ name: dataTypes.dbText('name').notNull(),
37
+ email: dataTypes.dbText('email').notNull()
38
+ });
39
+
40
+ // Create table
41
+ await env.DB.exec(`CREATE TABLE "${tableName}" (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, email TEXT NOT NULL)`);
42
+
43
+ // Insert record
44
+ const result = await client.insert(users).values({
45
+ name: 'John Doe',
46
+ email: 'john@example.com'
47
+ }).returning();
48
+
49
+ // Verify and cleanup
50
+ const success = result[0]?.name === 'John Doe' && result[0]?.email === 'john@example.com';
51
+ await env.DB.exec(`DROP TABLE IF EXISTS "${tableName}"`);
52
+
53
+ return new Response(JSON.stringify({ success, result: result[0] }), {
54
+ headers: { 'Content-Type': 'application/json' }
55
+ });
56
+ } catch (error: unknown) {
57
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
58
+ return new Response(JSON.stringify({ error: errorMessage }), {
59
+ status: 500,
60
+ headers: { 'Content-Type': 'application/json' }
61
+ });
62
+ }
63
+ }
64
+
65
+ case '/test/update-record': {
66
+ try {
67
+ const factory = new D1DrizzleAdapterFactory();
68
+ const adapter = await factory.create({
69
+ DATABASE: env.DB
70
+ }) as D1DrizzleAdapter;
71
+
72
+ const connection = adapter.getConnection();
73
+ const client = await connection.getClient();
74
+
75
+ // Create table definition
76
+ const dataTypes = adapter.getDataTypes();
77
+ const tableName = `test_users_${Date.now()}_${generateUUID().replace(/-/g, '_')}`;
78
+ const users = dataTypes.dbTable(tableName, {
79
+ id: dataTypes.dbInteger('id').primaryKey({ autoIncrement: true }),
80
+ name: dataTypes.dbText('name').notNull(),
81
+ email: dataTypes.dbText('email').notNull()
82
+ });
83
+
84
+ // Create table
85
+ await env.DB.exec(`CREATE TABLE "${tableName}" (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, email TEXT NOT NULL)`);
86
+
87
+ // Insert initial record
88
+ const inserted = await client.insert(users).values({
89
+ name: 'Jane Doe',
90
+ email: 'jane@example.com'
91
+ }).returning();
92
+
93
+ // Update record
94
+ const updated = await client
95
+ .update(users)
96
+ .set({ name: 'Jane Smith' })
97
+ .where(eq(users.id, inserted[0].id))
98
+ .returning();
99
+
100
+ // Verify and cleanup
101
+ const success = updated[0]?.name === 'Jane Smith' && updated[0]?.email === 'jane@example.com';
102
+ await env.DB.exec(`DROP TABLE IF EXISTS "${tableName}"`);
103
+
104
+ return new Response(JSON.stringify({ success, result: updated[0] }), {
105
+ headers: { 'Content-Type': 'application/json' }
106
+ });
107
+ } catch (error: unknown) {
108
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
109
+ return new Response(JSON.stringify({ error: errorMessage }), {
110
+ status: 500,
111
+ headers: { 'Content-Type': 'application/json' }
112
+ });
113
+ }
114
+ }
115
+
116
+ case '/test/select-records': {
117
+ try {
118
+ const factory = new D1DrizzleAdapterFactory();
119
+ const adapter = await factory.create({
120
+ DATABASE: env.DB
121
+ }) as D1DrizzleAdapter;
122
+
123
+ const connection = adapter.getConnection();
124
+ const client = await connection.getClient();
125
+
126
+ // Create table definition
127
+ const dataTypes = adapter.getDataTypes();
128
+ const tableName = `test_users_${Date.now()}_${generateUUID().replace(/-/g, '_')}`;
129
+ const users = dataTypes.dbTable(tableName, {
130
+ id: dataTypes.dbInteger('id').primaryKey({ autoIncrement: true }),
131
+ name: dataTypes.dbText('name').notNull(),
132
+ email: dataTypes.dbText('email').notNull()
133
+ });
134
+
135
+ // Create table
136
+ await env.DB.exec(`CREATE TABLE "${tableName}" (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, email TEXT NOT NULL)`);
137
+
138
+ // Insert test data
139
+ await client.insert(users).values([
140
+ { name: 'User 1', email: 'user1@example.com' },
141
+ { name: 'User 2', email: 'user2@example.com' }
142
+ ]);
143
+
144
+ // Select all records
145
+ const allUsers = await client.select().from(users);
146
+
147
+ // Select specific record
148
+ const specificUser = await client
149
+ .select()
150
+ .from(users)
151
+ .where(eq(users.email, 'user1@example.com'));
152
+
153
+ // Verify and cleanup
154
+ const success = allUsers.length >= 2 &&
155
+ specificUser[0]?.name === 'User 1';
156
+ await env.DB.exec(`DROP TABLE IF EXISTS "${tableName}"`);
157
+
158
+ return new Response(JSON.stringify({
159
+ success,
160
+ allUsers,
161
+ specificUser: specificUser[0]
162
+ }), {
163
+ headers: { 'Content-Type': 'application/json' }
164
+ });
165
+ } catch (error: unknown) {
166
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
167
+ return new Response(JSON.stringify({ error: errorMessage }), {
168
+ status: 500,
169
+ headers: { 'Content-Type': 'application/json' }
170
+ });
171
+ }
172
+ }
173
+
174
+ case '/test/migrations': {
175
+ try {
176
+ const factory = new D1DrizzleAdapterFactory();
177
+ const adapter = await factory.create({
178
+ DATABASE: env.DB
179
+ }) as D1DrizzleAdapter;
180
+
181
+ const connection = adapter.getConnection();
182
+ const client = await connection.getClient();
183
+
184
+ // Create table definition
185
+ const dataTypes = adapter.getDataTypes();
186
+ const tableName = `event_action_${Date.now()}_${generateUUID().replace(/-/g, '_')}`;
187
+ const eventActionTable = dataTypes.dbTable(tableName, {
188
+ id: dataTypes.dbInteger('id').primaryKey({ autoIncrement: true }),
189
+ createdAt: dataTypes.dbInteger('created_at').notNull().default(sql`CURRENT_TIMESTAMP`),
190
+ updatedAt: dataTypes.dbInteger('updated_at').notNull(),
191
+ action: dataTypes.dbText('action').notNull()
192
+ });
193
+
194
+ // Create table
195
+ await env.DB.exec(`CREATE TABLE "${tableName}" (id INTEGER PRIMARY KEY AUTOINCREMENT, created_at INTEGER NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at INTEGER NOT NULL, action TEXT NOT NULL)`);
196
+
197
+ // Create index
198
+ const indexName = `idx_${tableName}`;
199
+ await env.DB.exec(`CREATE INDEX "${indexName}" ON "${tableName}" (action)`);
200
+
201
+ // Insert test data
202
+ const now = Math.floor(Date.now() / 1000);
203
+ const result = await client.insert(eventActionTable).values({
204
+ action: 'TEST_ACTION',
205
+ updatedAt: now
206
+ }).returning();
207
+
208
+ // Test update
209
+ await new Promise(resolve => setTimeout(resolve, 1000));
210
+ const newTimestamp = Math.floor(Date.now() / 1000);
211
+ const updated = await client
212
+ .update(eventActionTable)
213
+ .set({
214
+ action: 'UPDATED_ACTION',
215
+ updatedAt: newTimestamp
216
+ })
217
+ .where(sql`${eventActionTable.id} = ${result[0].id}`)
218
+ .returning();
219
+
220
+ // Verify and cleanup
221
+ const success = result[0]?.action === 'TEST_ACTION' &&
222
+ updated[0]?.action === 'UPDATED_ACTION' &&
223
+ updated[0]?.updatedAt > result[0]?.updatedAt;
224
+
225
+ await env.DB.exec(`DROP TABLE IF EXISTS "${tableName}"`);
226
+
227
+ return new Response(JSON.stringify({
228
+ success,
229
+ initial: result[0],
230
+ updated: updated[0]
231
+ }), {
232
+ headers: { 'Content-Type': 'application/json' }
233
+ });
234
+ } catch (error: unknown) {
235
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
236
+ return new Response(JSON.stringify({ error: errorMessage }), {
237
+ status: 500,
238
+ headers: { 'Content-Type': 'application/json' }
239
+ });
240
+ }
241
+ }
242
+
243
+ case '/test/constraints': {
244
+ try {
245
+ const tableName = `event_action_${Date.now()}_${generateUUID().replace(/-/g, '_')}`;
246
+
247
+ // Create table
248
+ await env.DB.exec(`CREATE TABLE "${tableName}" (id INTEGER PRIMARY KEY AUTOINCREMENT, created_at INTEGER NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at INTEGER NOT NULL, action TEXT NOT NULL)`);
249
+
250
+ let error: unknown;
251
+ try {
252
+ // Try to insert NULL values
253
+ await env.DB.exec(`INSERT INTO "${tableName}" (updated_at, action) VALUES (${Math.floor(Date.now() / 1000)}, NULL)`);
254
+ } catch (e) {
255
+ error = e;
256
+ }
257
+
258
+ // Cleanup
259
+ await env.DB.exec(`DROP TABLE IF EXISTS "${tableName}"`);
260
+
261
+ // Verify
262
+ const success = error instanceof Error &&
263
+ error.message.includes('NOT NULL constraint failed');
264
+
265
+ return new Response(JSON.stringify({ success }), {
266
+ headers: { 'Content-Type': 'application/json' }
267
+ });
268
+ } catch (error: unknown) {
269
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
270
+ return new Response(JSON.stringify({ error: errorMessage }), {
271
+ status: 500,
272
+ headers: { 'Content-Type': 'application/json' }
273
+ });
274
+ }
275
+ }
276
+
277
+ case '/test/text-type': {
278
+ try {
279
+ const factory = new D1DrizzleAdapterFactory();
280
+ const adapter = await factory.create({
281
+ DATABASE: env.DB
282
+ }) as D1DrizzleAdapter;
283
+
284
+ const connection = adapter.getConnection();
285
+ const client = await connection.getClient();
286
+
287
+ // Create table definition
288
+ const dataTypes = adapter.getDataTypes();
289
+ const tableName = `event_action_${Date.now()}_${generateUUID().replace(/-/g, '_')}`;
290
+ const eventActionTable = dataTypes.dbTable(tableName, {
291
+ id: dataTypes.dbInteger('id').primaryKey({ autoIncrement: true }),
292
+ createdAt: dataTypes.dbInteger('created_at').notNull().default(sql`CURRENT_TIMESTAMP`),
293
+ updatedAt: dataTypes.dbInteger('updated_at').notNull(),
294
+ action: dataTypes.dbText('action').notNull()
295
+ });
296
+
297
+ // Create table
298
+ await env.DB.exec(`CREATE TABLE "${tableName}" (id INTEGER PRIMARY KEY AUTOINCREMENT, created_at INTEGER NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at INTEGER NOT NULL, action TEXT NOT NULL)`);
299
+
300
+ // Test with a long text value
301
+ const longAction = 'A'.repeat(1000);
302
+ const result = await client.insert(eventActionTable).values({
303
+ action: longAction,
304
+ updatedAt: Math.floor(Date.now() / 1000)
305
+ }).returning();
306
+
307
+ // Verify and cleanup
308
+ const success = result[0]?.action === longAction;
309
+ await env.DB.exec(`DROP TABLE IF EXISTS "${tableName}"`);
310
+
311
+ return new Response(JSON.stringify({
312
+ success,
313
+ result: result[0]
314
+ }), {
315
+ headers: { 'Content-Type': 'application/json' }
316
+ });
317
+ } catch (error: unknown) {
318
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
319
+ return new Response(JSON.stringify({ error: errorMessage }), {
320
+ status: 500,
321
+ headers: { 'Content-Type': 'application/json' }
322
+ });
323
+ }
324
+ }
325
+
326
+ default:
327
+ return new Response('D1 Worker Ready');
328
+ }
329
+ }
330
+ };
331
+
332
+ export interface Env {
333
+ DB: D1Database;
334
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "include": ["**/*.ts", "**/*.tsx"],
4
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "compilerOptions": {
3
+ "jsx": "react",
4
+ "lib": ["ESNext"],
5
+ "target": "ESNext",
6
+ "module": "ESNext",
7
+
8
+ // Node module resolution
9
+ "moduleResolution": "node",
10
+ "verbatimModuleSyntax": true,
11
+ "esModuleInterop": true,
12
+
13
+ // Emit options
14
+ "declaration": true,
15
+ "emitDeclarationOnly": false,
16
+ "rootDir": "./src",
17
+ "outDir": "./dist",
18
+ "resolveJsonModule": true,
19
+ "allowSyntheticDefaultImports": true,
20
+
21
+ // Best practices
22
+ "strict": true,
23
+ "skipLibCheck": true,
24
+ "noFallthroughCasesInSwitch": true,
25
+
26
+ // Some stricter flags (disabled by default)
27
+ "noUnusedLocals": true,
28
+ "noUnusedParameters": true,
29
+ "noPropertyAccessFromIndexSignature": true,
30
+
31
+ "baseUrl": ".",
32
+ "paths": {
33
+ "@drizzle-adapter/*": ["../*/dist"]
34
+ }
35
+ },
36
+ "include": ["src/**/*.ts", "tests/worker.ts", "tests/worker.ts"],
37
+ "exclude": ["node_modules", "dist", "tests"]
38
+ }
@@ -0,0 +1,15 @@
1
+ import { defineConfig } from 'vitest/config';
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ globals: true,
6
+ environment: 'node',
7
+ include: ['tests/**/*.test.ts'],
8
+ // Run tests sequentially
9
+ threads: false,
10
+ // Increase timeout for integration tests
11
+ testTimeout: 10000,
12
+ // Ensure test isolation
13
+ isolate: true
14
+ }
15
+ });
package/wrangler.toml ADDED
@@ -0,0 +1,8 @@
1
+ name = "drizzle-adapter-d1"
2
+ main = "src/worker.ts"
3
+ compatibility_date = "2024-02-28"
4
+
5
+ [[d1_databases]]
6
+ binding = "DB"
7
+ database_name = "drizzle-adapter-test"
8
+ database_id = "45bdd3c7-9fa9-4f31-be4c-8e90c09540e7"