driftsql 1.0.21 → 1.0.23

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
@@ -3,16 +3,7 @@
3
3
  [![npm version](https://img.shields.io/npm/v/driftsql?color=yellow)](https://npmjs.com/package/driftsql)
4
4
  [![npm downloads](https://img.shields.io/npm/dm/driftsql?color=yellow)](https://npm.chart.dev/driftsql)
5
5
 
6
- A lightweight, type-safe SQL client for TypeScript that supports multiple database drivers. Import only what you need.
7
-
8
- ## Features
9
-
10
- - 🔐 **Type-safe** - Full TypeScript support with generics
11
- - 🚀 **Modular** - Import only the drivers you need
12
- - 🛡️ **SQL injection protection** - Parameterized queries by default
13
- - 🔄 **Unified API** - Same interface across all drivers
14
- - ⚡ **Multiple drivers** - PostgreSQL, LibSQL, MySQL, SQLite
15
- - 🎯 **Custom drivers** - Easy to implement your own drivers
6
+ A lightweight, type-safe SQL client for TypeScript with support for PostgreSQL, MySQL, and LibSQL/SQLite.
16
7
 
17
8
  ## Installation
18
9
 
@@ -20,128 +11,55 @@ A lightweight, type-safe SQL client for TypeScript that supports multiple databa
20
11
  npm install driftsql
21
12
  ```
22
13
 
23
- ## Basic Usage
24
-
25
- ### Import Individual Drivers
26
-
27
- ```typescript
28
- import { PostgresDriver, LibSQLDriver, MySQLDriver, SqliteDriver, SQLClient } from 'driftsql'
29
-
30
- // Use PostgreSQL
31
- const postgresDriver = new PostgresDriver({
32
- connectionString: 'postgresql://user:password@localhost:5432/mydb'
33
- })
34
-
35
- // Use LibSQL/Turso
36
- const libsqlDriver = new LibSQLDriver({
37
- url: 'libsql://your-database.turso.io',
38
- authToken: 'your-auth-token'
39
- })
40
-
41
- // Use MySQL
42
- const mysqlDriver = new MySQLDriver({
43
- connectionString: 'mysql://user:password@localhost:3306/mydb'
44
- })
45
-
46
- // Use SQLite
47
- const sqliteDriver = new SqliteDriver({
48
- filename: './database.db'
49
- })
14
+ ## Features
50
15
 
51
- // Create a client with any driver
52
- const client = new SQLClient({ driver: postgresDriver })
53
- ```
16
+ - 🔐 **Type-safe** - Full TypeScript support
17
+ - 🚀 **Modular** - Import only what you need
18
+ - 🛡️ **SQL injection protection** - Parameterized queries
19
+ - 🔄 **Unified API** - Same interface across all drivers
20
+ - ⚡ **Transactions** - When supported by the driver
54
21
 
55
- ### Factory Functions
22
+ ## Quick Start
56
23
 
57
24
  ```typescript
58
- import { createPostgresClient, createLibSQLClient, createMySQLClient, createSqliteClient } from 'driftsql'
59
-
60
- // Quick setup
61
- const postgresClient = createPostgresClient({
62
- connectionString: 'postgresql://user:password@localhost:5432/mydb'
63
- })
64
-
65
- const libsqlClient = createLibSQLClient({
66
- url: 'file:local.db'
67
- })
68
-
69
- const mysqlClient = createMySQLClient({
70
- connectionString: 'mysql://user:password@localhost:3306/mydb'
71
- })
25
+ import { PostgresDriver, SQLClient } from 'driftsql'
72
26
 
73
- const sqliteClient = createSqliteClient({
74
- filename: './database.db'
27
+ // Choose your database
28
+ const driver = new PostgresDriver({
29
+ connectionString: 'postgresql://user:password@localhost:5432/mydb',
75
30
  })
76
- ```
77
-
78
- ## Database Operations
31
+ const client = new SQLClient({ driver })
79
32
 
80
- ### Raw Queries
33
+ // Raw queries
34
+ const result = await client.query('SELECT * FROM users WHERE id = $1', [1])
81
35
 
82
- ```typescript
83
- // Type-safe queries
84
- interface User {
85
- id: number
86
- name: string
87
- email: string
88
- }
89
-
90
- const result = await client.query<User>('SELECT * FROM users WHERE id = $1', [1])
91
- console.log(result.rows) // User[]
92
- console.log(result.rowCount) // number
36
+ // Helper methods
37
+ const user = await client.findFirst('users', { email: 'user@example.com' })
38
+ const newUser = await client.insert('users', { name: 'John', email: 'john@example.com' })
93
39
  ```
94
40
 
95
- ### Helper Methods
41
+ ## Supported Databases
96
42
 
97
43
  ```typescript
98
- // Define your database schema
99
- interface MyDatabase {
100
- users: User
101
- posts: Post
102
- }
44
+ import { PostgresDriver, LibSQLDriver, MySQLDriver, SQLClient } from 'driftsql'
103
45
 
104
- const client = new SQLClient<MyDatabase>({ driver: postgresDriver })
46
+ // PostgreSQL
47
+ const pg = new PostgresDriver({ connectionString: 'postgresql://...' })
105
48
 
106
- // Find operations
107
- const user = await client.findFirst('users', { email: 'user@example.com' })
108
- const users = await client.findMany('users', {
109
- where: { active: true },
110
- limit: 10
111
- })
112
-
113
- // Insert
114
- const newUser = await client.insert('users', {
115
- name: 'John Doe',
116
- email: 'john@example.com'
117
- })
118
-
119
- // Update
120
- const updatedUser = await client.update('users',
121
- { name: 'Jane Doe' },
122
- { id: 1 }
123
- )
124
-
125
- // Delete
126
- const deletedCount = await client.delete('users', { id: 1 })
127
- ```
49
+ // LibSQL/Turso/SQLite
50
+ const libsql = new LibSQLDriver({ url: 'libsql://...', authToken: '...' })
51
+ // or for local SQLite: new LibSQLDriver({ url: 'file:./database.db' })
128
52
 
129
- ## Transactions
53
+ // MySQL
54
+ const mysql = new MySQLDriver({ connectionString: 'mysql://...' })
130
55
 
131
- ```typescript
132
- // Check if driver supports transactions
133
- if (client.supportsTransactions()) {
134
- await client.transaction(async (txClient) => {
135
- await txClient.insert('users', { name: 'User 1', email: 'user1@example.com' })
136
- await txClient.insert('users', { name: 'User 2', email: 'user2@example.com' })
137
- // Both inserts will be committed together
138
- })
139
- }
56
+ // Create client with any driver
57
+ const client = new SQLClient({ driver: pg })
140
58
  ```
141
59
 
142
60
  ## Custom Drivers
143
61
 
144
- Implement your own database driver:
62
+ You can easily create your own database drivers by implementing the `DatabaseDriver` interface:
145
63
 
146
64
  ```typescript
147
65
  import type { DatabaseDriver, QueryResult } from 'driftsql'
@@ -152,7 +70,7 @@ class MyCustomDriver implements DatabaseDriver {
152
70
  return {
153
71
  rows: [], // T[]
154
72
  rowCount: 0,
155
- command: 'SELECT'
73
+ command: 'SELECT',
156
74
  }
157
75
  }
158
76
 
@@ -165,108 +83,6 @@ class MyCustomDriver implements DatabaseDriver {
165
83
  const client = new SQLClient({ driver: new MyCustomDriver() })
166
84
  ```
167
85
 
168
- ## Driver-Specific Features
169
-
170
- ### PostgreSQL HTTP Support
171
-
172
- ```typescript
173
- const postgresDriver = new PostgresDriver({
174
- experimental: {
175
- http: {
176
- url: 'https://your-postgres-http-api.com',
177
- apiKey: 'your-api-key'
178
- }
179
- }
180
- })
181
- ```
182
-
183
- ### LibSQL with Turso Serverless
184
-
185
- ```typescript
186
- const libsqlDriver = new LibSQLDriver({
187
- url: 'libsql://your-database.turso.io',
188
- authToken: 'your-auth-token',
189
- useTursoServerlessDriver: true
190
- })
191
- ```
192
-
193
- ### SQLite with Prepared Statements
194
-
195
- ```typescript
196
- const sqliteDriver = new SqliteDriver({ filename: './db.sqlite' })
197
- const client = new SQLClient({ driver: sqliteDriver })
198
-
199
- if (client.supportsPreparedStatements()) {
200
- const stmt = await client.prepare('SELECT * FROM users WHERE id = ?')
201
- const result = await stmt.execute([1])
202
- await stmt.finalize()
203
- }
204
- ```
205
-
206
- ## Error Handling
207
-
208
- ```typescript
209
- import { DatabaseError, QueryError, ConnectionError } from 'driftsql'
210
-
211
- try {
212
- await client.query('SELECT * FROM users')
213
- } catch (error) {
214
- if (error instanceof QueryError) {
215
- console.log('Query failed:', error.message)
216
- console.log('Driver:', error.driverType)
217
- } else if (error instanceof ConnectionError) {
218
- console.log('Connection failed:', error.message)
219
- }
220
- }
221
- ```
222
-
223
- ## Fallback Drivers
224
-
225
- ```typescript
226
- // Use multiple drivers with automatic fallback
227
- const client = new SQLClient({
228
- driver: primaryDriver,
229
- fallbackDrivers: [backupDriver1, backupDriver2]
230
- })
231
-
232
- // Will try drivers in order until one succeeds
233
- const result = await client.query('SELECT 1')
234
- ```
235
-
236
- ## API Reference
237
-
238
- ### DatabaseDriver Interface
239
-
240
- ```typescript
241
- interface DatabaseDriver {
242
- query<T = any>(sql: string, params?: any[]): Promise<QueryResult<T>>
243
- close(): Promise<void>
244
- }
245
- ```
246
-
247
- ### SQLClient
248
-
249
- ```typescript
250
- class SQLClient<DT = any> {
251
- constructor(options: { driver: DatabaseDriver; fallbackDrivers?: DatabaseDriver[] })
252
-
253
- query<T = any>(sql: string, params?: any[]): Promise<QueryResult<T>>
254
- findFirst<K extends keyof DT>(table: K, where?: Partial<DT[K]>): Promise<DT[K] | null>
255
- findMany<K extends keyof DT>(table: K, options?: FindManyOptions<DT[K]>): Promise<DT[K][]>
256
- insert<K extends keyof DT>(table: K, data: Partial<DT[K]>): Promise<DT[K]>
257
- update<K extends keyof DT>(table: K, data: Partial<DT[K]>, where: Partial<DT[K]>): Promise<DT[K] | null>
258
- delete<K extends keyof DT>(table: K, where: Partial<DT[K]>): Promise<number>
259
-
260
- transaction<T>(callback: (client: SQLClient<DT>) => Promise<T>): Promise<T>
261
- prepare(sql: string): Promise<PreparedStatement>
262
-
263
- getDriver(): DatabaseDriver
264
- supportsTransactions(): boolean
265
- supportsPreparedStatements(): boolean
266
- close(): Promise<void>
267
- }
268
- ```
269
-
270
86
  ## License
271
87
 
272
- Published under the [MIT](https://github.com/lassejlv/driftsql/blob/main/LICENSE) license.
88
+ Published under the [MIT](https://github.com/lassejlv/driftsql/blob/main/LICENSE) license.
@@ -0,0 +1,19 @@
1
+ import { type DatabaseDriver, type QueryResult } from '../types';
2
+ export interface NeonDriverOptions {
3
+ connectionString: string;
4
+ }
5
+ export declare class NeonDriver implements DatabaseDriver {
6
+ private client;
7
+ constructor(options: NeonDriverOptions);
8
+ query<T = any>(sql: string, params?: any[]): Promise<QueryResult<T>>;
9
+ findFirst<T = any>(table: string, where?: Record<string, any>): Promise<QueryResult<T> | null>;
10
+ findMany<T = any>(table: string, options?: {
11
+ where?: Record<string, any>;
12
+ limit?: number;
13
+ offset?: number;
14
+ }): Promise<QueryResult<T>>;
15
+ insert<T = any>(table: string, data: Record<string, any>): Promise<QueryResult<T>>;
16
+ update<T = any>(table: string, data: Record<string, any>, where: Record<string, any>): Promise<QueryResult<T>>;
17
+ delete<T = any>(table: string, where: Record<string, any>): Promise<number>;
18
+ close(): Promise<void>;
19
+ }
package/dist/index.d.ts CHANGED
@@ -3,8 +3,8 @@ export type { DatabaseDriver, QueryResult, QueryError, QueryField, ConnectionErr
3
3
  export { PostgresDriver } from './drivers/postgres';
4
4
  export { LibSQLDriver } from './drivers/libsql';
5
5
  export { MySQLDriver } from './drivers/mysql';
6
- export { SqliteDriver } from './drivers/sqlite';
7
- export { inspectDB, inspectPostgres, inspectLibSQL, inspectMySQL, inspectSQLite } from './pull';
6
+ export { NeonDriver } from './drivers/neon';
7
+ export { inspectDB } from './pull';
8
8
  export interface ClientOptions<T extends DatabaseDriver = DatabaseDriver> {
9
9
  driver: T;
10
10
  fallbackDrivers?: DatabaseDriver[];
@@ -30,25 +30,4 @@ export declare class SQLClient<DT = any> {
30
30
  supportsPreparedStatements(): boolean;
31
31
  close(): Promise<void>;
32
32
  }
33
- export declare function createPostgresClient<DT = any>(config: {
34
- connectionString?: string;
35
- experimental?: {
36
- http?: {
37
- url: string;
38
- apiKey?: string;
39
- };
40
- };
41
- }): SQLClient<DT>;
42
- export declare function createLibSQLClient<DT = any>(config: {
43
- url: string;
44
- authToken?: string;
45
- useTursoServerlessDriver?: boolean;
46
- }): SQLClient<DT>;
47
- export declare function createMySQLClient<DT = any>(config: {
48
- connectionString: string;
49
- }): SQLClient<DT>;
50
- export declare function createSqliteClient<DT = any>(config: {
51
- filename: string;
52
- readonly?: boolean;
53
- }): SQLClient<DT>;
54
33
  export declare const DriftSQLClient: typeof SQLClient;
package/dist/index.js CHANGED
@@ -1,15 +1,15 @@
1
- import consola2 from"consola";function hasTransactionSupport(driver){return"transaction"in driver&&typeof driver.transaction==="function"}function hasPreparedStatementSupport(driver){return"prepare"in driver&&typeof driver.prepare==="function"}class DatabaseError extends Error{driverType;originalError;constructor(message,driverType,originalError){super(message);this.driverType=driverType;this.originalError=originalError;this.name="DatabaseError"}}class QueryError extends DatabaseError{constructor(driverType,sql,originalError){super(`Query failed: ${sql}`,driverType,originalError);this.name="QueryError"}}class ConnectionError extends DatabaseError{constructor(driverType,originalError){super(`Failed to connect to ${driverType}`,driverType,originalError);this.name="ConnectionError"}}import postgres from"postgres";import ky from"ky";class PostgresDriver{client;constructor(config){try{if(config.experimental?.http){this.client=new PostgresHTTPDriver(config.experimental.http)}else{this.client=postgres(config.connectionString||"")}}catch(error){throw new ConnectionError("postgres",error)}}async query(sql,params){try{if(this.client instanceof PostgresHTTPDriver){return await this.client.query(sql,params)}const result=await this.client.unsafe(sql,params||[]);return{rows:result,rowCount:Array.isArray(result)?result.length:0,command:undefined}}catch(error){throw new QueryError("postgres",sql,error)}}async transaction(callback){if(this.client instanceof PostgresHTTPDriver){throw new Error("Transactions not supported with HTTP driver")}const result=await this.client.begin(async(sql)=>{const transactionDriver=new PostgresDriver({connectionString:""});transactionDriver.client=sql;return await callback(transactionDriver)});return result}async findFirst(table,where){const whereEntries=Object.entries(where||{});let sql=`SELECT * FROM ${table}`;let params=[];if(whereEntries.length>0){const whereClause=whereEntries.map((_,index)=>`${whereEntries[index]?.[0]} = $${index+1}`).join(" AND ");sql+=` WHERE ${whereClause}`;params=whereEntries.map(([,value])=>value)}sql+=" LIMIT 1";const result=await this.query(sql,params);return result.rows.length>0?result:null}async findMany(table,options){if(this.client instanceof PostgresHTTPDriver){return await this.client.findMany(table,options)}const{where,limit,offset}=options||{};const whereEntries=Object.entries(where||{});let sql=`SELECT * FROM ${table}`;let params=[];if(whereEntries.length>0){const whereClause=whereEntries.map((_,index)=>`${whereEntries[index]?.[0]} = $${index+1}`).join(" AND ");sql+=` WHERE ${whereClause}`;params=whereEntries.map(([,value])=>value)}if(typeof limit==="number"&&limit>0){sql+=` LIMIT $${params.length+1}`;params.push(limit)}if(typeof offset==="number"&&offset>0){sql+=` OFFSET $${params.length+1}`;params.push(offset)}return this.query(sql,params)}async insert(table,data){const tableName=String(table);const keys=Object.keys(data);const values=Object.values(data);if(keys.length===0){throw new Error("No data provided for insert")}const placeholders=keys.map((_,index)=>`$${index+1}`).join(", ");const sql=`INSERT INTO ${tableName} (${keys.join(", ")}) VALUES (${placeholders}) RETURNING *`;const result=await this.query(sql,values);if(!result.rows[0]){throw new Error("Insert failed: No data returned")}return result}async update(table,data,where){const tableName=String(table);const setEntries=Object.entries(data);const whereEntries=Object.entries(where);if(setEntries.length===0){throw new Error("No data provided for update")}if(whereEntries.length===0){throw new Error("No conditions provided for update")}const setClause=setEntries.map((_,index)=>`${setEntries[index]?.[0]} = $${index+1}`).join(", ");const whereClause=whereEntries.map((_,index)=>`${whereEntries[index]?.[0]} = $${setEntries.length+index+1}`).join(" AND ");const sql=`UPDATE ${tableName} SET ${setClause} WHERE ${whereClause} RETURNING *`;const params=[...setEntries.map(([,value])=>value),...whereEntries.map(([,value])=>value)];const result=await this.query(sql,params);return result.rows.length>0?result:result}async delete(table,where){const tableName=String(table);const whereEntries=Object.entries(where);if(whereEntries.length===0){throw new Error("No conditions provided for delete")}const whereClause=whereEntries.map((_,index)=>`${whereEntries[index]?.[0]} = $${index+1}`).join(" AND ");const sql=`DELETE FROM ${tableName} WHERE ${whereClause}`;const params=whereEntries.map(([,value])=>value);const result=await this.query(sql,params);return result.rowCount}async close(){try{if(this.client instanceof PostgresHTTPDriver){return await this.client.close()}await this.client.end()}catch(error){console.error("Error closing Postgres client:",error)}}}class PostgresHTTPDriver{httpClient;constructor(config){this.httpClient=ky.create({prefixUrl:config.url,headers:{Authorization:`Bearer ${config.apiKey||""}`}})}async query(sql,params){try{const response=await this.httpClient.post("query",{json:{query:sql,args:params}}).json();return{rows:response.rows,rowCount:response.rowCount,command:undefined}}catch(error){throw new QueryError("postgres-http",sql,error)}}async findFirst(table,where){const whereEntries=Object.entries(where||{});let sql=`SELECT * FROM ${table}`;let params=[];if(whereEntries.length>0){const whereClause=whereEntries.map((_,index)=>`${whereEntries[index]?.[0]} = $${index+1}`).join(" AND ");sql+=` WHERE ${whereClause}`;params=whereEntries.map(([,value])=>value)}sql+=" LIMIT 1";const result=await this.query(sql,params);return result.rows.length>0?result:null}async findMany(table,options){const{where,limit,offset}=options||{};const whereEntries=Object.entries(where||{});let sql=`SELECT * FROM ${table}`;let params=[];if(whereEntries.length>0){const whereClause=whereEntries.map((_,index)=>`${whereEntries[index]?.[0]} = $${index+1}`).join(" AND ");sql+=` WHERE ${whereClause}`;params=whereEntries.map(([,value])=>value)}if(typeof limit==="number"&&limit>0){sql+=` LIMIT $${params.length+1}`;params.push(limit)}if(typeof offset==="number"&&offset>0){sql+=` OFFSET $${params.length+1}`;params.push(offset)}return this.query(sql,params)}async insert(table,data){const tableName=String(table);const keys=Object.keys(data);const values=Object.values(data);if(keys.length===0){throw new Error("No data provided for insert")}const placeholders=keys.map((_,index)=>`$${index+1}`).join(", ");const sql=`INSERT INTO ${tableName} (${keys.join(", ")}) VALUES (${placeholders}) RETURNING *`;const result=await this.query(sql,values);if(!result.rows[0]){throw new Error("Insert failed: No data returned")}return result}async update(table,data,where){const tableName=String(table);const setEntries=Object.entries(data);const whereEntries=Object.entries(where);if(setEntries.length===0){throw new Error("No data provided for update")}if(whereEntries.length===0){throw new Error("No conditions provided for update")}const setClause=setEntries.map((_,index)=>`${setEntries[index]?.[0]} = $${index+1}`).join(", ");const whereClause=whereEntries.map((_,index)=>`${whereEntries[index]?.[0]} = $${setEntries.length+index+1}`).join(" AND ");const sql=`UPDATE ${tableName} SET ${setClause} WHERE ${whereClause} RETURNING *`;const params=[...setEntries.map(([,value])=>value),...whereEntries.map(([,value])=>value)];const result=await this.query(sql,params);return result.rows.length>0?result:result}async delete(table,where){const tableName=String(table);const whereEntries=Object.entries(where);if(whereEntries.length===0){throw new Error("No conditions provided for delete")}const whereClause=whereEntries.map((_,index)=>`${whereEntries[index]?.[0]} = $${index+1}`).join(" AND ");const sql=`DELETE FROM ${tableName} WHERE ${whereClause}`;const params=whereEntries.map(([,value])=>value);const result=await this.query(sql,params);return result.rowCount}async close(){return Promise.resolve()}}import{createClient}from"@libsql/client";import{createClient as tursoServerLessClient}from"@tursodatabase/serverless/compat";class LibSQLDriver{client;constructor(config){try{this.client=config.useTursoServerlessDriver?tursoServerLessClient({url:config.url,...config.authToken?{authToken:config.authToken}:{}}):createClient({url:config.url,...config.authToken?{authToken:config.authToken}:{}})}catch(error){throw new ConnectionError("libsql",error)}}async query(sql,params){try{const result=await this.client.execute(sql,params);return this.convertLibsqlResult(result)}catch(error){throw new QueryError("libsql",sql,error)}}async transaction(callback){const transactionDriver=new LibSQLDriver({url:"",authToken:""});transactionDriver.client=this.client;return await callback(transactionDriver)}async findFirst(table,where){const whereEntries=Object.entries(where||{});let sql=`SELECT * FROM ${table}`;let params=[];if(whereEntries.length>0){const whereClause=whereEntries.map((_,index)=>`${whereEntries[index]?.[0]} = ?`).join(" AND ");sql+=` WHERE ${whereClause}`;params=whereEntries.map(([,value])=>value)}sql+=" LIMIT 1";const result=await this.query(sql,params);return result.rows.length>0?result:null}async findMany(table,options){const{where,limit,offset}=options||{};const whereEntries=Object.entries(where||{});let sql=`SELECT * FROM ${table}`;let params=[];if(whereEntries.length>0){const whereClause=whereEntries.map((_,index)=>`${whereEntries[index]?.[0]} = ?`).join(" AND ");sql+=` WHERE ${whereClause}`;params=whereEntries.map(([,value])=>value)}if(typeof limit==="number"&&limit>0){sql+=` LIMIT ?`;params.push(limit)}if(typeof offset==="number"&&offset>0){sql+=` OFFSET ?`;params.push(offset)}return this.query(sql,params)}async insert(table,data){const tableName=String(table);const keys=Object.keys(data);const values=Object.values(data);if(keys.length===0){throw new Error("No data provided for insert")}const placeholders=keys.map(()=>"?").join(", ");const sql=`INSERT INTO ${tableName} (${keys.join(", ")}) VALUES (${placeholders})`;try{const result=await this.client.execute(sql,values);if(result.lastInsertRowid){try{const selectSql=`SELECT * FROM ${tableName} WHERE rowid = ?`;const insertedRow=await this.query(selectSql,[result.lastInsertRowid]);return{rows:insertedRow.rows,rowCount:result.rowsAffected||0,command:undefined,fields:insertedRow.fields}}catch{return{rows:[],rowCount:result.rowsAffected||0,command:undefined,fields:[]}}}return{rows:[],rowCount:result.rowsAffected||0,command:undefined,fields:[]}}catch(error){throw new QueryError("libsql",sql,error)}}async update(table,data,where){const tableName=String(table);const setEntries=Object.entries(data);const whereEntries=Object.entries(where);if(setEntries.length===0){throw new Error("No data provided for update")}if(whereEntries.length===0){throw new Error("No conditions provided for update")}const setClause=setEntries.map(([key])=>`${key} = ?`).join(", ");const whereClause=whereEntries.map(([key])=>`${key} = ?`).join(" AND ");const sql=`UPDATE ${tableName} SET ${setClause} WHERE ${whereClause}`;const params=[...setEntries.map(([,value])=>value),...whereEntries.map(([,value])=>value)];try{const result=await this.client.execute(sql,params);const selectSql=`SELECT * FROM ${tableName} WHERE ${whereClause}`;const selectParams=whereEntries.map(([,value])=>value);const updatedRows=await this.query(selectSql,selectParams);return{rows:updatedRows.rows,rowCount:result.rowsAffected||0,command:undefined,fields:updatedRows.fields}}catch(error){throw new QueryError("libsql",sql,error)}}async delete(table,where){const tableName=String(table);const whereEntries=Object.entries(where);if(whereEntries.length===0){throw new Error("No conditions provided for delete")}const whereClause=whereEntries.map(([key])=>`${key} = ?`).join(" AND ");const sql=`DELETE FROM ${tableName} WHERE ${whereClause}`;const params=whereEntries.map(([,value])=>value);try{const result=await this.client.execute(sql,params);return result.rowsAffected||0}catch(error){throw new QueryError("libsql",sql,error)}}async close(){try{this.client.close()}catch(error){console.error("Error closing LibSQL client:",error)}}convertLibsqlResult(result){const rows=result.rows.map((row)=>{const obj={};result.columns.forEach((col,index)=>{obj[col]=row[index]});return obj});return{rows,rowCount:result.rowsAffected||rows.length,command:undefined,fields:result.columns.map((col)=>({name:col,dataTypeID:0}))}}}import consola from"consola";import*as mysql from"mysql2/promise";class MySQLDriver{client;constructor(config){consola.warn("MySQL client is experimental and may not be compatible with the helper functions, since they originally designed for PostgreSQL and libsql. But .query() method should work.");try{this.client=mysql.createConnection(config.connectionString)}catch(error){throw new ConnectionError("mysql",error)}}async query(sql,params){try{const[rows,fields]=await(await this.client).execute(sql,params||[]);const rowCount=Array.isArray(rows)?rows.length:0;const normalizedFields=fields.map((field)=>({name:field.name,dataTypeID:field.columnType}));return{rows,rowCount,command:undefined,fields:normalizedFields}}catch(error){throw new QueryError("mysql",sql,error)}}async transaction(callback){const connection=await this.client;try{await connection.beginTransaction();const transactionDriver=new MySQLDriver({connectionString:""});transactionDriver.client=Promise.resolve(connection);const result=await callback(transactionDriver);await connection.commit();return result}catch(error){await connection.rollback();throw error}}async findFirst(table,where){const whereEntries=Object.entries(where||{});let sql=`SELECT * FROM ${table}`;let params=[];if(whereEntries.length>0){const whereClause=whereEntries.map(([key])=>`${key} = ?`).join(" AND ");sql+=` WHERE ${whereClause}`;params=whereEntries.map(([,value])=>value)}sql+=" LIMIT 1";const result=await this.query(sql,params);return result.rows.length>0?result:null}async findMany(table,options){const{where,limit,offset}=options||{};const whereEntries=Object.entries(where||{});let sql=`SELECT * FROM ${table}`;let params=[];if(whereEntries.length>0){const whereClause=whereEntries.map(([key])=>`${key} = ?`).join(" AND ");sql+=` WHERE ${whereClause}`;params=whereEntries.map(([,value])=>value)}if(typeof limit==="number"&&limit>0){sql+=` LIMIT ?`;params.push(limit)}if(typeof offset==="number"&&offset>0){sql+=` OFFSET ?`;params.push(offset)}return this.query(sql,params)}async insert(table,data){const tableName=String(table);const keys=Object.keys(data);const values=Object.values(data);if(keys.length===0){throw new Error("No data provided for insert")}const placeholders=keys.map(()=>"?").join(", ");const sql=`INSERT INTO ${tableName} (${keys.join(", ")}) VALUES (${placeholders})`;try{const connection=await this.client;const[result]=await connection.execute(sql,values);const insertResult=result;if(insertResult.insertId){try{const selectSql=`SELECT * FROM ${tableName} WHERE id = ?`;const insertedRow=await this.query(selectSql,[insertResult.insertId]);return{rows:insertedRow.rows,rowCount:insertResult.affectedRows||0,command:undefined,fields:insertedRow.fields}}catch{return{rows:[],rowCount:insertResult.affectedRows||0,command:undefined,fields:[]}}}return{rows:[],rowCount:insertResult.affectedRows||0,command:undefined,fields:[]}}catch(error){throw new QueryError("mysql",sql,error)}}async update(table,data,where){const tableName=String(table);const setEntries=Object.entries(data);const whereEntries=Object.entries(where);if(setEntries.length===0){throw new Error("No data provided for update")}if(whereEntries.length===0){throw new Error("No conditions provided for update")}const setClause=setEntries.map(([key])=>`${key} = ?`).join(", ");const whereClause=whereEntries.map(([key])=>`${key} = ?`).join(" AND ");const sql=`UPDATE ${tableName} SET ${setClause} WHERE ${whereClause}`;const params=[...setEntries.map(([,value])=>value),...whereEntries.map(([,value])=>value)];try{const connection=await this.client;const[result]=await connection.execute(sql,params);const selectSql=`SELECT * FROM ${tableName} WHERE ${whereClause}`;const selectParams=whereEntries.map(([,value])=>value);const updatedRows=await this.query(selectSql,selectParams);const updateResult=result;return{rows:updatedRows.rows,rowCount:updateResult.affectedRows||0,command:undefined,fields:updatedRows.fields}}catch(error){throw new QueryError("mysql",sql,error)}}async delete(table,where){const tableName=String(table);const whereEntries=Object.entries(where);if(whereEntries.length===0){throw new Error("No conditions provided for delete")}const whereClause=whereEntries.map(([key])=>`${key} = ?`).join(" AND ");const sql=`DELETE FROM ${tableName} WHERE ${whereClause}`;const params=whereEntries.map(([,value])=>value);try{const connection=await this.client;const[result]=await connection.execute(sql,params);const deleteResult=result;return deleteResult.affectedRows||0}catch(error){throw new QueryError("mysql",sql,error)}}async close(){try{await(await this.client).end()}catch(error){consola.error("Error closing MySQL client:",error)}}}import Database from"better-sqlite3";class SqliteDriver{client;constructor(config){try{this.client=new Database(config.filename,{readonly:config.readonly||false,fileMustExist:config.readonly||false})}catch(error){throw new ConnectionError("sqlite",error)}}async query(sql,params){try{const stmt=this.client.prepare(sql);const rows=stmt.all(params||[]);const fields=rows.length>0&&typeof rows[0]==="object"&&rows[0]!==null?Object.keys(rows[0]).map((name)=>({name,dataTypeID:0})):[];return{rows,rowCount:rows.length,command:undefined,fields}}catch(error){throw new QueryError("sqlite",sql,error)}}async transaction(callback){const transaction=this.client.transaction(()=>{const transactionDriver=new SqliteDriver({filename:""});transactionDriver.client=this.client;return callback(transactionDriver)});return await transaction()}async prepare(sql){return new SqlitePreparedStatement(this.client.prepare(sql))}async findFirst(table,where){const whereEntries=Object.entries(where||{});let sql=`SELECT * FROM ${table}`;let params=[];if(whereEntries.length>0){const whereClause=whereEntries.map((_,index)=>`${whereEntries[index]?.[0]} = ?`).join(" AND ");sql+=` WHERE ${whereClause}`;params=whereEntries.map(([,value])=>value)}sql+=" LIMIT 1";const result=await this.query(sql,params);return result.rows.length>0?result:null}async findMany(table,options){const{where,limit,offset}=options||{};const whereEntries=Object.entries(where||{});let sql=`SELECT * FROM ${table}`;let params=[];if(whereEntries.length>0){const whereClause=whereEntries.map((_,index)=>`${whereEntries[index]?.[0]} = ?`).join(" AND ");sql+=` WHERE ${whereClause}`;params=whereEntries.map(([,value])=>value)}if(typeof limit==="number"&&limit>0){sql+=` LIMIT ?`;params.push(limit)}if(typeof offset==="number"&&offset>0){sql+=` OFFSET ?`;params.push(offset)}return this.query(sql,params)}async insert(table,data){const tableName=String(table);const keys=Object.keys(data);const values=Object.values(data);if(keys.length===0){throw new Error("No data provided for insert")}const placeholders=keys.map(()=>"?").join(", ");const sql=`INSERT INTO ${tableName} (${keys.join(", ")}) VALUES (${placeholders})`;try{const stmt=this.client.prepare(sql);const result=stmt.run(values);if(result.lastInsertRowid){const selectSql=`SELECT * FROM ${tableName} WHERE rowid = ?`;const insertedRow=await this.query(selectSql,[result.lastInsertRowid]);return{rows:insertedRow.rows,rowCount:result.changes,command:undefined,fields:insertedRow.fields}}return{rows:[],rowCount:result.changes,command:undefined,fields:[]}}catch(error){throw new QueryError("sqlite",sql,error)}}async update(table,data,where){const tableName=String(table);const setEntries=Object.entries(data);const whereEntries=Object.entries(where);if(setEntries.length===0){throw new Error("No data provided for update")}if(whereEntries.length===0){throw new Error("No conditions provided for update")}const setClause=setEntries.map(([key])=>`${key} = ?`).join(", ");const whereClause=whereEntries.map(([key])=>`${key} = ?`).join(" AND ");const sql=`UPDATE ${tableName} SET ${setClause} WHERE ${whereClause}`;const params=[...setEntries.map(([,value])=>value),...whereEntries.map(([,value])=>value)];try{const stmt=this.client.prepare(sql);const result=stmt.run(params);const selectSql=`SELECT * FROM ${tableName} WHERE ${whereClause}`;const selectParams=whereEntries.map(([,value])=>value);const updatedRows=await this.query(selectSql,selectParams);return{rows:updatedRows.rows,rowCount:result.changes,command:undefined,fields:updatedRows.fields}}catch(error){throw new QueryError("sqlite",sql,error)}}async delete(table,where){const tableName=String(table);const whereEntries=Object.entries(where);if(whereEntries.length===0){throw new Error("No conditions provided for delete")}const whereClause=whereEntries.map(([key])=>`${key} = ?`).join(" AND ");const sql=`DELETE FROM ${tableName} WHERE ${whereClause}`;const params=whereEntries.map(([,value])=>value);try{const stmt=this.client.prepare(sql);const result=stmt.run(params);return result.changes}catch(error){throw new QueryError("sqlite",sql,error)}}async close(){try{this.client.close()}catch(error){console.error("Error closing SQLite client:",error)}}exec(sql){this.client.exec(sql)}backup(filename){return new Promise((resolve,reject)=>{try{this.client.backup(filename);resolve()}catch(error){reject(error)}})}pragma(pragma){return this.client.pragma(pragma)}}class SqlitePreparedStatement{stmt;constructor(stmt){this.stmt=stmt}async execute(params){try{const rows=this.stmt.all(params||[]);const fields=rows.length>0&&typeof rows[0]==="object"&&rows[0]!==null?Object.keys(rows[0]).map((name)=>({name,dataTypeID:0})):[];return{rows,rowCount:rows.length,command:undefined,fields}}catch(error){throw new QueryError("sqlite","prepared statement",error)}}async finalize(){return Promise.resolve()}run(params){return this.stmt.run(params||[])}get(params){return this.stmt.get(params||[])}all(params){return this.stmt.all(params||[])}}import fs from"node:fs/promises";var withTimeout=(promise,timeoutMs=30000)=>{return Promise.race([promise,new Promise((_,reject)=>setTimeout(()=>reject(new Error(`Query timeout after ${timeoutMs}ms`)),timeoutMs))])};var retryQuery=async(queryFn,maxRetries=3,baseDelay=1000)=>{for(let attempt=1;attempt<=maxRetries;attempt++){try{return await queryFn()}catch(error){if(attempt===maxRetries){throw error}const delay=baseDelay*Math.pow(2,attempt-1);console.warn(`Query attempt ${attempt} failed, retrying in ${delay}ms...`,error);await new Promise((resolve)=>setTimeout(resolve,delay))}}throw new Error("Max retries exceeded")};var mapDatabaseTypeToTypeScript=(dataType,isNullable=false,driverType="postgres")=>{const nullable=isNullable?" | null":"";const lowerType=dataType.toLowerCase();switch(lowerType){case"uuid":{return`string${nullable}`}case"character varying":case"varchar":case"text":case"char":case"character":case"longtext":case"mediumtext":case"tinytext":{return`string${nullable}`}case"integer":case"int":case"int4":case"smallint":case"int2":case"bigint":case"int8":case"serial":case"bigserial":case"numeric":case"decimal":case"real":case"float4":case"double precision":case"float8":case"tinyint":case"mediumint":case"float":case"double":{return`number${nullable}`}case"boolean":case"bool":case"bit":{return`boolean${nullable}`}case"timestamp":case"timestamp with time zone":case"timestamp without time zone":case"timestamptz":case"date":case"time":case"time with time zone":case"time without time zone":case"timetz":case"interval":case"datetime":case"year":{return`Date${nullable}`}case"json":case"jsonb":{return`any${nullable}`}case"array":{return`any[]${nullable}`}case"bytea":case"binary":case"varbinary":case"blob":case"longblob":case"mediumblob":case"tinyblob":{return`Buffer${nullable}`}case"enum":case"set":{return`string${nullable}`}default:{console.warn(`Unknown ${driverType} type: ${dataType}, defaulting to 'any'`);return`any${nullable}`}}};var getDriverType=(driver)=>{if(driver instanceof PostgresDriver)return"postgres";if(driver instanceof LibSQLDriver)return"libsql";if(driver instanceof MySQLDriver)return"mysql";if(driver instanceof SqliteDriver)return"sqlite";return"unknown"};var inspectDB=async(options)=>{const{driver,outputFile="db-types.ts"}=options;const driverType=getDriverType(driver);console.log(`Inspecting database using ${driverType} driver`);const client=new SQLClient({driver});let generatedTypes="";try{let tablesQuery;let tableSchemaFilter;if(driverType==="mysql"){const dbResult=await withTimeout(retryQuery(()=>client.query("SELECT DATABASE() as `database`",[])),1e4);const currentDatabase=dbResult.rows[0]?.database;if(!currentDatabase){throw new Error("Could not determine current MySQL database name")}console.log(`Using MySQL database: ${currentDatabase}`);tablesQuery=`SELECT TABLE_NAME as table_name
1
+ import consola3 from"consola";function hasTransactionSupport(driver){return"transaction"in driver&&typeof driver.transaction==="function"}function hasPreparedStatementSupport(driver){return"prepare"in driver&&typeof driver.prepare==="function"}class DatabaseError extends Error{driverType;originalError;constructor(message,driverType,originalError){super(message);this.driverType=driverType;this.originalError=originalError;this.name="DatabaseError"}}class QueryError extends DatabaseError{constructor(driverType,sql,originalError){super(`Query failed: ${sql}`,driverType,originalError);this.name="QueryError"}}class ConnectionError extends DatabaseError{constructor(driverType,originalError){super(`Failed to connect to ${driverType}`,driverType,originalError);this.name="ConnectionError"}}import postgres from"postgres";import ky from"ky";class PostgresDriver{client;constructor(config){try{if(config.experimental?.http){this.client=new PostgresHTTPDriver(config.experimental.http)}else{this.client=postgres(config.connectionString||"")}}catch(error){throw new ConnectionError("postgres",error)}}async query(sql,params){try{if(this.client instanceof PostgresHTTPDriver){return await this.client.query(sql,params)}const result=await this.client.unsafe(sql,params||[]);return{rows:result,rowCount:Array.isArray(result)?result.length:0,command:undefined}}catch(error){throw new QueryError("postgres",sql,error)}}async transaction(callback){if(this.client instanceof PostgresHTTPDriver){throw new Error("Transactions not supported with HTTP driver")}const result=await this.client.begin(async(sql)=>{const transactionDriver=new PostgresDriver({connectionString:""});transactionDriver.client=sql;return await callback(transactionDriver)});return result}async findFirst(table,where){const whereEntries=Object.entries(where||{});let sql=`SELECT * FROM ${table}`;let params=[];if(whereEntries.length>0){const whereClause=whereEntries.map((_,index)=>`${whereEntries[index]?.[0]} = $${index+1}`).join(" AND ");sql+=` WHERE ${whereClause}`;params=whereEntries.map(([,value])=>value)}sql+=" LIMIT 1";const result=await this.query(sql,params);return result.rows.length>0?result:null}async findMany(table,options){if(this.client instanceof PostgresHTTPDriver){return await this.client.findMany(table,options)}const{where,limit,offset}=options||{};const whereEntries=Object.entries(where||{});let sql=`SELECT * FROM ${table}`;let params=[];if(whereEntries.length>0){const whereClause=whereEntries.map((_,index)=>`${whereEntries[index]?.[0]} = $${index+1}`).join(" AND ");sql+=` WHERE ${whereClause}`;params=whereEntries.map(([,value])=>value)}if(typeof limit==="number"&&limit>0){sql+=` LIMIT $${params.length+1}`;params.push(limit)}if(typeof offset==="number"&&offset>0){sql+=` OFFSET $${params.length+1}`;params.push(offset)}return this.query(sql,params)}async insert(table,data){const tableName=String(table);const keys=Object.keys(data);const values=Object.values(data);if(keys.length===0){throw new Error("No data provided for insert")}const placeholders=keys.map((_,index)=>`$${index+1}`).join(", ");const sql=`INSERT INTO ${tableName} (${keys.join(", ")}) VALUES (${placeholders}) RETURNING *`;const result=await this.query(sql,values);if(!result.rows[0]){throw new Error("Insert failed: No data returned")}return result}async update(table,data,where){const tableName=String(table);const setEntries=Object.entries(data);const whereEntries=Object.entries(where);if(setEntries.length===0){throw new Error("No data provided for update")}if(whereEntries.length===0){throw new Error("No conditions provided for update")}const setClause=setEntries.map((_,index)=>`${setEntries[index]?.[0]} = $${index+1}`).join(", ");const whereClause=whereEntries.map((_,index)=>`${whereEntries[index]?.[0]} = $${setEntries.length+index+1}`).join(" AND ");const sql=`UPDATE ${tableName} SET ${setClause} WHERE ${whereClause} RETURNING *`;const params=[...setEntries.map(([,value])=>value),...whereEntries.map(([,value])=>value)];const result=await this.query(sql,params);return result.rows.length>0?result:result}async delete(table,where){const tableName=String(table);const whereEntries=Object.entries(where);if(whereEntries.length===0){throw new Error("No conditions provided for delete")}const whereClause=whereEntries.map((_,index)=>`${whereEntries[index]?.[0]} = $${index+1}`).join(" AND ");const sql=`DELETE FROM ${tableName} WHERE ${whereClause}`;const params=whereEntries.map(([,value])=>value);const result=await this.query(sql,params);return result.rowCount}async close(){try{if(this.client instanceof PostgresHTTPDriver){return await this.client.close()}await this.client.end()}catch(error){console.error("Error closing Postgres client:",error)}}}class PostgresHTTPDriver{httpClient;constructor(config){this.httpClient=ky.create({prefixUrl:config.url,headers:{Authorization:`Bearer ${config.apiKey||""}`}})}async query(sql,params){try{const response=await this.httpClient.post("query",{json:{query:sql,args:params}}).json();return{rows:response.rows,rowCount:response.rowCount,command:undefined}}catch(error){throw new QueryError("postgres-http",sql,error)}}async findFirst(table,where){const whereEntries=Object.entries(where||{});let sql=`SELECT * FROM ${table}`;let params=[];if(whereEntries.length>0){const whereClause=whereEntries.map((_,index)=>`${whereEntries[index]?.[0]} = $${index+1}`).join(" AND ");sql+=` WHERE ${whereClause}`;params=whereEntries.map(([,value])=>value)}sql+=" LIMIT 1";const result=await this.query(sql,params);return result.rows.length>0?result:null}async findMany(table,options){const{where,limit,offset}=options||{};const whereEntries=Object.entries(where||{});let sql=`SELECT * FROM ${table}`;let params=[];if(whereEntries.length>0){const whereClause=whereEntries.map((_,index)=>`${whereEntries[index]?.[0]} = $${index+1}`).join(" AND ");sql+=` WHERE ${whereClause}`;params=whereEntries.map(([,value])=>value)}if(typeof limit==="number"&&limit>0){sql+=` LIMIT $${params.length+1}`;params.push(limit)}if(typeof offset==="number"&&offset>0){sql+=` OFFSET $${params.length+1}`;params.push(offset)}return this.query(sql,params)}async insert(table,data){const tableName=String(table);const keys=Object.keys(data);const values=Object.values(data);if(keys.length===0){throw new Error("No data provided for insert")}const placeholders=keys.map((_,index)=>`$${index+1}`).join(", ");const sql=`INSERT INTO ${tableName} (${keys.join(", ")}) VALUES (${placeholders}) RETURNING *`;const result=await this.query(sql,values);if(!result.rows[0]){throw new Error("Insert failed: No data returned")}return result}async update(table,data,where){const tableName=String(table);const setEntries=Object.entries(data);const whereEntries=Object.entries(where);if(setEntries.length===0){throw new Error("No data provided for update")}if(whereEntries.length===0){throw new Error("No conditions provided for update")}const setClause=setEntries.map((_,index)=>`${setEntries[index]?.[0]} = $${index+1}`).join(", ");const whereClause=whereEntries.map((_,index)=>`${whereEntries[index]?.[0]} = $${setEntries.length+index+1}`).join(" AND ");const sql=`UPDATE ${tableName} SET ${setClause} WHERE ${whereClause} RETURNING *`;const params=[...setEntries.map(([,value])=>value),...whereEntries.map(([,value])=>value)];const result=await this.query(sql,params);return result.rows.length>0?result:result}async delete(table,where){const tableName=String(table);const whereEntries=Object.entries(where);if(whereEntries.length===0){throw new Error("No conditions provided for delete")}const whereClause=whereEntries.map((_,index)=>`${whereEntries[index]?.[0]} = $${index+1}`).join(" AND ");const sql=`DELETE FROM ${tableName} WHERE ${whereClause}`;const params=whereEntries.map(([,value])=>value);const result=await this.query(sql,params);return result.rowCount}async close(){return Promise.resolve()}}import{createClient}from"@libsql/client";import{createClient as tursoServerLessClient}from"@tursodatabase/serverless/compat";class LibSQLDriver{client;constructor(config){try{this.client=config.useTursoServerlessDriver?tursoServerLessClient({url:config.url,...config.authToken?{authToken:config.authToken}:{}}):createClient({url:config.url,...config.authToken?{authToken:config.authToken}:{}})}catch(error){throw new ConnectionError("libsql",error)}}async query(sql,params){try{const result=await this.client.execute(sql,params);return this.convertLibsqlResult(result)}catch(error){throw new QueryError("libsql",sql,error)}}async transaction(callback){const transactionDriver=new LibSQLDriver({url:"",authToken:""});transactionDriver.client=this.client;return await callback(transactionDriver)}async findFirst(table,where){const whereEntries=Object.entries(where||{});let sql=`SELECT * FROM ${table}`;let params=[];if(whereEntries.length>0){const whereClause=whereEntries.map((_,index)=>`${whereEntries[index]?.[0]} = ?`).join(" AND ");sql+=` WHERE ${whereClause}`;params=whereEntries.map(([,value])=>value)}sql+=" LIMIT 1";const result=await this.query(sql,params);return result.rows.length>0?result:null}async findMany(table,options){const{where,limit,offset}=options||{};const whereEntries=Object.entries(where||{});let sql=`SELECT * FROM ${table}`;let params=[];if(whereEntries.length>0){const whereClause=whereEntries.map((_,index)=>`${whereEntries[index]?.[0]} = ?`).join(" AND ");sql+=` WHERE ${whereClause}`;params=whereEntries.map(([,value])=>value)}if(typeof limit==="number"&&limit>0){sql+=` LIMIT ?`;params.push(limit)}if(typeof offset==="number"&&offset>0){sql+=` OFFSET ?`;params.push(offset)}return this.query(sql,params)}async insert(table,data){const tableName=String(table);const keys=Object.keys(data);const values=Object.values(data);if(keys.length===0){throw new Error("No data provided for insert")}const placeholders=keys.map(()=>"?").join(", ");const sql=`INSERT INTO ${tableName} (${keys.join(", ")}) VALUES (${placeholders})`;try{const result=await this.client.execute(sql,values);if(result.lastInsertRowid){try{const selectSql=`SELECT * FROM ${tableName} WHERE rowid = ?`;const insertedRow=await this.query(selectSql,[result.lastInsertRowid]);return{rows:insertedRow.rows,rowCount:result.rowsAffected||0,command:undefined,fields:insertedRow.fields}}catch{return{rows:[],rowCount:result.rowsAffected||0,command:undefined,fields:[]}}}return{rows:[],rowCount:result.rowsAffected||0,command:undefined,fields:[]}}catch(error){throw new QueryError("libsql",sql,error)}}async update(table,data,where){const tableName=String(table);const setEntries=Object.entries(data);const whereEntries=Object.entries(where);if(setEntries.length===0){throw new Error("No data provided for update")}if(whereEntries.length===0){throw new Error("No conditions provided for update")}const setClause=setEntries.map(([key])=>`${key} = ?`).join(", ");const whereClause=whereEntries.map(([key])=>`${key} = ?`).join(" AND ");const sql=`UPDATE ${tableName} SET ${setClause} WHERE ${whereClause}`;const params=[...setEntries.map(([,value])=>value),...whereEntries.map(([,value])=>value)];try{const result=await this.client.execute(sql,params);const selectSql=`SELECT * FROM ${tableName} WHERE ${whereClause}`;const selectParams=whereEntries.map(([,value])=>value);const updatedRows=await this.query(selectSql,selectParams);return{rows:updatedRows.rows,rowCount:result.rowsAffected||0,command:undefined,fields:updatedRows.fields}}catch(error){throw new QueryError("libsql",sql,error)}}async delete(table,where){const tableName=String(table);const whereEntries=Object.entries(where);if(whereEntries.length===0){throw new Error("No conditions provided for delete")}const whereClause=whereEntries.map(([key])=>`${key} = ?`).join(" AND ");const sql=`DELETE FROM ${tableName} WHERE ${whereClause}`;const params=whereEntries.map(([,value])=>value);try{const result=await this.client.execute(sql,params);return result.rowsAffected||0}catch(error){throw new QueryError("libsql",sql,error)}}async close(){try{this.client.close()}catch(error){console.error("Error closing LibSQL client:",error)}}convertLibsqlResult(result){const rows=result.rows.map((row)=>{const obj={};result.columns.forEach((col,index)=>{obj[col]=row[index]});return obj});return{rows,rowCount:result.rowsAffected||rows.length,command:undefined,fields:result.columns.map((col)=>({name:col,dataTypeID:0}))}}}import consola from"consola";import*as mysql from"mysql2/promise";class MySQLDriver{client;constructor(config){try{this.client=mysql.createConnection(config.connectionString)}catch(error){throw new ConnectionError("mysql",error)}}async query(sql,params){try{const[rows,fields]=await(await this.client).execute(sql,params||[]);const rowCount=Array.isArray(rows)?rows.length:0;const normalizedFields=fields.map((field)=>({name:field.name,dataTypeID:field.columnType}));return{rows,rowCount,command:undefined,fields:normalizedFields}}catch(error){throw new QueryError("mysql",sql,error)}}async transaction(callback){const connection=await this.client;try{await connection.beginTransaction();const transactionDriver=new MySQLDriver({connectionString:""});transactionDriver.client=Promise.resolve(connection);const result=await callback(transactionDriver);await connection.commit();return result}catch(error){await connection.rollback();throw error}}async findFirst(table,where){const whereEntries=Object.entries(where||{});let sql=`SELECT * FROM ${table}`;let params=[];if(whereEntries.length>0){const whereClause=whereEntries.map(([key])=>`${key} = ?`).join(" AND ");sql+=` WHERE ${whereClause}`;params=whereEntries.map(([,value])=>value)}sql+=" LIMIT 1";const result=await this.query(sql,params);return result.rows.length>0?result:null}async findMany(table,options){const{where,limit,offset}=options||{};const whereEntries=Object.entries(where||{});let sql=`SELECT * FROM ${table}`;let params=[];if(whereEntries.length>0){const whereClause=whereEntries.map(([key])=>`${key} = ?`).join(" AND ");sql+=` WHERE ${whereClause}`;params=whereEntries.map(([,value])=>value)}if(typeof limit==="number"&&limit>0){sql+=` LIMIT ?`;params.push(limit)}if(typeof offset==="number"&&offset>0){sql+=` OFFSET ?`;params.push(offset)}return this.query(sql,params)}async insert(table,data){const tableName=String(table);const keys=Object.keys(data);const values=Object.values(data);if(keys.length===0){throw new Error("No data provided for insert")}const placeholders=keys.map(()=>"?").join(", ");const sql=`INSERT INTO ${tableName} (${keys.join(", ")}) VALUES (${placeholders})`;try{const connection=await this.client;const[result]=await connection.execute(sql,values);const insertResult=result;if(insertResult.insertId){try{const selectSql=`SELECT * FROM ${tableName} WHERE id = ?`;const insertedRow=await this.query(selectSql,[insertResult.insertId]);return{rows:insertedRow.rows,rowCount:insertResult.affectedRows||0,command:undefined,fields:insertedRow.fields}}catch{return{rows:[],rowCount:insertResult.affectedRows||0,command:undefined,fields:[]}}}return{rows:[],rowCount:insertResult.affectedRows||0,command:undefined,fields:[]}}catch(error){throw new QueryError("mysql",sql,error)}}async update(table,data,where){const tableName=String(table);const setEntries=Object.entries(data);const whereEntries=Object.entries(where);if(setEntries.length===0){throw new Error("No data provided for update")}if(whereEntries.length===0){throw new Error("No conditions provided for update")}const setClause=setEntries.map(([key])=>`${key} = ?`).join(", ");const whereClause=whereEntries.map(([key])=>`${key} = ?`).join(" AND ");const sql=`UPDATE ${tableName} SET ${setClause} WHERE ${whereClause}`;const params=[...setEntries.map(([,value])=>value),...whereEntries.map(([,value])=>value)];try{const connection=await this.client;const[result]=await connection.execute(sql,params);const selectSql=`SELECT * FROM ${tableName} WHERE ${whereClause}`;const selectParams=whereEntries.map(([,value])=>value);const updatedRows=await this.query(selectSql,selectParams);const updateResult=result;return{rows:updatedRows.rows,rowCount:updateResult.affectedRows||0,command:undefined,fields:updatedRows.fields}}catch(error){throw new QueryError("mysql",sql,error)}}async delete(table,where){const tableName=String(table);const whereEntries=Object.entries(where);if(whereEntries.length===0){throw new Error("No conditions provided for delete")}const whereClause=whereEntries.map(([key])=>`${key} = ?`).join(" AND ");const sql=`DELETE FROM ${tableName} WHERE ${whereClause}`;const params=whereEntries.map(([,value])=>value);try{const connection=await this.client;const[result]=await connection.execute(sql,params);const deleteResult=result;return deleteResult.affectedRows||0}catch(error){throw new QueryError("mysql",sql,error)}}async close(){try{await(await this.client).end()}catch(error){consola.error("Error closing MySQL client:",error)}}}import{neon}from"@neondatabase/serverless";class NeonDriver{client;constructor(options){this.client=neon(options.connectionString)}async query(sql,params){try{const resp=await this.client.query(sql,params);return{rows:resp,rowCount:resp.length||0}}catch(error){throw new QueryError("neon",`Failed to query database: ${error}`)}}async findFirst(table,where){const whereEntries=Object.entries(where||{});let sql=`SELECT * FROM ${table}`;let params=[];if(whereEntries.length>0){const whereClause=whereEntries.map((_,index)=>`${whereEntries[index]?.[0]} = $${index+1}`).join(" AND ");sql+=` WHERE ${whereClause}`;params=whereEntries.map(([,value])=>value)}sql+=" LIMIT 1";const result=await this.query(sql,params);return result.rows.length>0?result:null}async findMany(table,options){const{where,limit,offset}=options||{};const whereEntries=Object.entries(where||{});let sql=`SELECT * FROM ${table}`;let params=[];if(whereEntries.length>0){const whereClause=whereEntries.map((_,index)=>`${whereEntries[index]?.[0]} = $${index+1}`).join(" AND ");sql+=` WHERE ${whereClause}`;params=whereEntries.map(([,value])=>value)}if(typeof limit==="number"&&limit>0){sql+=` LIMIT $${params.length+1}`;params.push(limit)}if(typeof offset==="number"&&offset>0){sql+=` OFFSET $${params.length+1}`;params.push(offset)}return this.query(sql,params)}async insert(table,data){const tableName=String(table);const keys=Object.keys(data);const values=Object.values(data);if(keys.length===0){throw new Error("No data provided for insert")}const placeholders=keys.map((_,index)=>`$${index+1}`).join(", ");const sql=`INSERT INTO ${tableName} (${keys.join(", ")}) VALUES (${placeholders}) RETURNING *`;const result=await this.query(sql,values);if(!result.rows[0]){throw new Error("Insert failed: No data returned")}return result}async update(table,data,where){const tableName=String(table);const setEntries=Object.entries(data);const whereEntries=Object.entries(where);if(setEntries.length===0){throw new Error("No data provided for update")}if(whereEntries.length===0){throw new Error("No conditions provided for update")}const setClause=setEntries.map((_,index)=>`${setEntries[index]?.[0]} = $${index+1}`).join(", ");const whereClause=whereEntries.map((_,index)=>`${whereEntries[index]?.[0]} = $${setEntries.length+index+1}`).join(" AND ");const sql=`UPDATE ${tableName} SET ${setClause} WHERE ${whereClause} RETURNING *`;const params=[...setEntries.map(([,value])=>value),...whereEntries.map(([,value])=>value)];const result=await this.query(sql,params);return result.rows.length>0?result:result}async delete(table,where){const tableName=String(table);const whereEntries=Object.entries(where);if(whereEntries.length===0){throw new Error("No conditions provided for delete")}const whereClause=whereEntries.map((_,index)=>`${whereEntries[index]?.[0]} = $${index+1}`).join(" AND ");const sql=`DELETE FROM ${tableName} WHERE ${whereClause}`;const params=whereEntries.map(([,value])=>value);const result=await this.query(sql,params);return result.rowCount}close(){return Promise.resolve()}}import consola2 from"consola";import fs from"node:fs/promises";var withTimeout=(promise,timeoutMs=30000)=>{return Promise.race([promise,new Promise((_,reject)=>setTimeout(()=>reject(new Error(`Query timeout after ${timeoutMs}ms`)),timeoutMs))])};var retryQuery=async(queryFn,maxRetries=3,baseDelay=1000)=>{for(let attempt=1;attempt<=maxRetries;attempt++){try{return await queryFn()}catch(error){if(attempt===maxRetries){throw error}const delay=baseDelay*Math.pow(2,attempt-1);consola2.warn(`Query attempt ${attempt} failed, retrying in ${delay}ms...`,error);await new Promise((resolve)=>setTimeout(resolve,delay))}}throw new Error("Max retries exceeded")};var mapDatabaseTypeToTypeScript=(dataType,isNullable=false,driverType="postgres")=>{const nullable=isNullable?" | null":"";const lowerType=dataType.toLowerCase();switch(lowerType){case"uuid":{return`string${nullable}`}case"character varying":case"varchar":case"text":case"char":case"character":case"longtext":case"mediumtext":case"tinytext":{return`string${nullable}`}case"integer":case"int":case"int4":case"smallint":case"int2":case"bigint":case"int8":case"serial":case"bigserial":case"numeric":case"decimal":case"real":case"float4":case"double precision":case"float8":case"tinyint":case"mediumint":case"float":case"double":{return`number${nullable}`}case"boolean":case"bool":case"bit":{return`boolean${nullable}`}case"timestamp":case"timestamp with time zone":case"timestamp without time zone":case"timestamptz":case"date":case"time":case"time with time zone":case"time without time zone":case"timetz":case"interval":case"datetime":case"year":{return`Date${nullable}`}case"json":case"jsonb":{return`any${nullable}`}case"array":{return`any[]${nullable}`}case"bytea":case"binary":case"varbinary":case"blob":case"longblob":case"mediumblob":case"tinyblob":{return`Buffer${nullable}`}case"enum":case"set":{return`string${nullable}`}default:{consola2.warn(`Unknown ${driverType} type: ${dataType}, defaulting to 'any'`);return`any${nullable}`}}};var getDriverType=(driver)=>{if(driver instanceof PostgresDriver)return"postgres";if(driver instanceof LibSQLDriver)return"libsql";if(driver instanceof MySQLDriver)return"mysql";if(driver instanceof NeonDriver)return"neon";return"unknown"};var inspectDB=async(options)=>{const{driver,outputFile="db-types.ts"}=options;const driverType=getDriverType(driver);consola2.log(`Inspecting database using ${driverType} driver`);const client=new SQLClient({driver});let generatedTypes="";try{let tablesQuery;let tableSchemaFilter;if(driverType==="mysql"){const dbResult=await withTimeout(retryQuery(()=>client.query("SELECT DATABASE() as `database`",[])),1e4);const currentDatabase=dbResult.rows[0]?.database;if(!currentDatabase){throw new Error("Could not determine current MySQL database name")}consola2.log(`Using MySQL database: ${currentDatabase}`);tablesQuery=`SELECT TABLE_NAME as table_name
2
2
  FROM information_schema.tables
3
3
  WHERE TABLE_SCHEMA = ?
4
4
  AND TABLE_TYPE = 'BASE TABLE'
5
- ORDER BY TABLE_NAME`;tableSchemaFilter=currentDatabase}else if(driverType==="postgres"){tablesQuery=`SELECT table_name
5
+ ORDER BY TABLE_NAME`;tableSchemaFilter=currentDatabase}else if(driverType==="postgres"||driverType==="neon"){tablesQuery=`SELECT table_name
6
6
  FROM information_schema.tables
7
7
  WHERE table_schema = $1
8
8
  AND table_type = 'BASE TABLE'
9
9
  ORDER BY table_name`;tableSchemaFilter="public"}else if(driverType==="libsql"||driverType==="sqlite"){tablesQuery=`SELECT name as table_name
10
10
  FROM sqlite_master
11
11
  WHERE type = 'table'
12
- ORDER BY name`;tableSchemaFilter=undefined}else{throw new Error(`Unsupported driver type: ${driverType}`)}const tables=await withTimeout(retryQuery(()=>client.query(tablesQuery,tableSchemaFilter?[tableSchemaFilter]:[])),30000);console.log("Tables in the database:",tables.rows.map((t)=>t.table_name).join(", "));let processedTables=0;const totalTables=tables.rows.length;for(const table of tables.rows){const tableName=table.table_name;processedTables++;console.log(`[${processedTables}/${totalTables}] Inspecting table: ${tableName}`);try{let columnsQuery;let queryParams;if(driverType==="mysql"){columnsQuery=`
12
+ ORDER BY name`;tableSchemaFilter=undefined}else{throw new Error(`Unsupported driver type: ${driverType}`)}const tables=await withTimeout(retryQuery(()=>client.query(tablesQuery,tableSchemaFilter?[tableSchemaFilter]:[])),30000);consola2.log("Tables in the database:",tables.rows.map((t)=>t.table_name).join(", "));let processedTables=0;const totalTables=tables.rows.length;for(const table of tables.rows){const tableName=table.table_name;processedTables++;consola2.log(`[${processedTables}/${totalTables}] Inspecting table: ${tableName}`);try{let columnsQuery;let queryParams;if(driverType==="mysql"){columnsQuery=`
13
13
  SELECT
14
14
  COLUMN_NAME as column_name,
15
15
  DATA_TYPE as data_type,
@@ -19,7 +19,7 @@ import consola2 from"consola";function hasTransactionSupport(driver){return"tran
19
19
  WHERE TABLE_NAME = ?
20
20
  AND TABLE_SCHEMA = ?
21
21
  ORDER BY ORDINAL_POSITION
22
- `;queryParams=[tableName,tableSchemaFilter]}else if(driverType==="postgres"){columnsQuery=`
22
+ `;queryParams=[tableName,tableSchemaFilter]}else if(driverType==="postgres"||driverType==="neon"){columnsQuery=`
23
23
  SELECT
24
24
  column_name,
25
25
  data_type,
@@ -37,12 +37,12 @@ import consola2 from"consola";function hasTransactionSupport(driver){return"tran
37
37
  dflt_value as column_default
38
38
  FROM pragma_table_info(?)
39
39
  ORDER BY cid
40
- `;queryParams=[tableName]}const columns=await withTimeout(retryQuery(()=>client.query(columnsQuery,queryParams)),15000);if(columns.rows.length===0){console.log(`No columns found for table: ${tableName}`);continue}console.log(`Columns in ${tableName}:`,columns.rows.map((c)=>`${c.column_name} (${c.data_type}${c.is_nullable==="YES"?", nullable":""})`).join(", "));const uniqueColumns=new Map;columns.rows.forEach((col)=>{if(!uniqueColumns.has(col.column_name)){uniqueColumns.set(col.column_name,col)}});generatedTypes+=`export interface ${tableName.charAt(0).toUpperCase()+tableName.slice(1)} {
40
+ `;queryParams=[tableName]}const columns=await withTimeout(retryQuery(()=>client.query(columnsQuery,queryParams)),15000);if(columns.rows.length===0){consola2.log(`No columns found for table: ${tableName}`);continue}consola2.log(`Columns in ${tableName}:`,columns.rows.map((c)=>`${c.column_name} (${c.data_type}${c.is_nullable==="YES"?", nullable":""})`).join(", "));const uniqueColumns=new Map;columns.rows.forEach((col)=>{if(!uniqueColumns.has(col.column_name)){uniqueColumns.set(col.column_name,col)}});generatedTypes+=`export interface ${tableName.charAt(0).toUpperCase()+tableName.slice(1)} {
41
41
  `;for(const col of uniqueColumns.values()){const tsType=mapDatabaseTypeToTypeScript(col.data_type,col.is_nullable==="YES",driverType);generatedTypes+=` ${col.column_name}: ${tsType};
42
42
  `}generatedTypes+=`}
43
43
 
44
- `}catch(error){console.error(`Failed to process table ${tableName}:`,error);console.log(`Skipping table ${tableName} and continuing...`);continue}}generatedTypes+=`export interface Database {
44
+ `}catch(error){consola2.error(`Failed to process table ${tableName}:`,error);consola2.log(`Skipping table ${tableName} and continuing...`);continue}}generatedTypes+=`export interface Database {
45
45
  `;for(const table of tables.rows){const interfaceName=table.table_name.charAt(0).toUpperCase()+table.table_name.slice(1);generatedTypes+=` ${table.table_name}: ${interfaceName};
46
46
  `}generatedTypes+=`}
47
47
 
48
- `;await fs.writeFile(outputFile,generatedTypes,"utf8");console.log(`TypeScript types written to ${outputFile}`);console.log(`Successfully processed ${processedTables} tables`)}catch(error){console.error("Fatal error during database inspection:",error);throw error}finally{await client.close()}};var inspectPostgres=async(config,outputFile)=>{const driver=new PostgresDriver(config);return inspectDB({driver,outputFile})};var inspectLibSQL=async(config,outputFile)=>{const driver=new LibSQLDriver(config);return inspectDB({driver,outputFile})};var inspectMySQL=async(config,outputFile)=>{const driver=new MySQLDriver(config);return inspectDB({driver,outputFile})};var inspectSQLite=async(config,outputFile)=>{const driver=new SqliteDriver(config);return inspectDB({driver,outputFile})};class SQLClient{primaryDriver;fallbackDrivers;constructor(options){this.primaryDriver=options.driver;this.fallbackDrivers=options.fallbackDrivers||[]}async query(sql,params){const drivers=[this.primaryDriver,...this.fallbackDrivers];let lastError;for(const driver of drivers){try{return await driver.query(sql,params)}catch(error){lastError=error;consola2.warn(`Query failed with ${driver.constructor.name}:`,error);continue}}throw lastError||new DatabaseError("All drivers failed to execute query","unknown")}async transaction(callback){if(!hasTransactionSupport(this.primaryDriver)){throw new DatabaseError("Primary driver does not support transactions",this.primaryDriver.constructor.name)}return await this.primaryDriver.transaction(async(transactionDriver)=>{const transactionClient=new SQLClient({driver:transactionDriver,fallbackDrivers:[]});return await callback(transactionClient)})}async prepare(sql){if(!hasPreparedStatementSupport(this.primaryDriver)){throw new DatabaseError("Primary driver does not support prepared statements",this.primaryDriver.constructor.name)}return await this.primaryDriver.prepare(sql)}async findFirst(table,where){if(!this.primaryDriver.findFirst)throw new DatabaseError("Primary driver does not support findFirst",this.primaryDriver.constructor.name);try{const response=await this.primaryDriver.findFirst(table,where);return response.rows[0]||null}catch(error){throw new QueryError("findFirst",`Error finding first in ${String(table)}`,error)}}async findMany(table,options){if(!this.primaryDriver.findMany)throw new DatabaseError("Primary driver does not support findMany",this.primaryDriver.constructor.name);try{const response=await this.primaryDriver.findMany(table,options);return response.rows}catch(error){throw new QueryError("findMany",`Error finding many in ${String(table)}`,error)}}async insert(table,data){if(!this.primaryDriver.insert)throw new DatabaseError("Primary driver does not support insert",this.primaryDriver.constructor.name);try{const response=await this.primaryDriver.insert(table,data);return response.rows[0]}catch(error){throw new QueryError("insert",`Error inserting into ${String(table)}`,error)}}async update(table,data,where){if(!this.primaryDriver.update)throw new DatabaseError("Primary driver does not support update",this.primaryDriver.constructor.name);try{const response=await this.primaryDriver.update(table,data,where);return response.rows[0]||null}catch(error){throw new QueryError("update",`Error updating ${String(table)}`,error)}}async delete(table,where){if(!this.primaryDriver.delete)throw new DatabaseError("Primary driver does not support delete",this.primaryDriver.constructor.name);try{const affectedRows=await this.primaryDriver.delete(table,where);return affectedRows}catch(error){throw new QueryError("delete",`Error deleting from ${String(table)}`,error)}}getDriver(){return this.primaryDriver}supportsTransactions(){return hasTransactionSupport(this.primaryDriver)}supportsPreparedStatements(){return hasPreparedStatementSupport(this.primaryDriver)}async close(){const drivers=[this.primaryDriver,...this.fallbackDrivers];await Promise.all(drivers.map((driver)=>driver.close().catch((err)=>consola2.warn(`Error closing ${driver.constructor.name}:`,err))))}}function createPostgresClient(config){return new SQLClient({driver:new PostgresDriver(config)})}function createLibSQLClient(config){return new SQLClient({driver:new LibSQLDriver(config)})}function createMySQLClient(config){return new SQLClient({driver:new MySQLDriver(config)})}function createSqliteClient(config){return new SQLClient({driver:new SqliteDriver(config)})}var DriftSQLClient=SQLClient;export{inspectSQLite,inspectPostgres,inspectMySQL,inspectLibSQL,inspectDB,createSqliteClient,createPostgresClient,createMySQLClient,createLibSQLClient,SqliteDriver,SQLClient,PostgresDriver,MySQLDriver,LibSQLDriver,DriftSQLClient};
48
+ `;await fs.writeFile(outputFile,generatedTypes,"utf8");consola2.log(`TypeScript types written to ${outputFile}`);consola2.log(`Successfully processed ${processedTables} tables`)}catch(error){consola2.error("Fatal error during database inspection:",error);throw error}finally{await client.close()}};class SQLClient{primaryDriver;fallbackDrivers;constructor(options){this.primaryDriver=options.driver;this.fallbackDrivers=options.fallbackDrivers||[]}async query(sql,params){const drivers=[this.primaryDriver,...this.fallbackDrivers];let lastError;for(const driver of drivers){try{return await driver.query(sql,params)}catch(error){lastError=error;consola3.warn(`Query failed with ${driver.constructor.name}:`,error);continue}}throw lastError||new DatabaseError("All drivers failed to execute query","unknown")}async transaction(callback){if(!hasTransactionSupport(this.primaryDriver)){throw new DatabaseError("Primary driver does not support transactions",this.primaryDriver.constructor.name)}return await this.primaryDriver.transaction(async(transactionDriver)=>{const transactionClient=new SQLClient({driver:transactionDriver,fallbackDrivers:[]});return await callback(transactionClient)})}async prepare(sql){if(!hasPreparedStatementSupport(this.primaryDriver)){throw new DatabaseError("Primary driver does not support prepared statements",this.primaryDriver.constructor.name)}return await this.primaryDriver.prepare(sql)}async findFirst(table,where){if(!this.primaryDriver.findFirst)throw new DatabaseError("Primary driver does not support findFirst",this.primaryDriver.constructor.name);try{const response=await this.primaryDriver.findFirst(table,where);return response.rows[0]||null}catch(error){throw new QueryError("findFirst",`Error finding first in ${String(table)}`,error)}}async findMany(table,options){if(!this.primaryDriver.findMany)throw new DatabaseError("Primary driver does not support findMany",this.primaryDriver.constructor.name);try{const response=await this.primaryDriver.findMany(table,options);return response.rows}catch(error){throw new QueryError("findMany",`Error finding many in ${String(table)}`,error)}}async insert(table,data){if(!this.primaryDriver.insert)throw new DatabaseError("Primary driver does not support insert",this.primaryDriver.constructor.name);try{const response=await this.primaryDriver.insert(table,data);return response.rows[0]}catch(error){throw new QueryError("insert",`Error inserting into ${String(table)}`,error)}}async update(table,data,where){if(!this.primaryDriver.update)throw new DatabaseError("Primary driver does not support update",this.primaryDriver.constructor.name);try{const response=await this.primaryDriver.update(table,data,where);return response.rows[0]||null}catch(error){throw new QueryError("update",`Error updating ${String(table)}`,error)}}async delete(table,where){if(!this.primaryDriver.delete)throw new DatabaseError("Primary driver does not support delete",this.primaryDriver.constructor.name);try{const affectedRows=await this.primaryDriver.delete(table,where);return affectedRows}catch(error){throw new QueryError("delete",`Error deleting from ${String(table)}`,error)}}getDriver(){return this.primaryDriver}supportsTransactions(){return hasTransactionSupport(this.primaryDriver)}supportsPreparedStatements(){return hasPreparedStatementSupport(this.primaryDriver)}async close(){const drivers=[this.primaryDriver,...this.fallbackDrivers];await Promise.all(drivers.map((driver)=>driver.close().catch((err)=>consola3.warn(`Error closing ${driver.constructor.name}:`,err))))}}var DriftSQLClient=SQLClient;export{inspectDB,SQLClient,PostgresDriver,NeonDriver,MySQLDriver,LibSQLDriver,DriftSQLClient};
package/dist/pull.d.ts CHANGED
@@ -4,25 +4,4 @@ interface InspectOptions {
4
4
  outputFile?: string;
5
5
  }
6
6
  export declare const inspectDB: (options: InspectOptions) => Promise<void>;
7
- export declare const inspectPostgres: (config: {
8
- connectionString?: string;
9
- experimental?: {
10
- http?: {
11
- url: string;
12
- apiKey?: string;
13
- };
14
- };
15
- }, outputFile?: string) => Promise<void>;
16
- export declare const inspectLibSQL: (config: {
17
- url: string;
18
- authToken?: string;
19
- useTursoServerlessDriver?: boolean;
20
- }, outputFile?: string) => Promise<void>;
21
- export declare const inspectMySQL: (config: {
22
- connectionString: string;
23
- }, outputFile?: string) => Promise<void>;
24
- export declare const inspectSQLite: (config: {
25
- filename: string;
26
- readonly?: boolean;
27
- }, outputFile?: string) => Promise<void>;
28
7
  export default inspectDB;
package/package.json CHANGED
@@ -1,40 +1,32 @@
1
1
  {
2
2
  "name": "driftsql",
3
- "version": "1.0.21",
3
+ "version": "1.0.23",
4
4
  "main": "dist/index.js",
5
5
  "description": "A lightweight SQL client for TypeScript",
6
6
  "scripts": {
7
7
  "build": "bun build.ts"
8
8
  },
9
- "author": "lasse vestergaard",
9
+ "author": "Lasse Vestergaard",
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "lassejlv/driftsql"
13
+ },
10
14
  "license": "MIT",
11
15
  "dependencies": {
12
16
  "@libsql/client": "^0.15.9",
13
17
  "@neondatabase/serverless": "^1.0.1",
14
18
  "@sqlitecloud/drivers": "^1.0.507",
15
19
  "@tursodatabase/serverless": "^0.1.2",
16
- "@types/pg": "^8.15.4",
17
- "better-sqlite3": "^12.2.0",
18
20
  "consola": "^3.4.2",
19
21
  "driftsql": "^1.0.19",
20
- "drizzle-orm": "^0.44.2",
21
22
  "ky": "^1.8.1",
22
23
  "mysql2": "^3.14.1",
23
- "pg": "^8.16.3",
24
- "postgres": "^3.4.7"
24
+ "postgres": "^3.4.7",
25
+ "zod": "^4.0.17"
25
26
  },
26
27
  "devDependencies": {
27
- "@types/better-sqlite3": "^7.6.13",
28
28
  "@types/bun": "^1.2.20",
29
- "@types/node": "^22.15.34",
30
- "@vitest/coverage-v8": "^3.2.4",
31
- "automd": "^0.4.0",
32
- "changelogen": "^0.6.1",
33
- "eslint": "^9.30.0",
34
- "eslint-config-unjs": "^0.4.2",
35
29
  "prettier": "^3.6.2",
36
- "typescript": "^5.8.3",
37
- "unbuild": "^3.5.0",
38
- "vitest": "^3.2.4"
30
+ "typescript": "^5.8.3"
39
31
  }
40
32
  }