driftsql 0.0.1 → 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.
- package/LICENSE +21 -0
- package/README.md +213 -53
- package/dist/index.d.mts +50 -0
- package/dist/index.d.ts +50 -0
- package/dist/index.mjs +194 -0
- package/package.json +44 -11
- package/dist/client.d.ts +0 -68
- package/dist/functions/create.d.ts +0 -6
- package/dist/functions/delete.d.ts +0 -5
- package/dist/functions/deleteMany.d.ts +0 -5
- package/dist/functions/findFirst.d.ts +0 -5
- package/dist/functions/findMany.d.ts +0 -7
- package/dist/functions/findOne.d.ts +0 -5
- package/dist/functions/update.d.ts +0 -6
- package/dist/lib/clean.d.ts +0 -1
- package/dist/main.d.ts +0 -2
- package/dist/main.js +0 -3
- package/dist/main.js.map +0 -91
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c)
|
|
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
CHANGED
|
@@ -1,83 +1,243 @@
|
|
|
1
|
-
#
|
|
1
|
+
# DriftSQL
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
<!-- automd:badges color=yellow -->
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
[](https://npmjs.com/package/driftsql)
|
|
6
|
+
[](https://npm.chart.dev/driftsql)
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
<!-- /automd -->
|
|
9
|
+
|
|
10
|
+
A lightweight SQL client for TypeScript, supporting multiple databases like PostgreSQL, LibSQL, and HTTP-based database services. DriftSQL provides a unified, type-safe interface for database operations across different database drivers.
|
|
11
|
+
|
|
12
|
+
## Features
|
|
13
|
+
|
|
14
|
+
- 🔐 Type-safe database operations with TypeScript generics
|
|
15
|
+
- 🛡️ SQL injection protection with parameterized queries
|
|
16
|
+
- 🚀 Multiple driver support (PostgreSQL, LibSQL, HTTP)
|
|
17
|
+
- 📝 Auto-completion support for database schema types
|
|
18
|
+
- ⚡ Built-in error handling and connection management
|
|
19
|
+
- 🔄 Unified API across different database types
|
|
20
|
+
|
|
21
|
+
## Supported Drivers
|
|
22
|
+
|
|
23
|
+
- **PostgreSQL** - Native PostgreSQL driver via `pg`
|
|
24
|
+
- **LibSQL** - SQLite-compatible databases via `@libsql/client`
|
|
25
|
+
- **HTTP** - HTTP-based database services
|
|
26
|
+
- **Neon** - Neon serverless PostgreSQL (experimental)
|
|
10
27
|
|
|
11
28
|
## Usage
|
|
12
29
|
|
|
13
|
-
|
|
30
|
+
Install the package:
|
|
14
31
|
|
|
15
|
-
|
|
32
|
+
```sh
|
|
33
|
+
# ✨ Auto-detect (supports npm, yarn, pnpm, deno and bun)
|
|
34
|
+
npx nypm install driftsql
|
|
35
|
+
```
|
|
16
36
|
|
|
17
|
-
|
|
18
|
-
import { DriftClient } from 'driftsql';
|
|
37
|
+
Import and use:
|
|
19
38
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
39
|
+
<!-- automd:jsimport cdn name="driftsql" -->
|
|
40
|
+
|
|
41
|
+
**ESM** (Node.js, Bun, Deno)
|
|
42
|
+
|
|
43
|
+
```js
|
|
44
|
+
import { DriftSQLClient } from 'driftsql'
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
**CDN** (Deno, Bun and Browsers)
|
|
48
|
+
|
|
49
|
+
```js
|
|
50
|
+
import { DriftSQLClient } from 'https://esm.sh/driftsql'
|
|
27
51
|
```
|
|
28
52
|
|
|
29
|
-
|
|
53
|
+
<!-- /automd -->
|
|
54
|
+
|
|
55
|
+
## Quick Start
|
|
56
|
+
|
|
57
|
+
### Define Your Database Schema
|
|
30
58
|
|
|
31
|
-
|
|
59
|
+
```typescript
|
|
60
|
+
import { DriftSQLClient } from 'driftsql'
|
|
32
61
|
|
|
33
|
-
|
|
34
|
-
|
|
62
|
+
// Define your database schema types
|
|
63
|
+
interface User {
|
|
64
|
+
id: number
|
|
65
|
+
name: string
|
|
66
|
+
email: string
|
|
67
|
+
created_at: string
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
interface Post {
|
|
71
|
+
id: number
|
|
72
|
+
title: string
|
|
73
|
+
content: string | null
|
|
74
|
+
user_id: number | null
|
|
75
|
+
published: boolean
|
|
76
|
+
created_at: Date
|
|
77
|
+
updated_at: Date
|
|
78
|
+
}
|
|
35
79
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
email: string;
|
|
41
|
-
password: string;
|
|
42
|
-
created_at: string;
|
|
43
|
-
};
|
|
80
|
+
// Define your database schema
|
|
81
|
+
interface MyDatabase {
|
|
82
|
+
users: User
|
|
83
|
+
posts: Post
|
|
44
84
|
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Initialize with PostgreSQL
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
const db = new DriftSQLClient<MyDatabase>({
|
|
91
|
+
drivers: {
|
|
92
|
+
postgres: {
|
|
93
|
+
connectionString: 'postgresql://user:password@localhost:5432/mydb',
|
|
94
|
+
// or individual options:
|
|
95
|
+
// host: 'localhost',
|
|
96
|
+
// port: 5432,
|
|
97
|
+
// database: 'mydb',
|
|
98
|
+
// user: 'user',
|
|
99
|
+
// password: 'password'
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
})
|
|
103
|
+
```
|
|
45
104
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
105
|
+
### Initialize with LibSQL
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
const db = new DriftSQLClient<MyDatabase>({
|
|
109
|
+
drivers: {
|
|
110
|
+
libsql: {
|
|
111
|
+
url: 'file:local.db',
|
|
112
|
+
// or for remote:
|
|
113
|
+
// url: 'libsql://your-database.turso.io',
|
|
114
|
+
// authToken: 'your-auth-token'
|
|
115
|
+
},
|
|
51
116
|
},
|
|
52
|
-
})
|
|
117
|
+
})
|
|
53
118
|
```
|
|
54
119
|
|
|
55
|
-
|
|
120
|
+
### Initialize with HTTP
|
|
56
121
|
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
122
|
+
```typescript
|
|
123
|
+
const db = new DriftSQLClient<MyDatabase>({
|
|
124
|
+
url: 'https://your-database-api.com',
|
|
125
|
+
password: 'your-bearer-token',
|
|
126
|
+
options: {
|
|
127
|
+
defaultTimeout: 5000, // optional, defaults to 5000ms
|
|
128
|
+
},
|
|
129
|
+
})
|
|
130
|
+
```
|
|
61
131
|
|
|
62
|
-
|
|
63
|
-
const user = await db.findOne({ table: 'users', id: 1 });
|
|
132
|
+
### Database Operations
|
|
64
133
|
|
|
65
|
-
|
|
66
|
-
|
|
134
|
+
```typescript
|
|
135
|
+
// Raw SQL queries
|
|
136
|
+
const users = await db.query<User>('SELECT * FROM users WHERE active = $1', [true])
|
|
137
|
+
console.log(users.rows)
|
|
67
138
|
|
|
68
|
-
//
|
|
69
|
-
const user = await db.
|
|
139
|
+
// Find operations
|
|
140
|
+
const user = await db.findFirst('users', { email: 'user@example.com' })
|
|
141
|
+
const activeUsers = await db.findMany('users', { active: true })
|
|
70
142
|
|
|
71
|
-
//
|
|
72
|
-
const
|
|
143
|
+
// Insert operations
|
|
144
|
+
const newUser = await db.insert('users', {
|
|
145
|
+
name: 'John Doe',
|
|
146
|
+
email: 'john@example.com',
|
|
147
|
+
})
|
|
73
148
|
|
|
74
|
-
//
|
|
75
|
-
const
|
|
149
|
+
// Update operations
|
|
150
|
+
const updatedUser = await db.update('users', { name: 'Jane Doe' }, { id: 1 })
|
|
76
151
|
|
|
77
|
-
// Delete
|
|
78
|
-
const
|
|
152
|
+
// Delete operations
|
|
153
|
+
const deleted = await db.delete('users', { id: 1 })
|
|
154
|
+
|
|
155
|
+
// Check server status (HTTP only)
|
|
156
|
+
const status = await db.status()
|
|
157
|
+
console.log(`Database OK: ${status.ok}, Ping: ${status.ping}ms`)
|
|
158
|
+
|
|
159
|
+
// Clean up connections
|
|
160
|
+
await db.close()
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## API Reference
|
|
164
|
+
|
|
165
|
+
### Constructor Options
|
|
166
|
+
|
|
167
|
+
```typescript
|
|
168
|
+
interface ClientOptions {
|
|
169
|
+
url?: string // HTTP server URL (for HTTP driver)
|
|
170
|
+
password?: string // Bearer token for HTTP authentication
|
|
171
|
+
drivers?: {
|
|
172
|
+
libsql?: LibsqlClientConfig // LibSQL configuration
|
|
173
|
+
postgres?: PoolConfig // PostgreSQL configuration
|
|
174
|
+
postgresNeonHTTP?: {
|
|
175
|
+
// Neon configuration (experimental)
|
|
176
|
+
connectionString: string
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
options?: {
|
|
180
|
+
defaultTimeout?: number // Request timeout in milliseconds
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Methods
|
|
186
|
+
|
|
187
|
+
- `query<T>(sql: string, args?: (string | number | boolean | null)[])` - Execute raw SQL with parameters
|
|
188
|
+
- `findFirst<K>(table: K, where?: Partial<DT[K]>)` - Find first matching record
|
|
189
|
+
- `findMany<K>(table: K, where?: Partial<DT[K]>)` - Find all matching records
|
|
190
|
+
- `insert<K>(table: K, data: Partial<DT[K]>)` - Insert new record
|
|
191
|
+
- `update<K>(table: K, data: Partial<DT[K]>, where: Partial<DT[K]>)` - Update records
|
|
192
|
+
- `delete<K>(table: K, where: Partial<DT[K]>)` - Delete records
|
|
193
|
+
- `deleteFirst<K>(table: K, where: Partial<DT[K]>)` - Delete first matching record
|
|
194
|
+
- `status()` - Get server status and ping (HTTP driver only)
|
|
195
|
+
- `close()` - Close database connections
|
|
196
|
+
|
|
197
|
+
### Return Types
|
|
198
|
+
|
|
199
|
+
All query methods return a unified result format:
|
|
200
|
+
|
|
201
|
+
```typescript
|
|
202
|
+
type UnifiedQueryResult<T> = {
|
|
203
|
+
rows: T[]
|
|
204
|
+
rowCount: number
|
|
205
|
+
command?: string
|
|
206
|
+
fields?: Array<{ name: string; dataTypeID: number }>
|
|
207
|
+
}
|
|
79
208
|
```
|
|
80
209
|
|
|
210
|
+
## Development
|
|
211
|
+
|
|
212
|
+
<details>
|
|
213
|
+
|
|
214
|
+
<summary>local development</summary>
|
|
215
|
+
|
|
216
|
+
- Clone this repository
|
|
217
|
+
- Install latest LTS version of [Node.js](https://nodejs.org/en/)
|
|
218
|
+
- Enable [Corepack](https://github.com/nodejs/corepack) using `corepack enable`
|
|
219
|
+
- Install dependencies using `pnpm install`
|
|
220
|
+
- Run interactive tests using `pnpm dev`
|
|
221
|
+
|
|
222
|
+
</details>
|
|
223
|
+
|
|
81
224
|
## License
|
|
82
225
|
|
|
83
|
-
MIT
|
|
226
|
+
<!-- automd:contributors license=MIT -->
|
|
227
|
+
|
|
228
|
+
Published under the [MIT](https://github.com/lassejlv/postgres-http-js/blob/main/LICENSE) license.
|
|
229
|
+
Made by [community](https://github.com/lassejlv/postgres-http-js/graphs/contributors) 💛
|
|
230
|
+
<br><br>
|
|
231
|
+
<a href="https://github.com/lassejlv/postgres-http-js/graphs/contributors">
|
|
232
|
+
<img src="https://contrib.rocks/image?repo=lassejlv/postgres-http-js" />
|
|
233
|
+
</a>
|
|
234
|
+
|
|
235
|
+
<!-- /automd -->
|
|
236
|
+
|
|
237
|
+
<!-- automd:with-automd -->
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
_🤖 auto updated with [automd](https://automd.unjs.io)_
|
|
242
|
+
|
|
243
|
+
<!-- /automd -->
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { PoolConfig } from 'pg';
|
|
2
|
+
import { Config } from '@libsql/client';
|
|
3
|
+
|
|
4
|
+
type UnifiedQueryResult<T extends Record<string, any>> = {
|
|
5
|
+
rows: T[];
|
|
6
|
+
rowCount: number;
|
|
7
|
+
command?: string;
|
|
8
|
+
fields?: Array<{
|
|
9
|
+
name: string;
|
|
10
|
+
dataTypeID: number;
|
|
11
|
+
}>;
|
|
12
|
+
};
|
|
13
|
+
interface ClientOptions {
|
|
14
|
+
url?: string;
|
|
15
|
+
password?: string;
|
|
16
|
+
drivers?: {
|
|
17
|
+
libsql?: Config;
|
|
18
|
+
postgres?: PoolConfig;
|
|
19
|
+
/** @deprecated use the postgres driver instead */
|
|
20
|
+
postgresNeonHTTP?: {
|
|
21
|
+
connectionString: string;
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
options?: {
|
|
25
|
+
defaultTimeout?: number;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
declare class DriftSQLClient<DT> {
|
|
29
|
+
private client;
|
|
30
|
+
private pool?;
|
|
31
|
+
private libsqlClient?;
|
|
32
|
+
private neonClient?;
|
|
33
|
+
constructor(options: ClientOptions);
|
|
34
|
+
private convertLibsqlResult;
|
|
35
|
+
query<T extends Record<string, any>>(query: string, args?: (string | number | boolean | null)[]): Promise<UnifiedQueryResult<T>>;
|
|
36
|
+
status(): Promise<{
|
|
37
|
+
ok: boolean;
|
|
38
|
+
ping: number;
|
|
39
|
+
}>;
|
|
40
|
+
findFirst<K extends keyof DT>(table: K, where?: Partial<DT[K]>): Promise<DT[K] | null>;
|
|
41
|
+
findMany<K extends keyof DT>(table: K, where?: Partial<DT[K]>): Promise<DT[K][]>;
|
|
42
|
+
insert<K extends keyof DT>(table: K, data: Partial<DT[K]>): Promise<DT[K]>;
|
|
43
|
+
update<K extends keyof DT>(table: K, data: Partial<DT[K]>, where: Partial<DT[K]>): Promise<DT[K] | null>;
|
|
44
|
+
delete<K extends keyof DT>(table: K, where: Partial<DT[K]>): Promise<boolean>;
|
|
45
|
+
deleteFirst<K extends keyof DT>(table: K, where: Partial<DT[K]>): Promise<boolean>;
|
|
46
|
+
close(): Promise<void>;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export { DriftSQLClient };
|
|
50
|
+
export type { ClientOptions };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { PoolConfig } from 'pg';
|
|
2
|
+
import { Config } from '@libsql/client';
|
|
3
|
+
|
|
4
|
+
type UnifiedQueryResult<T extends Record<string, any>> = {
|
|
5
|
+
rows: T[];
|
|
6
|
+
rowCount: number;
|
|
7
|
+
command?: string;
|
|
8
|
+
fields?: Array<{
|
|
9
|
+
name: string;
|
|
10
|
+
dataTypeID: number;
|
|
11
|
+
}>;
|
|
12
|
+
};
|
|
13
|
+
interface ClientOptions {
|
|
14
|
+
url?: string;
|
|
15
|
+
password?: string;
|
|
16
|
+
drivers?: {
|
|
17
|
+
libsql?: Config;
|
|
18
|
+
postgres?: PoolConfig;
|
|
19
|
+
/** @deprecated use the postgres driver instead */
|
|
20
|
+
postgresNeonHTTP?: {
|
|
21
|
+
connectionString: string;
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
options?: {
|
|
25
|
+
defaultTimeout?: number;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
declare class DriftSQLClient<DT> {
|
|
29
|
+
private client;
|
|
30
|
+
private pool?;
|
|
31
|
+
private libsqlClient?;
|
|
32
|
+
private neonClient?;
|
|
33
|
+
constructor(options: ClientOptions);
|
|
34
|
+
private convertLibsqlResult;
|
|
35
|
+
query<T extends Record<string, any>>(query: string, args?: (string | number | boolean | null)[]): Promise<UnifiedQueryResult<T>>;
|
|
36
|
+
status(): Promise<{
|
|
37
|
+
ok: boolean;
|
|
38
|
+
ping: number;
|
|
39
|
+
}>;
|
|
40
|
+
findFirst<K extends keyof DT>(table: K, where?: Partial<DT[K]>): Promise<DT[K] | null>;
|
|
41
|
+
findMany<K extends keyof DT>(table: K, where?: Partial<DT[K]>): Promise<DT[K][]>;
|
|
42
|
+
insert<K extends keyof DT>(table: K, data: Partial<DT[K]>): Promise<DT[K]>;
|
|
43
|
+
update<K extends keyof DT>(table: K, data: Partial<DT[K]>, where: Partial<DT[K]>): Promise<DT[K] | null>;
|
|
44
|
+
delete<K extends keyof DT>(table: K, where: Partial<DT[K]>): Promise<boolean>;
|
|
45
|
+
deleteFirst<K extends keyof DT>(table: K, where: Partial<DT[K]>): Promise<boolean>;
|
|
46
|
+
close(): Promise<void>;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export { DriftSQLClient };
|
|
50
|
+
export type { ClientOptions };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import consola from 'consola';
|
|
2
|
+
import ky from 'ky';
|
|
3
|
+
import { Pool } from 'pg';
|
|
4
|
+
import { createClient } from '@libsql/client';
|
|
5
|
+
import { neon } from '@neondatabase/serverless';
|
|
6
|
+
|
|
7
|
+
class DriftSQLClient {
|
|
8
|
+
client;
|
|
9
|
+
pool;
|
|
10
|
+
libsqlClient;
|
|
11
|
+
neonClient;
|
|
12
|
+
constructor(options) {
|
|
13
|
+
this.client = ky.create({
|
|
14
|
+
prefixUrl: options.url,
|
|
15
|
+
headers: {
|
|
16
|
+
Authorization: `Bearer ${options.password}`
|
|
17
|
+
},
|
|
18
|
+
timeout: options.options?.defaultTimeout || 5e3,
|
|
19
|
+
hooks: {
|
|
20
|
+
afterResponse: [
|
|
21
|
+
async (request, options2, response) => {
|
|
22
|
+
if (!response.ok) {
|
|
23
|
+
const errorText = await response.text();
|
|
24
|
+
throw new Error(`HTTP Error: ${response.status} - ${errorText}`);
|
|
25
|
+
}
|
|
26
|
+
return response;
|
|
27
|
+
}
|
|
28
|
+
]
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
this.pool = options.drivers?.postgres ? new Pool(options.drivers.postgres) : void 0;
|
|
32
|
+
this.libsqlClient = options.drivers?.libsql ? createClient(options.drivers.libsql) : void 0;
|
|
33
|
+
this.neonClient = options.drivers?.postgresNeonHTTP ? neon(options.drivers.postgresNeonHTTP.connectionString) : void 0;
|
|
34
|
+
}
|
|
35
|
+
convertLibsqlResult(result) {
|
|
36
|
+
const rows = result.rows.map((row) => {
|
|
37
|
+
const obj = {};
|
|
38
|
+
result.columns.forEach((col, index) => {
|
|
39
|
+
obj[col] = row[index];
|
|
40
|
+
});
|
|
41
|
+
return obj;
|
|
42
|
+
});
|
|
43
|
+
return {
|
|
44
|
+
rows,
|
|
45
|
+
rowCount: result.rowsAffected || rows.length,
|
|
46
|
+
command: void 0,
|
|
47
|
+
fields: result.columns.map((col) => ({ name: col, dataTypeID: 0 }))
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
async query(query, args) {
|
|
51
|
+
if (this.pool) {
|
|
52
|
+
try {
|
|
53
|
+
await this.pool.connect();
|
|
54
|
+
const result = await this.pool.query(query, args || []);
|
|
55
|
+
return {
|
|
56
|
+
rows: result.rows,
|
|
57
|
+
rowCount: result.rowCount || 0,
|
|
58
|
+
command: result.command,
|
|
59
|
+
fields: result.fields
|
|
60
|
+
};
|
|
61
|
+
} catch (error) {
|
|
62
|
+
consola.error("Failed to connect to PostgreSQL pool:", error);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (this.libsqlClient) {
|
|
66
|
+
try {
|
|
67
|
+
const result = await this.libsqlClient.execute({
|
|
68
|
+
sql: query,
|
|
69
|
+
args: args || []
|
|
70
|
+
});
|
|
71
|
+
return this.convertLibsqlResult(result);
|
|
72
|
+
} catch (error) {
|
|
73
|
+
consola.error("Failed to execute query with libsql:", error);
|
|
74
|
+
throw error;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (this.neonClient) {
|
|
78
|
+
try {
|
|
79
|
+
const sql = this.neonClient;
|
|
80
|
+
console.log(sql);
|
|
81
|
+
throw new Error("Neon client is not implemented yet");
|
|
82
|
+
return {
|
|
83
|
+
rows: [],
|
|
84
|
+
rowCount: 0
|
|
85
|
+
};
|
|
86
|
+
} catch (error) {
|
|
87
|
+
consola.error("Failed to execute query with Neon:", error);
|
|
88
|
+
throw error;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
try {
|
|
92
|
+
const response = await this.client.post("query", {
|
|
93
|
+
json: { query, args: args || [] }
|
|
94
|
+
});
|
|
95
|
+
return response.json();
|
|
96
|
+
} catch (error) {
|
|
97
|
+
if (error instanceof Error) {
|
|
98
|
+
throw error;
|
|
99
|
+
}
|
|
100
|
+
throw new Error(`Query failed: ${JSON.stringify(error)}`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
async status() {
|
|
104
|
+
if (!this.client) {
|
|
105
|
+
throw new Error("HTTP client is not configured");
|
|
106
|
+
}
|
|
107
|
+
const response = await this.client.get("status");
|
|
108
|
+
return response.json();
|
|
109
|
+
}
|
|
110
|
+
async findFirst(table, where) {
|
|
111
|
+
const tableName = String(table);
|
|
112
|
+
const whereEntries = Object.entries(where || {});
|
|
113
|
+
let query = `SELECT * FROM ${tableName}`;
|
|
114
|
+
let args = [];
|
|
115
|
+
if (whereEntries.length > 0) {
|
|
116
|
+
const whereClause = whereEntries.map(([key], index) => `${key} = $${index + 1}`).join(" AND ");
|
|
117
|
+
query += ` WHERE ${whereClause}`;
|
|
118
|
+
args = whereEntries.map(([, value]) => value);
|
|
119
|
+
}
|
|
120
|
+
query += " LIMIT 1";
|
|
121
|
+
const result = await this.query(query, args);
|
|
122
|
+
return result.rows[0] || null;
|
|
123
|
+
}
|
|
124
|
+
async findMany(table, where) {
|
|
125
|
+
const tableName = String(table);
|
|
126
|
+
const whereEntries = Object.entries(where || {});
|
|
127
|
+
let query = `SELECT * FROM ${tableName}`;
|
|
128
|
+
let args = [];
|
|
129
|
+
if (whereEntries.length > 0) {
|
|
130
|
+
const whereClause = whereEntries.map(([key], index) => `${key} = $${index + 1}`).join(" AND ");
|
|
131
|
+
query += ` WHERE ${whereClause}`;
|
|
132
|
+
args = whereEntries.map(([, value]) => value);
|
|
133
|
+
}
|
|
134
|
+
const result = await this.query(query, args);
|
|
135
|
+
return result.rows;
|
|
136
|
+
}
|
|
137
|
+
async insert(table, data) {
|
|
138
|
+
const tableName = String(table);
|
|
139
|
+
const keys = Object.keys(data);
|
|
140
|
+
const values = Object.values(data).map((value) => value);
|
|
141
|
+
if (keys.length === 0) {
|
|
142
|
+
throw new Error("No data provided for insert");
|
|
143
|
+
}
|
|
144
|
+
const placeholders = keys.map((_, index) => `$${index + 1}`).join(", ");
|
|
145
|
+
const query = `INSERT INTO ${tableName} (${keys.join(", ")}) VALUES (${placeholders}) RETURNING *`;
|
|
146
|
+
const result = await this.query(query, values);
|
|
147
|
+
if (!result.rows[0]) {
|
|
148
|
+
throw new Error("Insert failed: No data returned");
|
|
149
|
+
}
|
|
150
|
+
return result.rows[0];
|
|
151
|
+
}
|
|
152
|
+
async update(table, data, where) {
|
|
153
|
+
const tableName = String(table);
|
|
154
|
+
const setEntries = Object.entries(data);
|
|
155
|
+
const whereEntries = Object.entries(where);
|
|
156
|
+
if (setEntries.length === 0) {
|
|
157
|
+
throw new Error("No data provided for update");
|
|
158
|
+
}
|
|
159
|
+
if (whereEntries.length === 0) {
|
|
160
|
+
throw new Error("No conditions provided for update");
|
|
161
|
+
}
|
|
162
|
+
const setClause = setEntries.map(([key], index) => `${key} = $${index + 1}`).join(", ");
|
|
163
|
+
const whereClause = whereEntries.map(([key], index) => `${key} = $${setEntries.length + index + 1}`).join(" AND ");
|
|
164
|
+
const query = `UPDATE ${tableName} SET ${setClause} WHERE ${whereClause} RETURNING *`;
|
|
165
|
+
const args = [...setEntries.map(([, value]) => value), ...whereEntries.map(([, value]) => value)];
|
|
166
|
+
const result = await this.query(query, args);
|
|
167
|
+
return result.rows[0] || null;
|
|
168
|
+
}
|
|
169
|
+
async delete(table, where) {
|
|
170
|
+
const tableName = String(table);
|
|
171
|
+
const whereEntries = Object.entries(where);
|
|
172
|
+
if (whereEntries.length === 0) {
|
|
173
|
+
throw new Error("No conditions provided for delete");
|
|
174
|
+
}
|
|
175
|
+
const whereClause = whereEntries.map(([key], index) => `${key} = $${index + 1}`).join(" AND ");
|
|
176
|
+
const query = `DELETE FROM ${tableName} WHERE ${whereClause}`;
|
|
177
|
+
const args = whereEntries.map(([, value]) => value);
|
|
178
|
+
const result = await this.query(query, args);
|
|
179
|
+
return (result.rowCount || 0) > 0;
|
|
180
|
+
}
|
|
181
|
+
deleteFirst(table, where) {
|
|
182
|
+
return this.delete(table, where);
|
|
183
|
+
}
|
|
184
|
+
async close() {
|
|
185
|
+
if (this.pool) {
|
|
186
|
+
await this.pool.end();
|
|
187
|
+
}
|
|
188
|
+
if (this.libsqlClient) {
|
|
189
|
+
this.libsqlClient.close();
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export { DriftSQLClient };
|
package/package.json
CHANGED
|
@@ -1,19 +1,52 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "driftsql",
|
|
3
|
-
"version": "0.0
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"author": "lasse vestergaard",
|
|
5
|
+
"description": "A lightweight SQL client for TypeScript, supporting multiple databases like PostgreSQL, MySQL, and LibSQL.",
|
|
6
|
+
"repository": "lassejlv/driftsql",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"sideEffects": false,
|
|
6
9
|
"type": "module",
|
|
7
|
-
"
|
|
8
|
-
|
|
9
|
-
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.mts",
|
|
13
|
+
"default": "./dist/index.mjs"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "unbuild",
|
|
21
|
+
"dev": "vitest dev",
|
|
22
|
+
"lint": "eslint . && prettier -c .",
|
|
23
|
+
"lint:fix": "automd && eslint . --fix && prettier -w .",
|
|
24
|
+
"prepack": "pnpm build",
|
|
25
|
+
"release": "pnpm test && changelogen --release && npm publish && git push --follow-tags",
|
|
26
|
+
"test": "pnpm lint && pnpm test:types && vitest run --coverage",
|
|
27
|
+
"test:types": "tsc --noEmit --skipLibCheck"
|
|
10
28
|
},
|
|
11
|
-
"
|
|
12
|
-
"
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@types/node": "^22.13.13",
|
|
31
|
+
"@vitest/coverage-v8": "^3.0.9",
|
|
32
|
+
"automd": "^0.4.0",
|
|
33
|
+
"changelogen": "^0.6.1",
|
|
34
|
+
"eslint": "^9.23.0",
|
|
35
|
+
"eslint-config-unjs": "^0.4.2",
|
|
36
|
+
"prettier": "^3.5.3",
|
|
37
|
+
"typescript": "^5.8.2",
|
|
38
|
+
"unbuild": "^3.5.0",
|
|
39
|
+
"vitest": "^3.0.9"
|
|
13
40
|
},
|
|
41
|
+
"packageManager": "pnpm@10.12.1",
|
|
14
42
|
"dependencies": {
|
|
15
|
-
"@libsql/client": "^0.
|
|
16
|
-
"
|
|
17
|
-
"
|
|
43
|
+
"@libsql/client": "^0.15.9",
|
|
44
|
+
"@neondatabase/serverless": "^1.0.1",
|
|
45
|
+
"@types/pg": "^8.15.4",
|
|
46
|
+
"consola": "^3.4.2",
|
|
47
|
+
"driftsql": "^0.0.1",
|
|
48
|
+
"drizzle-orm": "^0.44.2",
|
|
49
|
+
"ky": "^1.8.1",
|
|
50
|
+
"pg": "^8.16.0"
|
|
18
51
|
}
|
|
19
52
|
}
|