Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
83 commits
Select commit Hold shift + click to select a range
5a1f894
refactor: Fix Bun.SQL options parsing to separate adapter detection a…
Aug 29, 2025
666aea0
fix: Correct MYSQL_URL protocol detection in adapter inference
Aug 29, 2025
6f75091
test: Add comprehensive MySQL port defaulting tests
Aug 29, 2025
669e022
fix: Infer adapter from environment variable names when protocol is m…
Aug 29, 2025
7dba454
refactor: Simplify adapter inference to prioritize environment variab…
Aug 29, 2025
c19c865
[autofix.ci] apply automated fixes
autofix-ci[bot] Aug 29, 2025
0906de4
feat: Add comprehensive MySQL environment variable support
Aug 29, 2025
bb89714
[autofix.ci] apply automated fixes
autofix-ci[bot] Aug 29, 2025
952300f
test: Add SSL mode verification for TLS environment variable tests
Aug 29, 2025
5128275
feat: Add comprehensive adapter-protocol validation with conflict det…
Aug 29, 2025
cdeefff
Complete SQL options parsing refactor
Aug 29, 2025
0bc8e6b
Fix SQL options precedence: explicit options override URL parameters
Aug 29, 2025
251268f
[autofix.ci] apply automated fixes
autofix-ci[bot] Aug 29, 2025
79996d1
fix linter
cirospaciari Aug 29, 2025
f0174a7
fix parseurlForAdapter
cirospaciari Aug 30, 2025
0009922
fix coderabbit issues
cirospaciari Aug 30, 2025
d4a15c4
fix error
cirospaciari Aug 30, 2025
f456566
fix more
cirospaciari Aug 30, 2025
98399e1
dont discard tls
cirospaciari Aug 30, 2025
a98c72e
revert shared for now
alii Aug 30, 2025
c99dfab
fix: redo connection parsing logic
alii Sep 2, 2025
562732d
normalize url protocol for parsing
alii Sep 2, 2025
b6a923f
missing TLS_MYSQL_DATABASE_URL when no adapter is specified in options
alii Sep 2, 2025
50b3b6e
enhance connection details parsing to include adapter detection and i…
alii Sep 2, 2025
ab3d771
refactor getConnectionDetailsFromEnvironment to streamline adapter de…
alii Sep 2, 2025
747576d
fix tests
alii Sep 2, 2025
a02583c
get more tests to pass
alii Sep 2, 2025
72fd476
cleanup
alii Sep 3, 2025
40b41c2
enhance SQL connection handling by introducing OptionsWithDefinedAdap…
alii Sep 3, 2025
1e7a3a7
fix: all tests passing
alii Sep 3, 2025
9203d57
refactor parseConnectionDetailsFromOptionsOrEnvironment to improve SQ…
alii Sep 3, 2025
75f139e
expect :memory: for blank path
alii Sep 3, 2025
a4a58ed
significant cleanup work
alii Sep 3, 2025
5d90887
satisfy typescript
alii Sep 3, 2025
5cb76d4
tidier
alii Sep 3, 2025
cf3f0c7
mariadb should have its own case
alii Sep 3, 2025
32943dd
default to sslMode.disable
alii Sep 3, 2025
9c5bd46
undo meaningless changes
alii Sep 3, 2025
ed8ce4f
test should have a timeout
alii Sep 3, 2025
8289b1b
this should not have been reverted
alii Sep 3, 2025
b8ec02e
tests are passing but could do with a cleanup
alii Sep 3, 2025
36fc3dc
[autofix.ci] apply automated fixes
autofix-ci[bot] Sep 3, 2025
d9522d2
refactor SQLite URL handling and connection options parsing for clari…
alii Sep 3, 2025
a2fc0d5
Merge branch 'ali/fix-sql-connection-string-parsing' of github.com:ov…
alii Sep 3, 2025
6fae93d
change
alii Sep 3, 2025
ba96b16
smaller
alii Sep 3, 2025
3052718
tidier
alii Sep 3, 2025
421a6b8
make sqlite special case easier to understand
alii Sep 3, 2025
f756a3e
fix connection string parsing url when adapter is not sqlite, but a n…
alii Sep 3, 2025
5d66a20
skip unix socket tests on windows
alii Sep 3, 2025
c2180b7
Empty filename should default to :memory:
alii Sep 3, 2025
3d9de4d
mariadb case
alii Sep 3, 2025
bfe6166
[autofix.ci] apply automated fixes
autofix-ci[bot] Sep 3, 2025
0588916
Revert launch.json
alii Sep 3, 2025
5d92536
fix: Make passing tests actually pass with better env resetting
alii Sep 3, 2025
6ac21ca
make sql errors much less noisy (omit undefined properties by default)
alii Sep 3, 2025
c6e735c
fix: Satisfy oxlint declaration merging
alii Sep 3, 2025
36fa997
Merge branch 'main' into ali/fix-sql-connection-string-parsing
alii Sep 3, 2025
6b149c4
fallback tls value
alii Sep 3, 2025
520a9b5
use `await using` in a test
alii Sep 3, 2025
2d1817d
try ci
alii Sep 4, 2025
677eefe
revert tls changes and try ci
alii Sep 4, 2025
6cd8d93
see if changes are related
alii Sep 4, 2025
e382508
debug
alii Sep 4, 2025
b04a3f9
dont listen on mysql.sock in precedence test
alii Sep 4, 2025
e0714d9
Fix Unix domain socket cleanup on listener.stop()
Sep 4, 2025
382f687
fix: should work with unix requires the path to exist
alii Sep 4, 2025
884f2f3
Merge branch 'main' into ali/fix-sql-connection-string-parsing
alii Sep 5, 2025
4a52927
[autofix.ci] apply automated fixes
autofix-ci[bot] Sep 5, 2025
e292748
fix: deprecate .ssl in the options since it's an alias of tls
alii Sep 5, 2025
d03b861
update docs & dont use regex for checking protocol
alii Sep 6, 2025
ba1e261
Merge branch 'main' into ali/fix-sql-connection-string-parsing
alii Sep 6, 2025
4ca6dcc
Merge branch 'main' into ali/fix-sql-connection-string-parsing
alii Sep 6, 2025
6ed13e9
ci: try run this on windows
alii Sep 6, 2025
4372d30
cleanup test
alii Sep 6, 2025
cefe202
remove Bun.listen changes for now
alii Sep 6, 2025
c3129d3
Merge branch 'main' into ali/fix-sql-connection-string-parsing
alii Sep 6, 2025
32a6a90
changes + unlink
alii Sep 6, 2025
34648f2
small cleaning in harness
alii Sep 8, 2025
ff91fc1
Merge branch 'main' into ali/fix-sql-connection-string-parsing
alii Sep 8, 2025
db15759
changes to types
alii Sep 8, 2025
c691df7
skip tls-sql.test.ts when no connection string secrets locally
alii Sep 8, 2025
2c85900
Merge branch 'main' into ali/fix-sql-connection-string-parsing
alii Sep 9, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 6 additions & 7 deletions docs/api/sql.md
Original file line number Diff line number Diff line change
Expand Up @@ -604,13 +604,12 @@ const db = new SQL({
connectionTimeout: 30, // Timeout when establishing new connections

// SSL/TLS options
ssl: "prefer", // or "disable", "require", "verify-ca", "verify-full"
// tls: {
// rejectUnauthorized: true,
// ca: "path/to/ca.pem",
// key: "path/to/key.pem",
// cert: "path/to/cert.pem",
// },
tls: {
rejectUnauthorized: true,
ca: "path/to/ca.pem",
key: "path/to/key.pem",
cert: "path/to/cert.pem",
},

// Callbacks
onconnect: client => {
Expand Down
45 changes: 23 additions & 22 deletions packages/bun-types/sql.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,22 +41,22 @@ declare module "bun" {

class PostgresError extends SQLError {
public readonly code: string;
public readonly errno: string | undefined;
public readonly detail: string | undefined;
public readonly hint: string | undefined;
public readonly severity: string | undefined;
public readonly position: string | undefined;
public readonly internalPosition: string | undefined;
public readonly internalQuery: string | undefined;
public readonly where: string | undefined;
public readonly schema: string | undefined;
public readonly table: string | undefined;
public readonly column: string | undefined;
public readonly dataType: string | undefined;
public readonly constraint: string | undefined;
public readonly file: string | undefined;
public readonly line: string | undefined;
public readonly routine: string | undefined;
public readonly errno?: string | undefined;
public readonly detail?: string | undefined;
public readonly hint?: string | undefined;
public readonly severity?: string | undefined;
public readonly position?: string | undefined;
public readonly internalPosition?: string | undefined;
public readonly internalQuery?: string | undefined;
public readonly where?: string | undefined;
public readonly schema?: string | undefined;
public readonly table?: string | undefined;
public readonly column?: string | undefined;
public readonly dataType?: string | undefined;
public readonly constraint?: string | undefined;
public readonly file?: string | undefined;
public readonly line?: string | undefined;
public readonly routine?: string | undefined;

constructor(
message: string,
Expand Down Expand Up @@ -84,8 +84,8 @@ declare module "bun" {

class MySQLError extends SQLError {
public readonly code: string;
public readonly errno: number | undefined;
public readonly sqlState: string | undefined;
public readonly errno?: number | undefined;
public readonly sqlState?: string | undefined;
constructor(message: string, options: { code: string; errno: number | undefined; sqlState: string | undefined });
}
Comment thread
alii marked this conversation as resolved.

Expand Down Expand Up @@ -143,13 +143,13 @@ declare module "bun" {

/**
* Database server hostname
* @deprecated Prefer {@link hostname}
* @default "localhost"
*/
host?: string | undefined;

/**
* Database server hostname (alias for host)
* @deprecated Prefer {@link host}
* Database server hostname
* @default "localhost"
*/
hostname?: string | undefined;
Expand Down Expand Up @@ -264,13 +264,14 @@ declare module "bun" {
* Whether to use TLS/SSL for the connection
* @default false
*/
tls?: TLSOptions | boolean | undefined;
tls?: Bun.BunFile | TLSOptions | boolean | undefined;

/**
* Whether to use TLS/SSL for the connection (alias for tls)
* @deprecated Prefer {@link tls}
* @default false
*/
ssl?: TLSOptions | boolean | undefined;
ssl?: Bun.BunFile | TLSOptions | boolean | undefined;

/**
* Unix domain socket path for connection
Expand Down
1 change: 1 addition & 0 deletions src/bun.js/api/bun/socket/Listener.zig
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,7 @@ pub fn stop(this: *Listener, _: *jsc.JSGlobalObject, callframe: *jsc.CallFrame)
fn doStop(this: *Listener, force_close: bool) void {
if (this.listener == .none) return;
const listener = this.listener;

defer switch (listener) {
.uws => |socket| socket.close(this.ssl),
.namedPipe => |namedPipe| if (Environment.isWindows) namedPipe.closePipeAndDeinit(),
Expand Down
1 change: 1 addition & 0 deletions src/js/bun/sql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ function adapterFromOptions(options: Bun.SQL.__internal.DefinedOptions) {
case "postgres":
return new PostgresAdapter(options);
case "mysql":
case "mariadb":
return new MySQLAdapter(options);
case "sqlite":
return new SQLiteAdapter(options);
Expand Down
62 changes: 38 additions & 24 deletions src/js/internal/sql/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,26 @@ class SQLError extends Error implements Bun.SQL.SQLError {

export interface PostgresErrorOptions {
code: string;
detail?: string | undefined;
hint?: string | undefined;
severity?: string | undefined;
errno?: string | undefined;
position?: string | undefined;
internalPosition?: string | undefined;
internalQuery?: string | undefined;
where?: string | undefined;
schema?: string | undefined;
table?: string | undefined;
column?: string | undefined;
dataType?: string | undefined;
constraint?: string | undefined;
file?: string | undefined;
line?: string | undefined;
routine?: string | undefined;
}

// oxlint-disable-next-line typescript-eslint(no-unsafe-declaration-merging)
interface PostgresError {
detail?: string | undefined;
hint?: string | undefined;
severity?: string | undefined;
Expand All @@ -28,33 +47,17 @@ export interface PostgresErrorOptions {

class PostgresError extends SQLError implements Bun.SQL.PostgresError {
public readonly code: string;
public readonly detail: string | undefined;
public readonly hint: string | undefined;
public readonly severity: string | undefined;
public readonly errno: string | undefined;
public readonly position: string | undefined;
public readonly internalPosition: string | undefined;
public readonly internalQuery: string | undefined;
public readonly where: string | undefined;
public readonly schema: string | undefined;
public readonly table: string | undefined;
public readonly column: string | undefined;
public readonly dataType: string | undefined;
public readonly constraint: string | undefined;
public readonly file: string | undefined;
public readonly line: string | undefined;
public readonly routine: string | undefined;

constructor(message: string, options: PostgresErrorOptions) {
super(message);

this.name = "PostgresError";
this.code = options.code;

if (options.errno !== undefined) this.errno = options.errno;
if (options.detail !== undefined) this.detail = options.detail;
if (options.hint !== undefined) this.hint = options.hint;
if (options.severity !== undefined) this.severity = options.severity;
if (options.errno !== undefined) this.errno = options.errno;
if (options.position !== undefined) this.position = options.position;
if (options.internalPosition !== undefined) this.internalPosition = options.internalPosition;
if (options.internalQuery !== undefined) this.internalQuery = options.internalQuery;
Expand All @@ -76,15 +79,20 @@ export interface SQLiteErrorOptions {
byteOffset?: number | undefined;
}

// oxlint-disable-next-line typescript-eslint(no-unsafe-declaration-merging)
interface SQLiteError {
byteOffset?: number | undefined;
}

Comment thread
alii marked this conversation as resolved.
Comment thread
alii marked this conversation as resolved.
class SQLiteError extends SQLError implements Bun.SQL.SQLiteError {
public readonly code: string;
public readonly errno: number;
public readonly byteOffset: number | undefined;

constructor(message: string, options: SQLiteErrorOptions) {
super(message);

this.name = "SQLiteError";

this.code = options.code;
this.errno = options.errno;

Expand All @@ -94,22 +102,28 @@ class SQLiteError extends SQLError implements Bun.SQL.SQLiteError {

export interface MySQLErrorOptions {
code: string;
errno: number | undefined;
sqlState: string | undefined;
errno?: number | undefined;
sqlState?: string | undefined;
}
Comment thread
alii marked this conversation as resolved.

// oxlint-disable-next-line typescript-eslint(no-unsafe-declaration-merging)
interface MySQLError {
errno?: number | undefined;
sqlState?: string | undefined;
}

class MySQLError extends SQLError implements Bun.SQL.MySQLError {
public readonly code: string;
public readonly errno: number | undefined;
public readonly sqlState: string | undefined;

constructor(message: string, options: MySQLErrorOptions) {
super(message);

this.name = "MySQLError";
this.code = options.code;
this.errno = options.errno;
this.sqlState = options.sqlState;

if (options.errno !== undefined) this.errno = options.errno;
if (options.sqlState !== undefined) this.sqlState = options.sqlState;
}
Comment thread
alii marked this conversation as resolved.
}

export default { PostgresError, SQLError, SQLiteError, MySQLError };
32 changes: 15 additions & 17 deletions src/js/internal/sql/mysql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ export interface MySQLDotZig {
password: string,
databae: string,
sslmode: SSLMode,
tls: Bun.TLSOptions | boolean | null, // boolean true => empty TLSOptions object `{}`, boolean false or null => nothing
tls: Bun.TLSOptions | boolean | null | Bun.BunFile, // boolean true => empty TLSOptions object `{}`, boolean false or null => nothing
query: string,
path: string,
onConnected: (err: Error | null, connection: $ZigGeneratedClasses.MySQLConnection) => void,
Expand All @@ -126,7 +126,7 @@ export interface MySQLDotZig {
columns: string[] | undefined,
bigint: boolean,
simple: boolean,
) => $ZigGeneratedClasses.MySQLSQLQuery;
) => $ZigGeneratedClasses.MySQLQuery;
}

const enum SQLCommand {
Expand Down Expand Up @@ -276,10 +276,10 @@ function onQueryFinish(this: PooledMySQLConnection, onClose: (err: Error) => voi

class PooledMySQLConnection {
private static async createConnection(
options: Bun.SQL.__internal.DefinedMySQLOptions,
onConnected: (err: Error | null, connection: $ZigGeneratedClasses.MySQLSQLConnection) => void,
options: Bun.SQL.__internal.DefinedPostgresOrMySQLOptions,
onConnected: (err: Error | null, connection: $ZigGeneratedClasses.MySQLConnection) => void,
onClose: (err: Error | null) => void,
): Promise<$ZigGeneratedClasses.MySQLSQLConnection | null> {
): Promise<$ZigGeneratedClasses.MySQLConnection | null> {
const {
hostname,
port,
Expand All @@ -292,8 +292,6 @@ class PooledMySQLConnection {
connectionTimeout = 30 * 1000,
maxLifetime = 0,
prepare = true,

// @ts-expect-error path is currently removed from the types
path,
} = options;

Expand All @@ -302,10 +300,10 @@ class PooledMySQLConnection {
try {
if (typeof password === "function") {
password = password();
}

if (password && $isPromise(password)) {
password = await password;
}
if (password && $isPromise(password)) {
password = await password;
}

return createMySQLConnection(
Expand Down Expand Up @@ -336,12 +334,12 @@ class PooledMySQLConnection {
}

adapter: MySQLAdapter;
connection: $ZigGeneratedClasses.MySQLSQLConnection | null = null;
connection: $ZigGeneratedClasses.MySQLConnection | null = null;
state: PooledConnectionState = PooledConnectionState.pending;
storedError: Error | null = null;
queries: Set<(err: Error) => void> = new Set();
onFinish: ((err: Error | null) => void) | null = null;
connectionInfo: Bun.SQL.__internal.DefinedMySQLOptions;
connectionInfo: Bun.SQL.__internal.DefinedPostgresOrMySQLOptions;
flags: number = 0;
/// queryCount is used to indicate the number of queries using the connection, if a connection is reserved or if its a transaction queryCount will be 1 independently of the number of queries
queryCount: number = 0;
Expand Down Expand Up @@ -488,7 +486,7 @@ export class MySQLAdapter
implements
DatabaseAdapter<PooledMySQLConnection, $ZigGeneratedClasses.MySQLConnection, $ZigGeneratedClasses.MySQLQuery>
{
public readonly connectionInfo: Bun.SQL.__internal.DefinedMySQLOptions;
public readonly connectionInfo: Bun.SQL.__internal.DefinedPostgresOrMySQLOptions;

public readonly connections: PooledMySQLConnection[];
public readonly readyConnections: Set<PooledMySQLConnection>;
Expand All @@ -501,7 +499,7 @@ export class MySQLAdapter
public totalQueries: number = 0;
public onAllQueriesFinished: (() => void) | null = null;

constructor(connectionInfo: Bun.SQL.__internal.DefinedMySQLOptions) {
constructor(connectionInfo: Bun.SQL.__internal.DefinedPostgresOrMySQLOptions) {
this.connectionInfo = connectionInfo;
this.connections = new Array(connectionInfo.max);
this.readyConnections = new Set();
Expand Down Expand Up @@ -845,7 +843,7 @@ export class MySQLAdapter
return;
}

const { promise, resolve } = Promise.withResolvers();
const { promise, resolve } = Promise.withResolvers<void>();
const timer = setTimeout(() => {
// timeout is reached, lets close and probably fail some queries
this.#close().finally(resolve);
Expand All @@ -868,7 +866,7 @@ export class MySQLAdapter
}

// gracefully close the pool
const { promise, resolve } = Promise.withResolvers();
const { promise, resolve } = Promise.withResolvers<void>();

this.onAllQueriesFinished = () => {
// everything is closed, lets close the pool
Expand Down Expand Up @@ -1179,7 +1177,7 @@ export class MySQLAdapter

export default {
MySQLAdapter,
SQLCommand,
commandToString,
detectCommand,
SQLCommand,
};
Loading