@flightdev/db 0.0.2
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/.turbo/turbo-build.log +26 -0
- package/.turbo/turbo-typecheck.log +4 -0
- package/CHANGELOG.md +7 -0
- package/LICENSE +21 -0
- package/README.md +226 -0
- package/dist/d1.d.ts +60 -0
- package/dist/d1.js +97 -0
- package/dist/index.d.ts +87 -0
- package/dist/index.js +19 -0
- package/dist/neon.d.ts +32 -0
- package/dist/neon.js +117 -0
- package/dist/postgres.d.ts +38 -0
- package/dist/postgres.js +99 -0
- package/dist/supabase.d.ts +42 -0
- package/dist/supabase.js +76 -0
- package/dist/turso.d.ts +39 -0
- package/dist/turso.js +102 -0
- package/package.json +76 -0
- package/src/ambient.d.ts +154 -0
- package/src/d1.ts +177 -0
- package/src/index.ts +140 -0
- package/src/neon.ts +164 -0
- package/src/postgres.ts +145 -0
- package/src/supabase.ts +136 -0
- package/src/turso.ts +150 -0
- package/tsconfig.json +17 -0
- package/tsup.config.ts +26 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
|
|
2
|
+
> @flightdev/db@0.0.2 build E:\testear framework\Flight\packages\db
|
|
3
|
+
> tsup
|
|
4
|
+
|
|
5
|
+
[34mCLI[39m Building entry: src/d1.ts, src/index.ts, src/neon.ts, src/postgres.ts, src/supabase.ts, src/turso.ts
|
|
6
|
+
[34mCLI[39m Using tsconfig: tsconfig.json
|
|
7
|
+
[34mCLI[39m tsup v8.5.1
|
|
8
|
+
[34mCLI[39m Using tsup config: E:\testear framework\Flight\packages\db\tsup.config.ts
|
|
9
|
+
[34mCLI[39m Target: node20
|
|
10
|
+
[34mCLI[39m Cleaning output folder
|
|
11
|
+
[34mESM[39m Build start
|
|
12
|
+
[32mESM[39m [1mdist\index.js [22m[32m402.00 B[39m
|
|
13
|
+
[32mESM[39m [1mdist\postgres.js [22m[32m2.39 KB[39m
|
|
14
|
+
[32mESM[39m [1mdist\neon.js [22m[32m2.96 KB[39m
|
|
15
|
+
[32mESM[39m [1mdist\supabase.js [22m[32m1.93 KB[39m
|
|
16
|
+
[32mESM[39m [1mdist\d1.js [22m[32m2.51 KB[39m
|
|
17
|
+
[32mESM[39m [1mdist\turso.js [22m[32m2.70 KB[39m
|
|
18
|
+
[32mESM[39m ⚡️ Build success in 23ms
|
|
19
|
+
[34mDTS[39m Build start
|
|
20
|
+
[32mDTS[39m ⚡️ Build success in 6371ms
|
|
21
|
+
[32mDTS[39m [1mdist\d1.d.ts [22m[32m1.53 KB[39m
|
|
22
|
+
[32mDTS[39m [1mdist\neon.d.ts [22m[32m857.00 B[39m
|
|
23
|
+
[32mDTS[39m [1mdist\postgres.d.ts [22m[32m907.00 B[39m
|
|
24
|
+
[32mDTS[39m [1mdist\supabase.d.ts [22m[32m1.16 KB[39m
|
|
25
|
+
[32mDTS[39m [1mdist\turso.d.ts [22m[32m916.00 B[39m
|
|
26
|
+
[32mDTS[39m [1mdist\index.d.ts [22m[32m2.92 KB[39m
|
package/CHANGELOG.md
ADDED
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024-2026 Flight Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
# @flight-framework/db
|
|
2
|
+
|
|
3
|
+
Database abstraction layer for Flight Framework. Connect to any database with a unified, type-safe API.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @flight-framework/db
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Install the driver for your database:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# PostgreSQL
|
|
15
|
+
npm install pg
|
|
16
|
+
|
|
17
|
+
# Turso / SQLite
|
|
18
|
+
npm install @libsql/client
|
|
19
|
+
|
|
20
|
+
# Neon Serverless
|
|
21
|
+
npm install @neondatabase/serverless
|
|
22
|
+
|
|
23
|
+
# Supabase
|
|
24
|
+
npm install @supabase/supabase-js
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Quick Start
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
import { createDb } from '@flight-framework/db';
|
|
31
|
+
import { postgres } from '@flight-framework/db/postgres';
|
|
32
|
+
|
|
33
|
+
const db = createDb(postgres({
|
|
34
|
+
connectionString: process.env.DATABASE_URL,
|
|
35
|
+
}));
|
|
36
|
+
|
|
37
|
+
// Query with type inference
|
|
38
|
+
const users = await db.query<{ id: string; email: string }>(
|
|
39
|
+
'SELECT * FROM users WHERE active = $1',
|
|
40
|
+
[true]
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
console.log(users.rows);
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Drivers
|
|
47
|
+
|
|
48
|
+
### PostgreSQL
|
|
49
|
+
|
|
50
|
+
Standard PostgreSQL driver using `pg` with connection pooling.
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
import { postgres } from '@flight-framework/db/postgres';
|
|
54
|
+
|
|
55
|
+
const driver = postgres({
|
|
56
|
+
connectionString: 'postgresql://user:pass@localhost:5432/mydb',
|
|
57
|
+
// Or use individual options:
|
|
58
|
+
host: 'localhost',
|
|
59
|
+
port: 5432,
|
|
60
|
+
database: 'mydb',
|
|
61
|
+
user: 'user',
|
|
62
|
+
password: 'pass',
|
|
63
|
+
ssl: true,
|
|
64
|
+
poolSize: 10,
|
|
65
|
+
timeout: 30000,
|
|
66
|
+
});
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Turso / SQLite
|
|
70
|
+
|
|
71
|
+
Cloud SQLite with Turso or local SQLite files.
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
import { turso } from '@flight-framework/db/turso';
|
|
75
|
+
|
|
76
|
+
// Turso Cloud
|
|
77
|
+
const cloud = turso({
|
|
78
|
+
url: 'libsql://your-db.turso.io',
|
|
79
|
+
authToken: process.env.TURSO_AUTH_TOKEN,
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// Local SQLite
|
|
83
|
+
const local = turso({
|
|
84
|
+
url: 'file:local.db',
|
|
85
|
+
});
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Neon Serverless
|
|
89
|
+
|
|
90
|
+
Edge-compatible PostgreSQL for serverless environments.
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
import { neon } from '@flight-framework/db/neon';
|
|
94
|
+
|
|
95
|
+
// HTTP mode (recommended for serverless)
|
|
96
|
+
const http = neon({
|
|
97
|
+
connectionString: process.env.NEON_DATABASE_URL,
|
|
98
|
+
mode: 'http',
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// WebSocket mode (for transactions)
|
|
102
|
+
const ws = neon({
|
|
103
|
+
connectionString: process.env.NEON_DATABASE_URL,
|
|
104
|
+
mode: 'websocket',
|
|
105
|
+
});
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Supabase
|
|
109
|
+
|
|
110
|
+
Direct database access with Supabase's query builder.
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
import { supabase } from '@flight-framework/db/supabase';
|
|
114
|
+
|
|
115
|
+
const driver = supabase({
|
|
116
|
+
url: process.env.SUPABASE_URL,
|
|
117
|
+
key: process.env.SUPABASE_ANON_KEY,
|
|
118
|
+
schema: 'public',
|
|
119
|
+
});
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Cloudflare D1
|
|
123
|
+
|
|
124
|
+
Native Cloudflare D1 support for edge SQLite.
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
import { d1 } from '@flight-framework/db/d1';
|
|
128
|
+
|
|
129
|
+
export default {
|
|
130
|
+
async fetch(request, env) {
|
|
131
|
+
const db = createDb(d1({ binding: env.DB }));
|
|
132
|
+
const users = await db.query('SELECT * FROM users');
|
|
133
|
+
return Response.json(users.rows);
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## API Reference
|
|
139
|
+
|
|
140
|
+
### Database Interface
|
|
141
|
+
|
|
142
|
+
```typescript
|
|
143
|
+
interface Database {
|
|
144
|
+
// Run a query that returns rows
|
|
145
|
+
query<T>(sql: string, params?: unknown[]): Promise<QueryResult<T>>;
|
|
146
|
+
|
|
147
|
+
// Execute a statement (INSERT, UPDATE, DELETE)
|
|
148
|
+
execute(sql: string, params?: unknown[]): Promise<ExecuteResult>;
|
|
149
|
+
|
|
150
|
+
// Run operations in a transaction
|
|
151
|
+
transaction<T>(fn: (tx: Transaction) => Promise<T>): Promise<T>;
|
|
152
|
+
|
|
153
|
+
// Close the connection
|
|
154
|
+
close(): Promise<void>;
|
|
155
|
+
|
|
156
|
+
// Check connection health
|
|
157
|
+
ping(): Promise<boolean>;
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Query Result
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
interface QueryResult<T> {
|
|
165
|
+
rows: T[];
|
|
166
|
+
rowCount: number;
|
|
167
|
+
raw?: unknown;
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Execute Result
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
interface ExecuteResult {
|
|
175
|
+
rowsAffected: number;
|
|
176
|
+
insertId?: string | number;
|
|
177
|
+
raw?: unknown;
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Transactions
|
|
182
|
+
|
|
183
|
+
All drivers support transactions with automatic rollback on error.
|
|
184
|
+
|
|
185
|
+
```typescript
|
|
186
|
+
const result = await db.transaction(async (tx) => {
|
|
187
|
+
const user = await tx.execute(
|
|
188
|
+
'INSERT INTO users (email) VALUES ($1) RETURNING id',
|
|
189
|
+
['user@example.com']
|
|
190
|
+
);
|
|
191
|
+
|
|
192
|
+
await tx.execute(
|
|
193
|
+
'INSERT INTO profiles (user_id, name) VALUES ($1, $2)',
|
|
194
|
+
[user.insertId, 'John Doe']
|
|
195
|
+
);
|
|
196
|
+
|
|
197
|
+
return user.insertId;
|
|
198
|
+
});
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## Type Safety
|
|
202
|
+
|
|
203
|
+
Define your row types for compile-time safety.
|
|
204
|
+
|
|
205
|
+
```typescript
|
|
206
|
+
interface User {
|
|
207
|
+
id: string;
|
|
208
|
+
email: string;
|
|
209
|
+
name: string;
|
|
210
|
+
created_at: Date;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const users = await db.query<User>('SELECT * FROM users');
|
|
214
|
+
// users.rows is typed as User[]
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
## Best Practices
|
|
218
|
+
|
|
219
|
+
1. **Use connection pooling** - All drivers support connection pools by default.
|
|
220
|
+
2. **Parameterize queries** - Always use parameterized queries to prevent SQL injection.
|
|
221
|
+
3. **Handle errors** - Wrap database operations in try-catch blocks.
|
|
222
|
+
4. **Close connections** - Call `db.close()` when shutting down your application.
|
|
223
|
+
|
|
224
|
+
## License
|
|
225
|
+
|
|
226
|
+
MIT
|
package/dist/d1.d.ts
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { Driver as DatabaseDriver } from './index.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @flightdev/db/d1 - Cloudflare D1 Driver
|
|
5
|
+
*
|
|
6
|
+
* Native Cloudflare D1 support for edge SQLite.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* // In your Cloudflare Worker
|
|
11
|
+
* import { d1 } from '@flightdev/db/d1';
|
|
12
|
+
* import { createDb } from '@flightdev/db';
|
|
13
|
+
*
|
|
14
|
+
* export default {
|
|
15
|
+
* async fetch(request, env) {
|
|
16
|
+
* const db = createDb(d1({ binding: env.DB }));
|
|
17
|
+
* const users = await db.query('SELECT * FROM users');
|
|
18
|
+
* return Response.json(users.rows);
|
|
19
|
+
* }
|
|
20
|
+
* };
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
/** D1 Database binding from Cloudflare Workers */
|
|
25
|
+
interface D1Database {
|
|
26
|
+
prepare(query: string): D1PreparedStatement;
|
|
27
|
+
batch<T = unknown>(statements: D1PreparedStatement[]): Promise<D1Result<T>[]>;
|
|
28
|
+
exec(query: string): Promise<D1ExecResult>;
|
|
29
|
+
}
|
|
30
|
+
interface D1PreparedStatement {
|
|
31
|
+
bind(...values: unknown[]): D1PreparedStatement;
|
|
32
|
+
first<T = unknown>(colName?: string): Promise<T>;
|
|
33
|
+
run(): Promise<D1Result>;
|
|
34
|
+
all<T = unknown>(): Promise<D1Result<T>>;
|
|
35
|
+
raw<T = unknown>(): Promise<T[]>;
|
|
36
|
+
}
|
|
37
|
+
interface D1Result<T = unknown> {
|
|
38
|
+
results?: T[];
|
|
39
|
+
success: boolean;
|
|
40
|
+
error?: string;
|
|
41
|
+
meta: {
|
|
42
|
+
changes: number;
|
|
43
|
+
last_row_id: number;
|
|
44
|
+
duration: number;
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
interface D1ExecResult {
|
|
48
|
+
count: number;
|
|
49
|
+
duration: number;
|
|
50
|
+
}
|
|
51
|
+
interface D1Config {
|
|
52
|
+
/** D1 database binding from env */
|
|
53
|
+
binding: D1Database;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Create a Cloudflare D1 driver
|
|
57
|
+
*/
|
|
58
|
+
declare function d1(config: D1Config): DatabaseDriver;
|
|
59
|
+
|
|
60
|
+
export { type D1Config, type D1Database, d1, d1 as default };
|
package/dist/d1.js
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// src/d1.ts
|
|
2
|
+
function d1(config) {
|
|
3
|
+
const db = config.binding;
|
|
4
|
+
return {
|
|
5
|
+
name: "d1",
|
|
6
|
+
async query(sql, params) {
|
|
7
|
+
let stmt = db.prepare(sql);
|
|
8
|
+
if (params?.length) {
|
|
9
|
+
stmt = stmt.bind(...params);
|
|
10
|
+
}
|
|
11
|
+
const result = await stmt.all();
|
|
12
|
+
return {
|
|
13
|
+
rows: result.results ?? [],
|
|
14
|
+
rowCount: result.results?.length ?? 0,
|
|
15
|
+
raw: result
|
|
16
|
+
};
|
|
17
|
+
},
|
|
18
|
+
async execute(sql, params) {
|
|
19
|
+
let stmt = db.prepare(sql);
|
|
20
|
+
if (params?.length) {
|
|
21
|
+
stmt = stmt.bind(...params);
|
|
22
|
+
}
|
|
23
|
+
const result = await stmt.run();
|
|
24
|
+
return {
|
|
25
|
+
rowsAffected: result.meta.changes,
|
|
26
|
+
insertId: result.meta.last_row_id,
|
|
27
|
+
raw: result
|
|
28
|
+
};
|
|
29
|
+
},
|
|
30
|
+
async transaction(fn) {
|
|
31
|
+
const statements = [];
|
|
32
|
+
const results = [];
|
|
33
|
+
const tx = {
|
|
34
|
+
async query(sql, params) {
|
|
35
|
+
let stmt = db.prepare(sql);
|
|
36
|
+
if (params?.length) {
|
|
37
|
+
stmt = stmt.bind(...params);
|
|
38
|
+
}
|
|
39
|
+
statements.push(stmt);
|
|
40
|
+
const placeholder = { rows: [], rowCount: 0 };
|
|
41
|
+
results.push(placeholder);
|
|
42
|
+
return placeholder;
|
|
43
|
+
},
|
|
44
|
+
async execute(sql, params) {
|
|
45
|
+
let stmt = db.prepare(sql);
|
|
46
|
+
if (params?.length) {
|
|
47
|
+
stmt = stmt.bind(...params);
|
|
48
|
+
}
|
|
49
|
+
statements.push(stmt);
|
|
50
|
+
const placeholder = { rowsAffected: 0 };
|
|
51
|
+
results.push(placeholder);
|
|
52
|
+
return placeholder;
|
|
53
|
+
},
|
|
54
|
+
async commit() {
|
|
55
|
+
const batchResults = await db.batch(statements);
|
|
56
|
+
batchResults.forEach((result, i) => {
|
|
57
|
+
const placeholder = results[i];
|
|
58
|
+
if (placeholder && "rows" in placeholder) {
|
|
59
|
+
placeholder.rows = result.results ?? [];
|
|
60
|
+
placeholder.rowCount = result.results?.length ?? 0;
|
|
61
|
+
} else if (placeholder) {
|
|
62
|
+
placeholder.rowsAffected = result.meta.changes;
|
|
63
|
+
placeholder.insertId = result.meta.last_row_id;
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
},
|
|
67
|
+
async rollback() {
|
|
68
|
+
statements.length = 0;
|
|
69
|
+
results.length = 0;
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
try {
|
|
73
|
+
const result = await fn(tx);
|
|
74
|
+
await tx.commit();
|
|
75
|
+
return result;
|
|
76
|
+
} catch (error) {
|
|
77
|
+
await tx.rollback();
|
|
78
|
+
throw error;
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
async close() {
|
|
82
|
+
},
|
|
83
|
+
async ping() {
|
|
84
|
+
try {
|
|
85
|
+
await db.prepare("SELECT 1").first();
|
|
86
|
+
return true;
|
|
87
|
+
} catch {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
var d1_default = d1;
|
|
94
|
+
export {
|
|
95
|
+
d1,
|
|
96
|
+
d1_default as default
|
|
97
|
+
};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @flightdev/db - Agnostic Database Layer
|
|
3
|
+
*
|
|
4
|
+
* Universal database abstraction with pluggable drivers.
|
|
5
|
+
* Inspired by Drizzle ORM's driver pattern but framework-agnostic.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { createDb } from '@flightdev/db';
|
|
10
|
+
* import { postgres } from '@flightdev/db/postgres';
|
|
11
|
+
*
|
|
12
|
+
* const db = createDb(postgres({ connectionString: process.env.DATABASE_URL }));
|
|
13
|
+
*
|
|
14
|
+
* const users = await db.query('SELECT * FROM users');
|
|
15
|
+
* await db.execute('INSERT INTO users (name) VALUES (?)', ['John']);
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
/** Result of a database query */
|
|
19
|
+
interface QueryResult<T = Record<string, unknown>> {
|
|
20
|
+
rows: T[];
|
|
21
|
+
rowCount: number;
|
|
22
|
+
/** Raw result from underlying driver (for advanced use) */
|
|
23
|
+
raw?: unknown;
|
|
24
|
+
}
|
|
25
|
+
/** Result of a database execute (INSERT, UPDATE, DELETE) */
|
|
26
|
+
interface ExecuteResult {
|
|
27
|
+
rowsAffected: number;
|
|
28
|
+
insertId?: string | number;
|
|
29
|
+
raw?: unknown;
|
|
30
|
+
}
|
|
31
|
+
/** Transaction interface */
|
|
32
|
+
interface Transaction {
|
|
33
|
+
query<T = Record<string, unknown>>(sql: string, params?: unknown[]): Promise<QueryResult<T>>;
|
|
34
|
+
execute(sql: string, params?: unknown[]): Promise<ExecuteResult>;
|
|
35
|
+
commit(): Promise<void>;
|
|
36
|
+
rollback(): Promise<void>;
|
|
37
|
+
}
|
|
38
|
+
/** Database connection interface - what drivers must implement */
|
|
39
|
+
interface DatabaseDriver {
|
|
40
|
+
/** Driver name for identification */
|
|
41
|
+
readonly name: string;
|
|
42
|
+
/** Query that returns rows */
|
|
43
|
+
query<T = Record<string, unknown>>(sql: string, params?: unknown[]): Promise<QueryResult<T>>;
|
|
44
|
+
/** Execute that doesn't return rows (INSERT, UPDATE, DELETE) */
|
|
45
|
+
execute(sql: string, params?: unknown[]): Promise<ExecuteResult>;
|
|
46
|
+
/** Begin a transaction */
|
|
47
|
+
transaction<T>(fn: (tx: Transaction) => Promise<T>): Promise<T>;
|
|
48
|
+
/** Close the connection */
|
|
49
|
+
close(): Promise<void>;
|
|
50
|
+
/** Check if connection is alive */
|
|
51
|
+
ping(): Promise<boolean>;
|
|
52
|
+
}
|
|
53
|
+
/** Database instance with full API */
|
|
54
|
+
interface Database extends DatabaseDriver {
|
|
55
|
+
/** The underlying driver */
|
|
56
|
+
readonly driver: DatabaseDriver;
|
|
57
|
+
/** Infer types from database (Better Auth style) */
|
|
58
|
+
readonly $Infer: {
|
|
59
|
+
Query: QueryResult;
|
|
60
|
+
Execute: ExecuteResult;
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Create a database instance from a driver
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```typescript
|
|
68
|
+
* import { createDb } from '@flightdev/db';
|
|
69
|
+
* import { postgres } from '@flightdev/db/postgres';
|
|
70
|
+
*
|
|
71
|
+
* const db = createDb(postgres({ connectionString: process.env.DATABASE_URL }));
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
declare function createDb(driver: DatabaseDriver): Database;
|
|
75
|
+
/** Infer row type from a query */
|
|
76
|
+
type InferRow<T extends QueryResult> = T['rows'][number];
|
|
77
|
+
/** Database configuration base */
|
|
78
|
+
interface DatabaseConfig {
|
|
79
|
+
/** Connection string */
|
|
80
|
+
connectionString?: string;
|
|
81
|
+
/** Pool size */
|
|
82
|
+
poolSize?: number;
|
|
83
|
+
/** Connection timeout in ms */
|
|
84
|
+
timeout?: number;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export { type Database, type DatabaseConfig, type DatabaseDriver, type DatabaseDriver as Driver, type ExecuteResult, type InferRow, type QueryResult, type Transaction, createDb };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
function createDb(driver) {
|
|
3
|
+
return {
|
|
4
|
+
name: driver.name,
|
|
5
|
+
driver,
|
|
6
|
+
query: (sql, params) => driver.query(sql, params),
|
|
7
|
+
execute: (sql, params) => driver.execute(sql, params),
|
|
8
|
+
transaction: (fn) => driver.transaction(fn),
|
|
9
|
+
close: () => driver.close(),
|
|
10
|
+
ping: () => driver.ping(),
|
|
11
|
+
$Infer: {
|
|
12
|
+
Query: {},
|
|
13
|
+
Execute: {}
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export {
|
|
18
|
+
createDb
|
|
19
|
+
};
|
package/dist/neon.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Driver as DatabaseDriver } from './index.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @flightdev/db/neon - Neon Serverless Driver
|
|
5
|
+
*
|
|
6
|
+
* Uses @neondatabase/serverless for edge-compatible PostgreSQL.
|
|
7
|
+
* Supports both HTTP (single queries) and WebSocket (transactions) modes.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```typescript
|
|
11
|
+
* import { neon } from '@flightdev/db/neon';
|
|
12
|
+
* import { createDb } from '@flightdev/db';
|
|
13
|
+
*
|
|
14
|
+
* const db = createDb(neon({
|
|
15
|
+
* connectionString: process.env.NEON_DATABASE_URL,
|
|
16
|
+
* mode: 'http', // 'http' for serverless, 'websocket' for transactions
|
|
17
|
+
* }));
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
interface NeonConfig {
|
|
22
|
+
/** Neon connection string */
|
|
23
|
+
connectionString: string;
|
|
24
|
+
/** Connection mode */
|
|
25
|
+
mode?: 'http' | 'websocket';
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Create a Neon Serverless driver
|
|
29
|
+
*/
|
|
30
|
+
declare function neon(config: NeonConfig): DatabaseDriver;
|
|
31
|
+
|
|
32
|
+
export { type NeonConfig, neon as default, neon };
|
package/dist/neon.js
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
// src/neon.ts
|
|
2
|
+
function neon(config) {
|
|
3
|
+
const mode = config.mode ?? "http";
|
|
4
|
+
let sql = null;
|
|
5
|
+
let pool = null;
|
|
6
|
+
async function getSql() {
|
|
7
|
+
if (!sql) {
|
|
8
|
+
const neonModule = await import("@neondatabase/serverless");
|
|
9
|
+
if (mode === "http") {
|
|
10
|
+
sql = neonModule.neon(config.connectionString);
|
|
11
|
+
} else {
|
|
12
|
+
const { Pool } = neonModule;
|
|
13
|
+
pool = new Pool({ connectionString: config.connectionString });
|
|
14
|
+
sql = pool;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return { sql, pool };
|
|
18
|
+
}
|
|
19
|
+
return {
|
|
20
|
+
name: "neon",
|
|
21
|
+
async query(sqlQuery, params) {
|
|
22
|
+
const { sql: client } = await getSql();
|
|
23
|
+
if (mode === "http") {
|
|
24
|
+
const rows = await client(sqlQuery, params ?? []);
|
|
25
|
+
return {
|
|
26
|
+
rows,
|
|
27
|
+
rowCount: rows.length,
|
|
28
|
+
raw: rows
|
|
29
|
+
};
|
|
30
|
+
} else {
|
|
31
|
+
const result = await client.query(sqlQuery, params);
|
|
32
|
+
return {
|
|
33
|
+
rows: result.rows,
|
|
34
|
+
rowCount: result.rowCount ?? 0,
|
|
35
|
+
raw: result
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
async execute(sqlQuery, params) {
|
|
40
|
+
const { sql: client } = await getSql();
|
|
41
|
+
if (mode === "http") {
|
|
42
|
+
const result = await client(sqlQuery, params ?? []);
|
|
43
|
+
return {
|
|
44
|
+
rowsAffected: result.length ?? 0,
|
|
45
|
+
raw: result
|
|
46
|
+
};
|
|
47
|
+
} else {
|
|
48
|
+
const result = await client.query(sqlQuery, params);
|
|
49
|
+
return {
|
|
50
|
+
rowsAffected: result.rowCount ?? 0,
|
|
51
|
+
raw: result
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
async transaction(fn) {
|
|
56
|
+
if (mode === "http") {
|
|
57
|
+
throw new Error('Transactions require websocket mode. Use neon({ mode: "websocket" })');
|
|
58
|
+
}
|
|
59
|
+
const { pool: p } = await getSql();
|
|
60
|
+
const client = await p.connect();
|
|
61
|
+
try {
|
|
62
|
+
await client.query("BEGIN");
|
|
63
|
+
const tx = {
|
|
64
|
+
async query(sqlQuery, params) {
|
|
65
|
+
const result2 = await client.query(sqlQuery, params);
|
|
66
|
+
return {
|
|
67
|
+
rows: result2.rows,
|
|
68
|
+
rowCount: result2.rowCount ?? 0,
|
|
69
|
+
raw: result2
|
|
70
|
+
};
|
|
71
|
+
},
|
|
72
|
+
async execute(sqlQuery, params) {
|
|
73
|
+
const result2 = await client.query(sqlQuery, params);
|
|
74
|
+
return {
|
|
75
|
+
rowsAffected: result2.rowCount ?? 0,
|
|
76
|
+
raw: result2
|
|
77
|
+
};
|
|
78
|
+
},
|
|
79
|
+
async commit() {
|
|
80
|
+
await client.query("COMMIT");
|
|
81
|
+
},
|
|
82
|
+
async rollback() {
|
|
83
|
+
await client.query("ROLLBACK");
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
const result = await fn(tx);
|
|
87
|
+
await client.query("COMMIT");
|
|
88
|
+
return result;
|
|
89
|
+
} catch (error) {
|
|
90
|
+
await client.query("ROLLBACK");
|
|
91
|
+
throw error;
|
|
92
|
+
} finally {
|
|
93
|
+
client.release();
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
async close() {
|
|
97
|
+
if (pool) {
|
|
98
|
+
await pool.end();
|
|
99
|
+
pool = null;
|
|
100
|
+
}
|
|
101
|
+
sql = null;
|
|
102
|
+
},
|
|
103
|
+
async ping() {
|
|
104
|
+
try {
|
|
105
|
+
await this.query("SELECT 1");
|
|
106
|
+
return true;
|
|
107
|
+
} catch {
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
var neon_default = neon;
|
|
114
|
+
export {
|
|
115
|
+
neon_default as default,
|
|
116
|
+
neon
|
|
117
|
+
};
|