driftsql 1.0.31 → 1.0.32
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/dist/index.d.ts +2 -0
- package/dist/index.js +8 -2
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -7,6 +7,8 @@ export { NeonDriver } from './drivers/neon';
|
|
|
7
7
|
export { SqliteCloudDriver } from './drivers/sqlitecloud';
|
|
8
8
|
export { inspectDB } from './inspect';
|
|
9
9
|
export { SurrealDriver } from './drivers/surreal';
|
|
10
|
+
export { BunDriver } from './drivers/bun';
|
|
11
|
+
export { PoubelleDriver } from './drivers/poubelle/poubelle';
|
|
10
12
|
export interface ClientOptions<T extends DatabaseDriver = DatabaseDriver> {
|
|
11
13
|
driver: T;
|
|
12
14
|
fallbackDrivers?: DatabaseDriver[];
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import consola4 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{Database}from"@sqlitecloud/drivers";class SqliteCloudDriver{options;client;constructor(options){this.options=options;this.client=new Database(this.options.connectionString)}async query(sql,params){try{const result=await this.client.sql(sql,params);const rows=Array.isArray(result)?result.map((row)=>{const data={};for(const key in row){if(typeof row[key]!=="function"){data[key]=row[key]}}return data}):[];return{rows,rowCount:rows.length,command:undefined}}catch(error){throw new QueryError("sqlitecloud",sql,error)}}async prepare(sql){return 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 result=await this.query(sql,values);if(result.rows.length===0){const returningSql=`INSERT INTO ${tableName} (${keys.join(", ")}) VALUES (${placeholders}) RETURNING *`;return await this.query(returningSql,values)}return result}catch(error){throw new QueryError("sqlitecloud",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} RETURNING *`;const params=[...setEntries.map(([,value])=>value),...whereEntries.map(([,value])=>value)];try{const result=await this.query(sql,params);return result}catch(error){throw new QueryError("sqlitecloud",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.query(sql,params);return result.rowCount}catch(error){throw new QueryError("sqlitecloud",sql,error)}}async close(){this.client.close()}}import consola2 from"consola";import chalk from"chalk";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";if(driver instanceof SqliteCloudDriver)return"sqlitecloud";return`${driver.constructor.name||"unknown driver"}`};var inspectDB=async(options)=>{consola2.warn("inspectDB is experimental and may make mistakes when inspecting your database. However it will not destroy your database.");const{driver,outputFile="db-types.ts"}=options;const driverType=getDriverType(driver);consola2.start(`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.success(`Using MySQL database: ${currentDatabase}`);tablesQuery=`SELECT TABLE_NAME as table_name
|
|
1
|
+
// @bun
|
|
2
|
+
import consola6 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{Database}from"@sqlitecloud/drivers";class SqliteCloudDriver{options;client;constructor(options){this.options=options;this.client=new Database(this.options.connectionString)}async query(sql,params){try{const result=await this.client.sql(sql,params);const rows=Array.isArray(result)?result.map((row)=>{const data={};for(const key in row){if(typeof row[key]!=="function"){data[key]=row[key]}}return data}):[];return{rows,rowCount:rows.length,command:undefined}}catch(error){throw new QueryError("sqlitecloud",sql,error)}}async prepare(sql){return 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 result=await this.query(sql,values);if(result.rows.length===0){const returningSql=`INSERT INTO ${tableName} (${keys.join(", ")}) VALUES (${placeholders}) RETURNING *`;return await this.query(returningSql,values)}return result}catch(error){throw new QueryError("sqlitecloud",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} RETURNING *`;const params=[...setEntries.map(([,value])=>value),...whereEntries.map(([,value])=>value)];try{const result=await this.query(sql,params);return result}catch(error){throw new QueryError("sqlitecloud",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.query(sql,params);return result.rowCount}catch(error){throw new QueryError("sqlitecloud",sql,error)}}async close(){this.client.close()}}import consola2 from"consola";import chalk from"chalk";import fs from"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";if(driver instanceof SqliteCloudDriver)return"sqlitecloud";return`${driver.constructor.name||"unknown driver"}`};var inspectDB=async(options)=>{consola2.warn("inspectDB is experimental and may make mistakes when inspecting your database. However it will not destroy your database.");const{driver,outputFile="db-types.ts"}=options;const driverType=getDriverType(driver);consola2.start(`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.success(`Using MySQL database: ${currentDatabase}`);tablesQuery=`SELECT TABLE_NAME as table_name
|
|
2
3
|
FROM information_schema.tables
|
|
3
4
|
WHERE TABLE_SCHEMA = ?
|
|
4
5
|
AND TABLE_TYPE = 'BASE TABLE'
|
|
@@ -45,4 +46,9 @@ import consola4 from"consola";function hasTransactionSupport(driver){return"tran
|
|
|
45
46
|
`;for(const table of tables.rows){if(table.table_name.startsWith("sqlite_sequence")||table.table_name.startsWith("_prisma_migrations")){continue}const interfaceName=table.table_name.charAt(0).toUpperCase()+table.table_name.slice(1);generatedTypes+=` ${table.table_name}: ${interfaceName};
|
|
46
47
|
`}generatedTypes+=`}
|
|
47
48
|
|
|
48
|
-
`;await fs.writeFile(outputFile,generatedTypes,"utf8");consola2.success(`TypeScript types written to ${outputFile}`);consola2.success(`Successfully processed ${processedTables} tables`)}catch(error){consola2.error("Fatal error during database inspection:",error);throw error}finally{await client.close().catch((error)=>consola2.error("Error closing client:",error))}};import Surreal from"surrealdb";import consola3 from"consola";class SurrealDriver{client;constructor(config){consola3.warn("SurrealDriver is very experimental and not all functions from the sdk are supported. It is only used for testing purposes.");this.client=new Surreal;this.client.connect(config.url,{namespace:config.namespace,database:config.database,auth:config.auth})}async query(sql,params){try{if(params)throw new QueryError("surreal",sql,new Error("SurrealDB does need params"));const dbResult=await this.client.query(sql);return{rows:dbResult,rowCount:dbResult.length}}catch(error){throw new QueryError("surreal",sql,error)}}async close(){await this.client.close()}}class
|
|
49
|
+
`;await fs.writeFile(outputFile,generatedTypes,"utf8");consola2.success(`TypeScript types written to ${outputFile}`);consola2.success(`Successfully processed ${processedTables} tables`)}catch(error){consola2.error("Fatal error during database inspection:",error);throw error}finally{await client.close().catch((error)=>consola2.error("Error closing client:",error))}};import Surreal from"surrealdb";import consola3 from"consola";class SurrealDriver{client;constructor(config){consola3.warn("SurrealDriver is very experimental and not all functions from the sdk are supported. It is only used for testing purposes.");this.client=new Surreal;this.client.connect(config.url,{namespace:config.namespace,database:config.database,auth:config.auth})}async query(sql,params){try{if(params)throw new QueryError("surreal",sql,new Error("SurrealDB does need params"));const dbResult=await this.client.query(sql);return{rows:dbResult,rowCount:dbResult.length}}catch(error){throw new QueryError("surreal",sql,error)}}async close(){await this.client.close()}}var{SQL}=globalThis.Bun;import consola4 from"consola";class BunDriver{client;adapter;constructor(config){if(!Bun){throw new Error("BunDriver is only supported in Bun runtime")}consola4.warn("BunDriver only supports helper functions for PostgreSQL for now. But you can still use the query method.");this.adapter=config.adapter;this.client=new SQL({url:config.connectionString,adapter:config.adapter==="postgres"?"postgres":config.adapter==="mysql"?"mysql":config.adapter==="mariadb"?"mariadb":"sqlite"})}async query(sql,params){try{const response=await this.client.unsafe(sql,params);return{rows:response,rowCount:response.length}}catch(error){throw new QueryError("bun",sql,error)}}async findFirst(table,where){if(this.adapter!=="postgres"){throw new Error("Helper functions are only supported for PostgreSQL adapter")}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.adapter!=="postgres"){throw new Error("Helper functions are only supported for PostgreSQL adapter")}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){if(this.adapter!=="postgres"){throw new Error("Helper functions are only supported for PostgreSQL adapter")}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){if(this.adapter!=="postgres"){throw new Error("Helper functions are only supported for PostgreSQL adapter")}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){if(this.adapter!=="postgres"){throw new Error("Helper functions are only supported for PostgreSQL adapter")}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(){await this.client.close()}}import consola5 from"consola";var{connect}=globalThis.Bun;function parseRows(result){const rows=[];const lines=result.split(`
|
|
50
|
+
`).filter((l)=>l.trim());for(const line of lines){const cleaned=line.replace(/^{|}$/g,"");const pairs=cleaned.split(", ");const row={};for(const pair of pairs){const[key,value]=pair.split(": ");if(key&&value){const cleanKey=key.replace(/"/g,"");const cleanValue=value.replace(/"/g,"");if(cleanValue==="Null"){row[cleanKey]=null}else if(cleanValue.startsWith("Int(")){row[cleanKey]=parseInt(cleanValue.slice(4,-1))}else if(cleanValue.startsWith("Text(")){row[cleanKey]=cleanValue.slice(5,-1)}else{row[cleanKey]=cleanValue}}}if(Object.keys(row).length>0){rows.push(row)}}return rows}class PoubelleClient{socket=null;config;connected=false;buffer="";constructor(connectionString){this.config=this.parseConnectionString(connectionString)}parseConnectionString(connStr){const urlPattern=/^poubelle:\/\/([^:]+):([^@]+)@([^:]+):(\d+)$/;const match=connStr.match(urlPattern);if(!match){throw new Error("Invalid connection string format. Expected: poubelle://username:password@host:port")}const[,username,password,host,port]=match;return{username,password,host,port:parseInt(port,10)}}async connect(){this.socket=await connect({hostname:this.config.host,port:this.config.port,socket:{data:(socket,data)=>{const text=Buffer.from(data).toString();this.buffer+=text},error:(socket,error)=>{console.error("Socket error:",error)}}});await this.waitForPrompt("Username: ");await this.send(`${this.config.username}
|
|
51
|
+
`);await this.waitForPrompt("Password: ");await this.send(`${this.config.password}
|
|
52
|
+
`);await this.waitForPrompt("Connected to Poubelle DB");this.connected=true}async query(sql){if(!this.connected||!this.socket){throw new Error("Not connected")}await this.waitForPrompt("poubelle> ");this.buffer="";await this.send(`${sql}
|
|
53
|
+
`);await new Promise((resolve)=>setTimeout(resolve,100));const result=this.buffer.split("poubelle> ")[0].trim();return parseRows(result)}async createTable(name,columns){const cols=Object.entries(columns).map(([name2,type])=>`${name2} ${type}`).join(", ");await this.query(`CREATE TABLE ${name} (${cols})`)}async insert(table,data){const columns=Object.keys(data).join(", ");const values=Object.values(data).map((v)=>{if(v===null)return"NULL";if(typeof v==="string")return`'${v}'`;return v}).join(", ");await this.query(`INSERT INTO ${table} (${columns}) VALUES (${values})`)}async select(table,columns=["*"]){const cols=columns.join(", ");return await this.query(`SELECT ${cols} FROM ${table}`)}async close(){if(this.socket){await this.send(`exit
|
|
54
|
+
`);this.socket.end();this.socket=null;this.connected=false}}async send(data){if(!this.socket)throw new Error("Socket not connected");this.socket.write(data)}async waitForPrompt(prompt,timeout=5000){const start=Date.now();while(!this.buffer.includes(prompt)){if(Date.now()-start>timeout){throw new Error(`Timeout waiting for prompt: ${prompt}`)}await new Promise((resolve)=>setTimeout(resolve,10))}}}var client_default=PoubelleClient;class PoubelleDriver{client;constructor(config){if(!Bun){throw new Error("PoubelleDriver is only supported in Bun runtime")}consola5.warn("PoubelleDriver is experimental, please use with caution");this.client=new client_default(config.connectionString)}async query(sql,params){try{if(params)throw new Error("PoubelleDriver does not support params");const result=await this.client.query(sql);return{rows:result,rowCount:0}}catch(error){throw new QueryError("poubelle",sql,error)}}async close(){await this.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;consola6.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)=>consola6.warn(`Error closing ${driver.constructor.name}:`,err))))}}var DriftSQLClient=SQLClient;export{inspectDB,SurrealDriver,SqliteCloudDriver,SQLClient,PoubelleDriver,PostgresDriver,NeonDriver,MySQLDriver,LibSQLDriver,DriftSQLClient,BunDriver};
|