aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2023-01-02 21:05:56 -0800
committerGravatar Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2023-01-02 21:05:56 -0800
commitea2b65d4834d864029299809fb23f40ba2a56f90 (patch)
treeb178b1c6327ed9b450b8764b0c13dea63112ee55
parent80c2da73ef59f0170f1c92551c948a1b285da17c (diff)
downloadbun-jarred/pg.tar.gz
bun-jarred/pg.tar.zst
bun-jarred/pg.zip
Draw the owljarred/pg
-rw-r--r--src/bun.js/api/bun.zig1
-rw-r--r--src/bun.js/api/postgres.classes.ts40
-rw-r--r--src/bun.js/api/postgres.zig425
-rw-r--r--src/bun.js/api/postgres_messages.zig410
-rw-r--r--src/bun.js/bindings/ZigGeneratedClasses+DOMClientIsoSubspaces.h1
-rw-r--r--src/bun.js/bindings/ZigGeneratedClasses+DOMIsoSubspaces.h1
-rw-r--r--src/bun.js/bindings/ZigGeneratedClasses+lazyStructureHeader.h6
-rw-r--r--src/bun.js/bindings/ZigGeneratedClasses+lazyStructureImpl.h7
-rw-r--r--src/bun.js/bindings/ZigGeneratedClasses.cpp316
-rw-r--r--src/bun.js/bindings/ZigGeneratedClasses.h87
-rw-r--r--src/bun.js/bindings/ZigGlobalObject.cpp8
-rw-r--r--src/bun.js/bindings/bindings.zig16
-rw-r--r--src/bun.js/bindings/generated_classes.zig180
-rw-r--r--src/bun.js/bindings/generated_classes_list.zig1
-rw-r--r--src/bun.js/module_loader.zig12
-rw-r--r--src/bun.js/postgres/postgres.exports.js8
-rw-r--r--src/bun.js/rare_data.zig2
-rw-r--r--src/bun.js/sql.exports.js436
-rw-r--r--src/bun.zig3
-rw-r--r--src/deps/uws.zig5
-rw-r--r--test/bun.js/sql.test.ts10
21 files changed, 1967 insertions, 8 deletions
diff --git a/src/bun.js/api/bun.zig b/src/bun.js/api/bun.zig
index 6b19f138d..8bc3ee962 100644
--- a/src/bun.js/api/bun.zig
+++ b/src/bun.js/api/bun.zig
@@ -4004,4 +4004,5 @@ pub const JSZlib = struct {
}
};
+pub usingnamespace @import("./postgres.zig");
pub usingnamespace @import("./bun/subprocess.zig");
diff --git a/src/bun.js/api/postgres.classes.ts b/src/bun.js/api/postgres.classes.ts
new file mode 100644
index 000000000..309c9a0db
--- /dev/null
+++ b/src/bun.js/api/postgres.classes.ts
@@ -0,0 +1,40 @@
+import { define } from "../scripts/class-definitions" assert { type: "bun:pg" };
+
+export default [
+ define({
+ name: "PostgresSQLDatabase",
+ construct: false,
+ finalize: true,
+ hasPendingActivity: true,
+ noConstructor: true,
+ klass: {},
+ proto: {
+ close: {
+ fn: "close",
+ length: 0,
+ },
+ query: {
+ fn: "query",
+ length: 4,
+ },
+ // prepare: {
+ // fn: "prepare",
+ // length: 2,
+ // },
+ // run: {
+ // fn: "run",
+ // length: 2,
+ // },
+ ref: {
+ fn: "ref",
+ length: 0,
+ },
+ unref: {
+ fn: "unref",
+ length: 0,
+ },
+ },
+ values: ["onClose", "onNotice", "onOpen", "onTimeout", "onDrain"],
+ JSType: "0b11101110",
+ }),
+];
diff --git a/src/bun.js/api/postgres.zig b/src/bun.js/api/postgres.zig
new file mode 100644
index 000000000..bd45ba7cb
--- /dev/null
+++ b/src/bun.js/api/postgres.zig
@@ -0,0 +1,425 @@
+const Bun = @This();
+const default_allocator = @import("bun").default_allocator;
+const bun = @import("bun");
+const Environment = bun.Environment;
+const NetworkThread = @import("bun").HTTP.NetworkThread;
+const Global = bun.Global;
+const strings = bun.strings;
+const string = bun.string;
+const Output = @import("bun").Output;
+const MutableString = @import("bun").MutableString;
+const std = @import("std");
+const Allocator = std.mem.Allocator;
+const JSC = @import("bun").JSC;
+const JSValue = JSC.JSValue;
+const JSGlobalObject = JSC.JSGlobalObject;
+
+const uws = bun.uws;
+const Socket = uws.NewSocketHandler(false);
+const SocketContext = uws.SocketContext;
+const Messages = @import("./postgres_messages.zig");
+
+const ErrorCode = enum(i32) {
+ cancel,
+ invalid_response,
+ timeout,
+ closed,
+ failed_to_write,
+ failed_to_connect,
+ failed_to_allocate_memory,
+ invalid_utf8,
+ ended,
+ unknown,
+
+ pub const status = bun.enumMap(ErrorCode, .{
+ .{ .cancel, "cancel" },
+ .{ .invalid_response, "invalidResponse" },
+ .{ .timeout, "timeout" },
+ .{ .closed, "closed" },
+ .{ .failed_to_write, "failedToWrite" },
+ .{ .failed_to_connect, "failedToConnect" },
+ .{ .failed_to_allocate_memory, "failedToAllocateMemory" },
+ .{ .invalid_utf8, "invalidUtf8" },
+ .{ .ended, "ended" },
+ .{ .unknown, "unknown" },
+ });
+
+ pub const code = bun.enumMap(ErrorCode, .{
+ .{ .cancel, "POSTGRES_ERROR_CANCEL" },
+ .{ .invalid_response, "POSTGRES_ERROR_INVALID_RESPONSE" },
+ .{ .timeout, "POSTGRES_ERROR_TIMEOUT" },
+ .{ .closed, "POSTGRES_ERROR_CLOSED" },
+ .{ .failed_to_write, "POSTGRES_ERROR_FAILED_TO_WRITE" },
+ .{ .failed_to_connect, "POSTGRES_ERROR_FAILED_TO_CONNECT" },
+ .{ .failed_to_allocate_memory, "POSTGRES_ERROR_FAILED_TO_ALLOCATE_MEMORY" },
+ .{ .invalid_utf8, "POSTGRES_ERROR_INVALID_UTF8" },
+ .{ .ended, "POSTGRES_ERROR_ENDED" },
+ .{ .unknown, "POSTGRES_ERROR_UNKNOWN" },
+ });
+
+ pub const label = bun.enumMap(ErrorCode, .{
+ .{ .cancel, "The connection was cancelled" },
+ .{ .invalid_response, "The connection has an invalid response" },
+ .{ .timeout, "The connection timed out" },
+ .{ .closed, "The connection was closed" },
+ .{ .failed_to_write, "The connection failed to write" },
+ .{ .failed_to_connect, "The connection failed to connect" },
+ .{ .failed_to_allocate_memory, "Failed to allocate memory" },
+ .{ .invalid_utf8, "Received invalid UTF-8" },
+ .{ .ended, "The connection was ended" },
+ .{ .unknown, "An unknown error occurred" },
+ });
+
+ pub fn toErrorInstance(
+ this: ErrorCode,
+ globalObject: *JSC.JSGlobalObject,
+ ) JSC.JSValue {
+ var instance = globalObject.createErrorInstance(
+ "{s}",
+ .{this.label()},
+ );
+ instance.put("code", JSC.ZigString.init(this.code()).toValueGC(globalObject));
+ instance.put("name", JSC.ZigString.static("PostgresError").toValueGC(globalObject));
+ return instance;
+ }
+};
+
+const ConnectionOptions = union(enum) {
+ pub const TCP = struct {
+ hostname: []const u8 = "localhost",
+ port: u16 = 5432,
+ database: []const u8 = "postgres",
+ user: []const u8 = "",
+ password: []const u8 = "",
+ };
+ tcp: TCP,
+ tls: struct {
+ tcp: TCP,
+ },
+};
+
+pub const PostgresData = struct {
+ tcp_ctx: ?*uws.SocketContext = null,
+};
+
+pub const Protocol = struct {};
+
+pub const PostgresConnection = struct {
+ const log = Output.scoped(.PostgresConnection, false);
+
+ tcp: Socket,
+ poll_ref: JSC.PollRef = .{},
+
+ pub fn connect(globalThis: *JSC.JSGlobalObject, db: *PostgresSQLDatabase, options: ConnectionOptions) !void {
+ autoRegister(globalThis);
+ log("connect {s}:{d}", .{ options.tcp.hostname, options.tcp.port });
+ const socket = Socket.connectAnon(
+ options.tcp.hostname,
+ options.tcp.port,
+ globalThis.bunVM().rareData().postgres_data.tcp_ctx.?,
+ &db.connection,
+ ) orelse {
+ return error.FailedToConnect;
+ };
+ db.connection.tcp = socket;
+ }
+
+ pub fn closeGracefully(this: *PostgresConnection) void {
+ this.tcp.close(0, null); // todo
+ }
+
+ pub fn autoRegister(global: *JSC.JSGlobalObject) void {
+ var vm = global.bunVM();
+
+ if (vm.rareData().postgres_data.tcp_ctx == null) {
+ var opts: uws.us_socket_context_options_t = undefined;
+ @memset(@ptrCast([*]u8, &opts), 0, @sizeOf(uws.us_socket_context_options_t));
+ var ctx = uws.us_create_socket_context(0, vm.uws_event_loop.?, @sizeOf(usize), opts).?;
+ vm.rareData().postgres_data.tcp_ctx = ctx;
+ Socket.configure(
+ ctx,
+ false,
+ PostgresConnection,
+ struct {
+ pub const onClose = PostgresConnection.onClose;
+ pub const onData = PostgresConnection.onData;
+ pub const onWritable = PostgresConnection.onWritable;
+ pub const onTimeout = PostgresConnection.onTimeout;
+ pub const onConnectError = PostgresConnection.onConnectError;
+ pub const onEnd = PostgresConnection.onEnd;
+ },
+ );
+ }
+ }
+
+ pub inline fn database(this: *PostgresConnection) *PostgresSQLDatabase {
+ return @fieldParentPtr(PostgresSQLDatabase, "connection", this);
+ }
+
+ pub fn onWritable(
+ this: *PostgresConnection,
+ socket: Socket,
+ ) void {
+ std.debug.assert(socket.socket == this.tcp.socket);
+ // if (this.to_send.len == 0)
+ // return;
+
+ // const wrote = socket.write(this.to_send, true);
+ // if (wrote < 0) {
+ // this.terminate(ErrorCode.failed_to_write);
+ // return;
+ // }
+ // this.to_send = this.to_send[@min(@intCast(usize, wrote), this.to_send.len)..];
+ }
+ pub fn onTimeout(
+ this: *PostgresConnection,
+ _: Socket,
+ ) void {
+ this.terminate(ErrorCode.timeout);
+ }
+ pub fn onConnectError(this: *PostgresConnection, _: Socket, _: c_int) void {
+ this.terminate(ErrorCode.failed_to_connect);
+ }
+
+ pub fn onEnd(this: *PostgresConnection, socket: Socket) void {
+ log("onEnd", .{});
+ std.debug.assert(socket.socket == this.tcp.socket);
+ this.terminate(ErrorCode.ended);
+ }
+
+ pub fn onData(_: *PostgresConnection, _: Socket, data: []const u8) void {
+ log("onData: {d}", .{data.len});
+ }
+
+ pub fn onClose(this: *PostgresConnection, _: Socket, _: c_int, _: ?*anyopaque) void {
+ log("onClose", .{});
+ this.terminate(ErrorCode.closed);
+ }
+
+ pub fn onOpen(this: *PostgresConnection, socket: Socket) void {
+ log("onOpen", .{});
+ std.debug.assert(socket.socket == this.tcp.socket);
+ }
+
+ pub fn terminate(this: *PostgresConnection, code: ErrorCode) void {
+ log("terminate - {s}", .{code.code()});
+ this.poll_ref.disable();
+
+ if (this.tcp.isEstablished() and !this.tcp.isClosed()) {
+ this.tcp.ext(?*anyopaque).?.* = null;
+ this.tcp.close(0, null);
+ }
+
+ this.database().terminate(code);
+ }
+};
+
+const PendingQuery = struct {
+ resolve: JSC.JSValue,
+ reject: JSC.JSValue,
+ query: JSC.ZigString.Slice,
+};
+
+pub const PostgresSQLDatabase = struct {
+ const log = Output.scoped(.PostgresSQLDatabase, false);
+ pub usingnamespace JSC.Codegen.JSPostgresSQLDatabase;
+ arena: std.heap.ArenaAllocator,
+ connection: PostgresConnection,
+ options: ConnectionOptions,
+ this_jsvalue: JSC.JSValue = .zero,
+ globalObject: *JSC.JSGlobalObject,
+ status: Status = .connecting,
+ has_pending_activity: std.atomic.Atomic(bool) = std.atomic.Atomic(bool).init(false),
+
+ close_status: ErrorCode = .unknown,
+
+ pending_queries: std.ArrayListUnmanaged(PendingQuery) = .{},
+
+ pub const Status = enum {
+ connecting,
+ connected,
+ closing,
+ closed,
+
+ pub const label = bun.enumMap(Status, .{
+ .{ .connecting, "connecting" },
+ .{ .connected, "connected" },
+ .{ .closing, "closing" },
+ .{ .closed, "closed" },
+ });
+ };
+
+ pub fn hasPendingActivity(this: *PostgresSQLDatabase) callconv(.C) bool {
+ @fence(.Acquire);
+ return this.has_pending_activity.load(.Acquire);
+ }
+
+ pub fn getStatus(this: *PostgresSQLDatabase, globalThis: *JSC.JSGlobalObject) callconv(.C) JSC.JSValue {
+ return JSC.ZigString.init(this.status.label()).toValueGC(globalThis);
+ }
+
+ fn setStatus(
+ this: *PostgresSQLDatabase,
+ status: Status,
+ _: JSC.JSValue,
+ ) void {
+ this.status = status;
+ this.updateHasPendingData();
+ if (status == .connected) {}
+ }
+
+ pub fn updateHasPendingData(this: *PostgresSQLDatabase) void {
+ @fence(.Release);
+ this.has_pending_activity.store(this.status != .closed, .Release);
+ }
+
+ pub fn terminate(this: *PostgresSQLDatabase, code: ErrorCode) void {
+ const js_value = this.this_jsvalue;
+ if (this.status == .connecting) {
+ this.setStatus(.closed, js_value);
+ return;
+ }
+ this.close_status = code;
+
+ if (this.status == .closed)
+ return;
+
+ this.setStatus(.closed, js_value);
+ }
+
+ pub fn connect(globalObject: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSC.JSValue {
+ const arguments_ = callframe.arguments(8);
+ const arguments: []const JSC.JSValue = arguments_.ptr[0..arguments_.len];
+
+ if (arguments.len < 1) {
+ globalObject.throwNotEnoughArguments("connect", 1, 0);
+ return .zero;
+ }
+
+ if (arguments[0].isEmptyOrUndefinedOrNull()) {
+ globalObject.throwInvalidArgumentType("connect", "options", "url string or object");
+ return .zero;
+ }
+
+ var arena = std.heap.ArenaAllocator.init(globalObject.allocator());
+
+ var options = ConnectionOptions{ .tcp = .{} };
+
+ if (arguments[0].get(globalObject, "host")) |value| {
+ if (!value.isEmptyOrUndefinedOrNull()) {
+ const str = value.toSlice(globalObject, arena.allocator()).clone(arena.allocator()) catch @panic("Out of memory");
+ if (str.len > 0)
+ options.tcp.hostname = str.slice();
+ }
+ }
+ if (arguments[0].get(globalObject, "port")) |value| {
+ if (!value.isEmptyOrUndefinedOrNull()) {
+ const str = value.toSlice(globalObject, arena.allocator()).clone(arena.allocator()) catch @panic("Out of memory");
+ if (str.len > 0)
+ options.tcp.port = std.fmt.parseInt(u16, str.slice(), 10) catch @panic("Error parsing port number");
+ }
+ }
+ if (arguments[0].get(globalObject, "database")) |value| {
+ if (!value.isEmptyOrUndefinedOrNull()) {
+ const str = value.toSlice(globalObject, arena.allocator()).clone(arena.allocator()) catch @panic("Out of memory");
+ if (str.len > 0)
+ options.tcp.database = str.slice();
+ }
+ }
+ if (arguments[0].get(globalObject, "user")) |value| {
+ if (!value.isEmptyOrUndefinedOrNull()) {
+ const str = value.toSlice(globalObject, arena.allocator()).clone(arena.allocator()) catch @panic("Out of memory");
+ if (str.len > 0)
+ options.tcp.user = str.slice();
+ }
+ }
+ if (arguments[0].get(globalObject, "pass")) |value| {
+ if (!value.isEmptyOrUndefinedOrNull()) {
+ const str = value.toSlice(globalObject, arena.allocator()).clone(arena.allocator()) catch @panic("Out of memory");
+ if (str.len > 0)
+ options.tcp.password = str.slice();
+ }
+ }
+ // if (arguments[0].get(globalObject, "path")) |value| {
+ // if (!value.isEmptyOrUndefinedOrNull()) {
+ // const str = value.toSlice(globalObject).clone(arena.allocator());
+ // if (str.len > 0)
+ // options.tcp.p = str.slice();
+ // }
+ // }
+ var db = globalObject.allocator().create(PostgresSQLDatabase) catch |err| {
+ arena.deinit();
+ globalObject.throwError(err, "failed to allocate db");
+ return .zero;
+ };
+
+ const this = db.toJS(globalObject);
+ db.* = .{
+ .this_jsvalue = this,
+ .options = options,
+ .status = .connecting,
+ .arena = arena,
+ .globalObject = globalObject,
+ .connection = undefined,
+ };
+ PostgresSQLDatabase.onCloseSetCached(this, globalObject, arguments[0].get(globalObject, "onClose") orelse @panic("Expected onClose. Don't call this function outside of bun:sql."));
+ PostgresSQLDatabase.onNoticeSetCached(this, globalObject, arguments[0].get(globalObject, "onNotice") orelse @panic("Expected onNotice. Don't call this function outside of bun:sql."));
+ PostgresSQLDatabase.onOpenSetCached(this, globalObject, arguments[0].get(globalObject, "onOpen") orelse @panic("Expected onOpen. Don't call this function outside of bun:sql."));
+ PostgresSQLDatabase.onTimeoutSetCached(this, globalObject, arguments[0].get(globalObject, "onTimeout") orelse @panic("Expected onTimeout. Don't call this function outside of bun:sql."));
+ PostgresSQLDatabase.onDrainSetCached(this, globalObject, arguments[0].get(globalObject, "onDrain") orelse @panic("Expected onDrain. Don't call this function outside of bun:sql."));
+ db.updateHasPendingData();
+ PostgresConnection.connect(globalObject, db, options) catch |err| {
+ arena.deinit();
+ globalObject.throwError(err, "failed to connect");
+ return .zero;
+ };
+
+ return this;
+ }
+
+ pub fn query(_: *PostgresSQLDatabase, _: *JSC.JSGlobalObject, _: *JSC.CallFrame) callconv(.C) JSC.JSValue {
+ return JSC.JSValue.jsUndefined();
+ }
+
+ pub fn ref(_: *PostgresSQLDatabase, _: *JSC.JSGlobalObject, _: *JSC.CallFrame) callconv(.C) JSC.JSValue {
+ return JSC.JSValue.jsUndefined();
+ }
+
+ pub fn unref(_: *PostgresSQLDatabase, _: *JSC.JSGlobalObject, _: *JSC.CallFrame) callconv(.C) JSC.JSValue {
+ return JSC.JSValue.jsUndefined();
+ }
+
+ pub fn close(this: *PostgresSQLDatabase, globalObject: *JSC.JSGlobalObject, _: *JSC.CallFrame) callconv(.C) JSC.JSValue {
+ if (this.status == .closed) {
+ return JSC.ZigString.init(this.close_status.label()).toValueGC(globalObject);
+ }
+
+ if (this.status == .closing) {
+ return JSC.JSValue.jsUndefined();
+ }
+
+ std.debug.assert(!this.connection.tcp.isClosed());
+ std.debug.assert(this.connection.tcp.isEstablished());
+ std.debug.assert(!this.connection.tcp.isShutdown());
+
+ this.setStatus(.closing, this.this_jsvalue);
+ this.connection.closeGracefully();
+ return JSC.JSValue.jsUndefined();
+ }
+
+ pub fn finalize(this: *PostgresSQLDatabase) callconv(.C) void {
+ this.deinit();
+ }
+
+ pub fn deinit(this: *PostgresSQLDatabase) void {
+ std.debug.assert(this.status == .closed);
+ this.arena.deinit();
+ bun.default_allocator.destroy(this);
+ }
+};
+
+comptime {
+ @export(PostgresSQLDatabase.connect, .{
+ .name = "Bun__PostgreSQL__connect",
+ });
+}
diff --git a/src/bun.js/api/postgres_messages.zig b/src/bun.js/api/postgres_messages.zig
new file mode 100644
index 000000000..35fee4906
--- /dev/null
+++ b/src/bun.js/api/postgres_messages.zig
@@ -0,0 +1,410 @@
+pub const String = extern struct {
+ data: [*:0]u8 align(1) = undefined,
+};
+
+pub const Byten = extern struct {
+ data: [*:0]u8 align(1) = undefined,
+};
+
+pub const AuthenticationOk = extern struct {
+ pub const direction = .backend;
+ pub const Bytes = extern struct {
+ byte1: u8 align(1) = 'R',
+ length: i32 align(1) = 8,
+ tag: i32 align(1) = 0,
+ };
+ pub const bytes = Bytes{};
+};
+
+pub const AuthenticationKerberosV5 = extern struct {
+ pub const direction = .backend;
+ pub const Bytes = extern struct {
+ byte1: u8 align(1) = 'R',
+ length: i32 align(1) = 8,
+ tag: i32 align(1) = 2,
+ };
+ pub const bytes = Bytes{};
+};
+
+pub const AuthenticationMD5Password = extern struct {
+ pub const direction = .backend;
+ pub const Bytes = extern struct {
+ byte1: u8 align(1) = 'R',
+ length: i32 align(1) = 12,
+ tag: i32 align(1) = 5,
+ salt: [4]u8 align(1) = undefined,
+ };
+ pub const bytes = Bytes{};
+};
+
+pub const AuthenticationSCMCredential = extern struct {
+ pub const direction = .backend;
+ pub const Bytes = extern struct {
+ byte1: u8 align(1) = 'R',
+ length: i32 align(1) = 8,
+ tag: i32 align(1) = 6,
+ };
+ pub const bytes = Bytes{};
+};
+
+pub const AuthenticationCleartextPassword = extern struct {
+ pub const direction = .backend;
+ pub const Bytes = extern struct {
+ byte1: u8 align(1) = 'R',
+ length: i32 align(1) = 8,
+ tag: i32 align(1) = 3,
+ };
+ pub const bytes = Bytes{};
+};
+
+pub const AuthenticationGSS = extern struct {
+ pub const direction = .backend;
+ pub const Bytes = extern struct {
+ /// Identifies the message as an authentication request.
+ byte1: u8 align(1) = 'R',
+ /// Length of message contents in bytes, including self.
+ length: i32 align(1) = 8,
+ /// Specifies that GSSAPI authentication is required.
+ tag: i32 align(1) = 7,
+ };
+ pub const bytes = Bytes{};
+};
+
+pub const AuthenticationGSSContinue = extern struct {
+ pub const direction = .backend;
+ pub const Bytes = extern struct {
+ /// Identifies the message as an authentication request.
+ byte1: u8 align(1) = 'R',
+ /// Length of message contents in bytes, including self.
+ length: i32 align(1) = 8,
+ /// Specifies that this message contains GSSAPI or SSPI data.
+ tag: i32 align(1) = 8,
+ /// GSSAPI or SSPI authentication data.
+ data: []u8 align(1),
+ };
+ pub const bytes = Bytes{};
+};
+
+pub const AuthenticationSSPI = extern struct {
+ pub const direction = .backend;
+ pub const Bytes = extern struct {
+ /// Identifies the message as an authentication request.
+ byte1: u8 align(1) = 'R',
+ /// Length of message contents in bytes, including self.
+ length: i32 align(1) = 8,
+ /// Specifies that SSPI authentication is required.
+ tag: i32 align(1) = 9,
+ };
+ pub const bytes = Bytes{};
+};
+
+pub const AuthenticationSASL = extern struct {
+ pub const direction = .backend;
+ pub const Bytes = extern struct {
+ /// Identifies the message as an authentication request.
+ byte1: u8 align(1) = 'R',
+ /// Length of message contents in bytes, including self.
+ length: i32 align(1) = 8,
+ /// Specifies that SASL authentication is required.
+ tag: i32 align(1) = 10,
+ /// The message body is a list of SASL authentication mechanisms, in the server's order of preference. A zero byte is required as terminator after the last authentication mechanism name. For each mechanism, there is the following:
+ mechanisms: [:0]const u8 align(1) = "",
+ };
+ pub const bytes = Bytes{};
+};
+
+pub const AuthenticationSASLContinue = extern struct {
+ pub const direction = .backend;
+ pub const Bytes = extern struct {
+ /// Identifies the message as an authentication request.
+ byte1: u8 align(1) = 'R',
+ /// Length of message contents in bytes, including self.
+ length: i32 align(1) = undefined,
+ /// Specifies that this message contains a SASL challenge.
+ tag: i32 align(1) = 11,
+ /// SASL data, specific to the SASL mechanism being used.
+ data: []const u8 align(1) = "",
+ };
+ pub const bytes = Bytes{};
+};
+
+pub const AuthenticationSASLFinal = extern struct {
+ pub const direction = .backend;
+ pub const Bytes = extern struct {
+ /// Identifies the message as an authentication request.
+ byte1: u8 align(1) = 'R',
+ /// Length of message contents in bytes, including self.
+ length: i32 align(1) = undefined,
+ /// Specifies that SASL authentication has completed.
+ tag: i32 align(1) = 12,
+ /// SASL outcome "additional data", specific to the SASL mechanism being used.
+ data: []const u8 align(1) = "",
+ };
+ pub const bytes = Bytes{};
+};
+
+pub const CancelRequest = extern struct {
+ pub const direction = .frontend;
+ pub const Bytes = extern struct {
+ /// Length of message contents in bytes, including self.
+ length: i32 align(1) = 16,
+ /// The cancel request code. The value is chosen to contain 1234 in the most significant 16 bits, and 5678 in the least significant 16 bits. (To avoid confusion, this code must not be the same as any protocol version number.)
+ code: i32 align(1) = 80877102,
+ /// The process ID of the target backend.
+ process_id: i32 align(1),
+ /// The secret key for the target backend.
+ secret_key: i32 align(1),
+ };
+ pub const bytes = Bytes{};
+};
+
+pub const Close = extern struct {
+ pub const direction = .frontend;
+ pub const Bytes = extern struct {
+ /// Identifies the message as a Close command.
+ byte1: u8 align(1) = 'C',
+ /// Length of message contents in bytes, including self.
+ length: i32 align(1),
+ /// 'S' to close a prepared statement; or 'P' to close a portal.
+ type: u8 align(1),
+ /// The name of the prepared statement or portal to close (an empty string selects the unnamed prepared statement or portal).
+ name: []u8 align(1),
+ };
+ pub const bytes = Bytes{};
+};
+
+pub const CloseComplete = extern struct {
+ pub const direction = .backend;
+ pub const Bytes = extern struct {
+ /// Identifies the message as a Close-complete indicator.
+ byte1: u8 align(1) = '3',
+ /// Length of message contents in bytes, including self.
+ length: i32 align(1) = 4,
+ };
+ pub const bytes = Bytes{};
+};
+
+pub const CommandComplete = extern struct {
+ pub const direction = .backend;
+ pub const Bytes = extern struct {
+ /// Identifies the message as a command-completed response.
+ byte1: u8 align(1) = 'C',
+ /// Length of message contents in bytes, including self.
+ length: i32 align(1) = undefined,
+ /// The command tag. This is usually a single word that identifies which SQL command was completed.
+ /// For an INSERT command, the tag is INSERT oid rows, where rows is the number of rows inserted. oid used to be the object ID of the inserted row if rows was 1 and the target table had OIDs, but OIDs system columns are not supported anymore; therefore oid is always 0.
+ /// For a DELETE command, the tag is DELETE rows where rows is the number of rows deleted.
+ /// For an UPDATE command, the tag is UPDATE rows where rows is the number of rows updated.
+ /// For a SELECT or CREATE TABLE AS command, the tag is SELECT rows where rows is the number of rows retrieved.
+ /// For a MOVE command, the tag is MOVE rows where rows is the number of rows the cursor's position has been changed by.
+ /// For a FETCH command, the tag is FETCH rows where rows is the number of rows that have been retrieved from the cursor.
+ /// For a COPY command, the tag is COPY rows where rows is the number of rows copied. (Note: the row count appears only in PostgreSQL 8.2 and later.)
+ tag: [8]u8 align(1) = .{ 0, 0, 0, 0, 0, 0, 0, 0 },
+ };
+ pub const bytes = Bytes{};
+};
+
+pub const CopyData = extern struct {
+ pub const direction = .both;
+ pub const Bytes = extern struct {
+ /// Identifies the message as copy data.
+ byte1: u8 align(1) = 'd',
+ /// Length of message contents in bytes, including self.
+ length: i32 align(1) = undefined,
+ /// Data that forms part of a copy-in or copy-out operation.
+ data: []const u8 align(1),
+ };
+ pub const bytes = Bytes{};
+};
+
+pub const CopyDone = extern struct {
+ pub const direction = .frontend;
+ pub const Bytes = extern struct {
+ /// Identifies the message as copy-done.
+ byte1: u8 align(1) = 'c',
+ /// Length of message contents in bytes, including self.
+ length: i32 align(1) = 4,
+ };
+ pub const bytes = Bytes{};
+};
+
+pub const CopyFail = extern struct {
+ pub const direction = .frontend;
+ pub const Bytes = extern struct {
+ /// Identifies the message as copy-fail.
+ byte1: u8 align(1) = 'f',
+ /// Length of message contents in bytes, including self.
+ length: i32 align(1) = undefined,
+ /// The failure message.
+ message: [:0]const u8 align(1) = "",
+ };
+ pub const bytes = Bytes{};
+};
+
+pub const CopyInResponse = extern struct {
+ pub const direction = .backend;
+ pub const Bytes = extern struct {
+ /// Identifies the message as a CopyInResponse.
+ byte1: u8 align(1) = 'G',
+ /// Length of message contents in bytes, including self.
+ length: i32 align(1) = undefined,
+
+ /// 0 indicates the overall COPY format is textual (rows separated by newlines, columns separated by separator characters, etc.). 1 indicates the overall copy format is binary (similar to DataRow format). See COPY for more information.
+ copy_format: i8 align(1) = undefined,
+
+ /// The format code being used for the data transfer.
+ columns_count: i16 align(1) = 0,
+
+ /// The format codes to be used for each column. Each must presently be zero (text) or one (binary). All must be zero if the overall copy format is textual.
+ columns: []i16 align(1) = &[_]i16{},
+ };
+ pub const bytes = Bytes{};
+};
+
+pub const CopyOutResponse = extern struct {
+ pub const direction = .backend;
+ pub const Bytes = extern struct {
+ /// Identifies the message as a CopyOutResponse.
+ byte1: u8 align(1) = 'H',
+ /// Length of message contents in bytes, including self.
+ length: i32 align(1) = undefined,
+
+ /// 0 indicates the overall COPY format is textual (rows separated by newlines, columns separated by separator characters, etc.). 1 indicates the overall copy format is binary (similar to DataRow format). See COPY for more information.
+ copy_format: i8 align(1) = undefined,
+
+ /// The format code being used for the data transfer.
+ columns_count: i16 align(1) = 0,
+
+ /// The format codes to be used for each column. Each must presently be zero (text) or one (binary). All must be zero if the overall copy format is textual.
+ columns: []i16 align(1) = &[_]i16{},
+ };
+ pub const bytes = Bytes{};
+};
+
+pub const CopyBothResponse = extern struct {
+ pub const direction = .backend;
+ pub const Bytes = struct {
+ /// Identifies the message as a CopyBothResponse.
+ byte1: u8 align(1) = 'W',
+ /// Length of message contents in bytes, including self.
+ length: i32 align(1) = undefined,
+
+ /// 0 indicates the overall COPY format is textual (rows separated by newlines, columns separated by separator characters, etc.). 1 indicates the overall copy format is binary (similar to DataRow format). See COPY for more information.
+ copy_format: i8 align(1) = undefined,
+
+ /// The format code being used for the data transfer.
+ columns_count: i16 align(1) = 0,
+
+ /// The format codes to be used for each column. Each must presently be zero (text) or one (binary). All must be zero if the overall copy format is textual.
+ columns: [*]i16 align(1) = &[_]i16{},
+ };
+ pub const bytes = Bytes{};
+};
+
+pub const DataRow = extern struct {
+ pub const direction = .backend;
+ pub const Bytes = extern struct {
+ /// Identifies the message as a DataRow.
+ byte1: u8 align(1) = 'D',
+ /// Length of message contents in bytes, including self.
+ length: i32 align(1) = undefined,
+ /// The number of column values that follow (possibly zero).
+ columns_count: i16 align(1) = 0,
+ };
+ pub const bytes = Bytes{};
+};
+
+pub const Describe = extern struct {
+ pub const direction = .frontend;
+ pub const Bytes = extern struct {
+ /// Identifies the message as a Describe command.
+ byte1: u8 align(1) = 'D',
+ /// Length of message contents in bytes, including self.
+ length: i32 align(1) = undefined,
+ /// The object to describe. 'S' to describe a prepared statement; or 'P' to describe a portal.
+ object_type: u8 align(1) = 'S',
+ /// The name of the prepared statement or portal to describe (an empty string selects the unnamed prepared statement or portal).
+ object_name: [*:0]const u8 align(1) = "",
+ };
+ pub const bytes = Bytes{};
+};
+
+pub const EmptyQueryResponse = extern struct {
+ pub const direction = .backend;
+ pub const Bytes = extern struct {
+ /// Identifies the message as an EmptyQueryResponse.
+ byte1: u8 align(1) = 'I',
+ /// Length of message contents in bytes, including self.
+ length: i32 align(1) = 4,
+ };
+ pub const bytes = Bytes{};
+};
+
+pub const ErrorResponse = extern struct {
+ pub const direction = .backend;
+ pub const Bytes = extern struct {
+ /// Identifies the message as an ErrorResponse.
+ byte1: u8 align(1) = 'E',
+ /// Length of message contents in bytes, including self.
+ length: i32 align(1) = undefined,
+ /// The fields of the error response.
+ fields: [*:0]const Field align(1) = &[_]Field{},
+ };
+ pub const bytes = Bytes{};
+
+ pub const Field = extern struct {
+ /// The error code.
+ code: u8 align(1) = undefined,
+ /// The error message.
+ message: [:0]const u8 align(1) = "",
+ };
+};
+
+pub const Execute = extern struct {
+ pub const direction = .frontend;
+ pub const Bytes = extern struct {
+ /// Identifies the message as an Execute command.
+ byte1: u8 align(1) = 'E',
+ /// Length of message contents in bytes, including self.
+ length: i32 align(1) = undefined,
+ /// The name of the portal to execute (an empty string selects the unnamed portal).
+ portal_name: [*:0]const u8 align(1) = "",
+ /// The maximum number of rows to return, if portal contains a query that returns rows (ignored otherwise). Zero denotes "no limit".
+ max_rows: i32 align(1) = 0,
+ };
+ pub const bytes = Bytes{};
+};
+
+pub const Flush = extern struct {
+ pub const direction = .frontend;
+ pub const Bytes = extern struct {
+ /// Identifies the message as a Flush.
+ byte1: u8 align(1) = 'H',
+ /// Length of message contents in bytes, including self.
+ length: i32 align(1) = 4,
+ };
+ pub const bytes = Bytes{};
+};
+
+pub const FunctionCall = extern struct {
+ pub const direction = .frontend;
+ pub const Bytes = extern struct {
+ /// Identifies the message as a FunctionCall.
+ byte1: u8 align(1) = 'F',
+ /// Length of message contents in bytes, including self.
+ length: i32 align(1) = undefined,
+ /// The object ID of the function to be called.
+ function_id: i32 align(1) = undefined,
+
+ /// The number of argument format codes that follow (denoted C below). This can be zero to indicate that there are no arguments or that the arguments all use the default format (text); or one, in which case the specified format code is applied to all arguments; or it can equal the actual number of arguments.
+ format_codes_len: i16 align(1) = 0,
+
+ format_codes: [:0]i16 align(1) = &[_]i16{},
+ };
+ pub const bytes = Bytes{};
+
+ pub const Argument = extern struct {
+ /// The argument value, in the format indicated by the associated format code. n is the above length.
+ value: [:0]const u8 align(1) = "",
+ };
+};
diff --git a/src/bun.js/bindings/ZigGeneratedClasses+DOMClientIsoSubspaces.h b/src/bun.js/bindings/ZigGeneratedClasses+DOMClientIsoSubspaces.h
index f74d54b02..b7c50465d 100644
--- a/src/bun.js/bindings/ZigGeneratedClasses+DOMClientIsoSubspaces.h
+++ b/src/bun.js/bindings/ZigGeneratedClasses+DOMClientIsoSubspaces.h
@@ -14,6 +14,7 @@ std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForSHA512_256Constructor;
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForCryptoHasherConstructor;std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForServerWebSocket;
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForServerWebSocketConstructor;std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForFileSystemRouter;
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForFileSystemRouterConstructor;std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForMatchedRoute;
+std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForPostgresSQLDatabase;
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForExpect;
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForExpectConstructor;std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForTextDecoder;
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForTextDecoderConstructor;std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForRequest;
diff --git a/src/bun.js/bindings/ZigGeneratedClasses+DOMIsoSubspaces.h b/src/bun.js/bindings/ZigGeneratedClasses+DOMIsoSubspaces.h
index cda555fa9..ea7457ed2 100644
--- a/src/bun.js/bindings/ZigGeneratedClasses+DOMIsoSubspaces.h
+++ b/src/bun.js/bindings/ZigGeneratedClasses+DOMIsoSubspaces.h
@@ -14,6 +14,7 @@ std::unique_ptr<IsoSubspace> m_subspaceForSHA512_256Constructor;std::unique_ptr<
std::unique_ptr<IsoSubspace> m_subspaceForCryptoHasherConstructor;std::unique_ptr<IsoSubspace> m_subspaceForServerWebSocket;
std::unique_ptr<IsoSubspace> m_subspaceForServerWebSocketConstructor;std::unique_ptr<IsoSubspace> m_subspaceForFileSystemRouter;
std::unique_ptr<IsoSubspace> m_subspaceForFileSystemRouterConstructor;std::unique_ptr<IsoSubspace> m_subspaceForMatchedRoute;
+std::unique_ptr<IsoSubspace> m_subspaceForPostgresSQLDatabase;
std::unique_ptr<IsoSubspace> m_subspaceForExpect;
std::unique_ptr<IsoSubspace> m_subspaceForExpectConstructor;std::unique_ptr<IsoSubspace> m_subspaceForTextDecoder;
std::unique_ptr<IsoSubspace> m_subspaceForTextDecoderConstructor;std::unique_ptr<IsoSubspace> m_subspaceForRequest;
diff --git a/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureHeader.h b/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureHeader.h
index 2c0cf9929..6cc13981f 100644
--- a/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureHeader.h
+++ b/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureHeader.h
@@ -94,6 +94,12 @@ JSC::Structure* JSMatchedRouteStructure() { return m_JSMatchedRoute.getInitializ
JSC::LazyClassStructure m_JSMatchedRoute;
bool hasJSMatchedRouteSetterValue { false };
mutable JSC::WriteBarrier<JSC::Unknown> m_JSMatchedRouteSetterValue;
+JSC::Structure* JSPostgresSQLDatabaseStructure() { return m_JSPostgresSQLDatabase.getInitializedOnMainThread(this); }
+ JSC::JSObject* JSPostgresSQLDatabaseConstructor() { return m_JSPostgresSQLDatabase.constructorInitializedOnMainThread(this); }
+ JSC::JSValue JSPostgresSQLDatabasePrototype() { return m_JSPostgresSQLDatabase.prototypeInitializedOnMainThread(this); }
+ JSC::LazyClassStructure m_JSPostgresSQLDatabase;
+ bool hasJSPostgresSQLDatabaseSetterValue { false };
+ mutable JSC::WriteBarrier<JSC::Unknown> m_JSPostgresSQLDatabaseSetterValue;
JSC::Structure* JSExpectStructure() { return m_JSExpect.getInitializedOnMainThread(this); }
JSC::JSObject* JSExpectConstructor() { return m_JSExpect.constructorInitializedOnMainThread(this); }
JSC::JSValue JSExpectPrototype() { return m_JSExpect.prototypeInitializedOnMainThread(this); }
diff --git a/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureImpl.h b/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureImpl.h
index 8b4240876..987b298a3 100644
--- a/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureImpl.h
+++ b/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureImpl.h
@@ -95,6 +95,12 @@ void GlobalObject::initGeneratedLazyClasses() {
init.setStructure(WebCore::JSMatchedRoute::createStructure(init.vm, init.global, init.prototype));
});
+ m_JSPostgresSQLDatabase.initLater(
+ [](LazyClassStructure::Initializer& init) {
+ init.setPrototype(WebCore::JSPostgresSQLDatabase::createPrototype(init.vm, reinterpret_cast<Zig::GlobalObject*>(init.global)));
+ init.setStructure(WebCore::JSPostgresSQLDatabase::createStructure(init.vm, init.global, init.prototype));
+
+ });
m_JSExpect.initLater(
[](LazyClassStructure::Initializer& init) {
init.setPrototype(WebCore::JSExpect::createPrototype(init.vm, reinterpret_cast<Zig::GlobalObject*>(init.global)));
@@ -157,6 +163,7 @@ void GlobalObject::visitGeneratedLazyClasses(GlobalObject *thisObject, Visitor&
thisObject->m_JSServerWebSocket.visit(visitor); visitor.append(thisObject->m_JSServerWebSocketSetterValue);
thisObject->m_JSFileSystemRouter.visit(visitor); visitor.append(thisObject->m_JSFileSystemRouterSetterValue);
thisObject->m_JSMatchedRoute.visit(visitor); visitor.append(thisObject->m_JSMatchedRouteSetterValue);
+ thisObject->m_JSPostgresSQLDatabase.visit(visitor); visitor.append(thisObject->m_JSPostgresSQLDatabaseSetterValue);
thisObject->m_JSExpect.visit(visitor); visitor.append(thisObject->m_JSExpectSetterValue);
thisObject->m_JSTextDecoder.visit(visitor); visitor.append(thisObject->m_JSTextDecoderSetterValue);
thisObject->m_JSRequest.visit(visitor); visitor.append(thisObject->m_JSRequestSetterValue);
diff --git a/src/bun.js/bindings/ZigGeneratedClasses.cpp b/src/bun.js/bindings/ZigGeneratedClasses.cpp
index b649229d4..cf7bb2603 100644
--- a/src/bun.js/bindings/ZigGeneratedClasses.cpp
+++ b/src/bun.js/bindings/ZigGeneratedClasses.cpp
@@ -6243,6 +6243,322 @@ void JSMatchedRoute::visitOutputConstraintsImpl(JSCell* cell, Visitor& visitor)
}
DEFINE_VISIT_OUTPUT_CONSTRAINTS(JSMatchedRoute);
+class JSPostgresSQLDatabasePrototype final : public JSC::JSNonFinalObject {
+public:
+ using Base = JSC::JSNonFinalObject;
+
+ static JSPostgresSQLDatabasePrototype* create(JSC::VM& vm, JSGlobalObject* globalObject, JSC::Structure* structure)
+ {
+ JSPostgresSQLDatabasePrototype* ptr = new (NotNull, JSC::allocateCell<JSPostgresSQLDatabasePrototype>(vm)) JSPostgresSQLDatabasePrototype(vm, globalObject, structure);
+ ptr->finishCreation(vm, globalObject);
+ return ptr;
+ }
+
+ DECLARE_INFO;
+ template<typename CellType, JSC::SubspaceAccess>
+ static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
+ {
+ return &vm.plainObjectSpace();
+ }
+ static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
+ {
+ return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());
+ }
+
+private:
+ JSPostgresSQLDatabasePrototype(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure)
+ : Base(vm, structure)
+ {
+ }
+
+ void finishCreation(JSC::VM&, JSC::JSGlobalObject*);
+};
+
+extern "C" void PostgresSQLDatabaseClass__finalize(void*);
+
+extern "C" EncodedJSValue PostgresSQLDatabasePrototype__close(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame);
+JSC_DECLARE_HOST_FUNCTION(PostgresSQLDatabasePrototype__closeCallback);
+
+extern "C" EncodedJSValue PostgresSQLDatabasePrototype__query(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame);
+JSC_DECLARE_HOST_FUNCTION(PostgresSQLDatabasePrototype__queryCallback);
+
+extern "C" EncodedJSValue PostgresSQLDatabasePrototype__ref(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame);
+JSC_DECLARE_HOST_FUNCTION(PostgresSQLDatabasePrototype__refCallback);
+
+extern "C" EncodedJSValue PostgresSQLDatabasePrototype__unref(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame);
+JSC_DECLARE_HOST_FUNCTION(PostgresSQLDatabasePrototype__unrefCallback);
+
+STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSPostgresSQLDatabasePrototype, JSPostgresSQLDatabasePrototype::Base);
+
+static const HashTableValue JSPostgresSQLDatabasePrototypeTableValues[] = {
+ { "close"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, PostgresSQLDatabasePrototype__closeCallback, 0 } },
+ { "query"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, PostgresSQLDatabasePrototype__queryCallback, 4 } },
+ { "ref"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, PostgresSQLDatabasePrototype__refCallback, 0 } },
+ { "unref"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, PostgresSQLDatabasePrototype__unrefCallback, 0 } }
+};
+
+const ClassInfo JSPostgresSQLDatabasePrototype::s_info = { "PostgresSQLDatabase"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSPostgresSQLDatabasePrototype) };
+
+JSC_DEFINE_HOST_FUNCTION(PostgresSQLDatabasePrototype__closeCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
+{
+ auto& vm = lexicalGlobalObject->vm();
+
+ JSPostgresSQLDatabase* thisObject = jsDynamicCast<JSPostgresSQLDatabase*>(callFrame->thisValue());
+
+ if (UNLIKELY(!thisObject)) {
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ return throwVMTypeError(lexicalGlobalObject, throwScope);
+ }
+
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+
+ return PostgresSQLDatabasePrototype__close(thisObject->wrapped(), lexicalGlobalObject, callFrame);
+}
+
+JSC_DEFINE_HOST_FUNCTION(PostgresSQLDatabasePrototype__queryCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
+{
+ auto& vm = lexicalGlobalObject->vm();
+
+ JSPostgresSQLDatabase* thisObject = jsDynamicCast<JSPostgresSQLDatabase*>(callFrame->thisValue());
+
+ if (UNLIKELY(!thisObject)) {
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ return throwVMTypeError(lexicalGlobalObject, throwScope);
+ }
+
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+
+ return PostgresSQLDatabasePrototype__query(thisObject->wrapped(), lexicalGlobalObject, callFrame);
+}
+
+JSC_DEFINE_HOST_FUNCTION(PostgresSQLDatabasePrototype__refCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
+{
+ auto& vm = lexicalGlobalObject->vm();
+
+ JSPostgresSQLDatabase* thisObject = jsDynamicCast<JSPostgresSQLDatabase*>(callFrame->thisValue());
+
+ if (UNLIKELY(!thisObject)) {
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ return throwVMTypeError(lexicalGlobalObject, throwScope);
+ }
+
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+
+ return PostgresSQLDatabasePrototype__ref(thisObject->wrapped(), lexicalGlobalObject, callFrame);
+}
+
+JSC_DEFINE_HOST_FUNCTION(PostgresSQLDatabasePrototype__unrefCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
+{
+ auto& vm = lexicalGlobalObject->vm();
+
+ JSPostgresSQLDatabase* thisObject = jsDynamicCast<JSPostgresSQLDatabase*>(callFrame->thisValue());
+
+ if (UNLIKELY(!thisObject)) {
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ return throwVMTypeError(lexicalGlobalObject, throwScope);
+ }
+
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+
+ return PostgresSQLDatabasePrototype__unref(thisObject->wrapped(), lexicalGlobalObject, callFrame);
+}
+
+extern "C" void PostgresSQLDatabasePrototype__onCloseSetCachedValue(JSC::EncodedJSValue thisValue, JSC::JSGlobalObject* globalObject, JSC::EncodedJSValue value)
+{
+ auto& vm = globalObject->vm();
+ auto* thisObject = jsCast<JSPostgresSQLDatabase*>(JSValue::decode(thisValue));
+ thisObject->m_onClose.set(vm, thisObject, JSValue::decode(value));
+}
+
+extern "C" EncodedJSValue PostgresSQLDatabasePrototype__onCloseGetCachedValue(JSC::EncodedJSValue thisValue)
+{
+ auto* thisObject = jsCast<JSPostgresSQLDatabase*>(JSValue::decode(thisValue));
+ return JSValue::encode(thisObject->m_onClose.get());
+}
+
+extern "C" void PostgresSQLDatabasePrototype__onNoticeSetCachedValue(JSC::EncodedJSValue thisValue, JSC::JSGlobalObject* globalObject, JSC::EncodedJSValue value)
+{
+ auto& vm = globalObject->vm();
+ auto* thisObject = jsCast<JSPostgresSQLDatabase*>(JSValue::decode(thisValue));
+ thisObject->m_onNotice.set(vm, thisObject, JSValue::decode(value));
+}
+
+extern "C" EncodedJSValue PostgresSQLDatabasePrototype__onNoticeGetCachedValue(JSC::EncodedJSValue thisValue)
+{
+ auto* thisObject = jsCast<JSPostgresSQLDatabase*>(JSValue::decode(thisValue));
+ return JSValue::encode(thisObject->m_onNotice.get());
+}
+
+extern "C" void PostgresSQLDatabasePrototype__onOpenSetCachedValue(JSC::EncodedJSValue thisValue, JSC::JSGlobalObject* globalObject, JSC::EncodedJSValue value)
+{
+ auto& vm = globalObject->vm();
+ auto* thisObject = jsCast<JSPostgresSQLDatabase*>(JSValue::decode(thisValue));
+ thisObject->m_onOpen.set(vm, thisObject, JSValue::decode(value));
+}
+
+extern "C" EncodedJSValue PostgresSQLDatabasePrototype__onOpenGetCachedValue(JSC::EncodedJSValue thisValue)
+{
+ auto* thisObject = jsCast<JSPostgresSQLDatabase*>(JSValue::decode(thisValue));
+ return JSValue::encode(thisObject->m_onOpen.get());
+}
+
+extern "C" void PostgresSQLDatabasePrototype__onTimeoutSetCachedValue(JSC::EncodedJSValue thisValue, JSC::JSGlobalObject* globalObject, JSC::EncodedJSValue value)
+{
+ auto& vm = globalObject->vm();
+ auto* thisObject = jsCast<JSPostgresSQLDatabase*>(JSValue::decode(thisValue));
+ thisObject->m_onTimeout.set(vm, thisObject, JSValue::decode(value));
+}
+
+extern "C" EncodedJSValue PostgresSQLDatabasePrototype__onTimeoutGetCachedValue(JSC::EncodedJSValue thisValue)
+{
+ auto* thisObject = jsCast<JSPostgresSQLDatabase*>(JSValue::decode(thisValue));
+ return JSValue::encode(thisObject->m_onTimeout.get());
+}
+
+extern "C" void PostgresSQLDatabasePrototype__onDrainSetCachedValue(JSC::EncodedJSValue thisValue, JSC::JSGlobalObject* globalObject, JSC::EncodedJSValue value)
+{
+ auto& vm = globalObject->vm();
+ auto* thisObject = jsCast<JSPostgresSQLDatabase*>(JSValue::decode(thisValue));
+ thisObject->m_onDrain.set(vm, thisObject, JSValue::decode(value));
+}
+
+extern "C" EncodedJSValue PostgresSQLDatabasePrototype__onDrainGetCachedValue(JSC::EncodedJSValue thisValue)
+{
+ auto* thisObject = jsCast<JSPostgresSQLDatabase*>(JSValue::decode(thisValue));
+ return JSValue::encode(thisObject->m_onDrain.get());
+}
+
+void JSPostgresSQLDatabasePrototype::finishCreation(JSC::VM& vm, JSC::JSGlobalObject* globalObject)
+{
+ Base::finishCreation(vm);
+ reifyStaticProperties(vm, JSPostgresSQLDatabase::info(), JSPostgresSQLDatabasePrototypeTableValues, *this);
+ JSC_TO_STRING_TAG_WITHOUT_TRANSITION();
+}
+
+extern "C" bool PostgresSQLDatabase__hasPendingActivity(void* ptr);
+bool JSPostgresSQLDatabase::hasPendingActivity(void* ctx)
+{
+ return PostgresSQLDatabase__hasPendingActivity(ctx);
+}
+
+JSPostgresSQLDatabase::~JSPostgresSQLDatabase()
+{
+ if (m_ctx) {
+ PostgresSQLDatabaseClass__finalize(m_ctx);
+ }
+}
+void JSPostgresSQLDatabase::destroy(JSCell* cell)
+{
+ static_cast<JSPostgresSQLDatabase*>(cell)->JSPostgresSQLDatabase::~JSPostgresSQLDatabase();
+}
+
+const ClassInfo JSPostgresSQLDatabase::s_info = { "PostgresSQLDatabase"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSPostgresSQLDatabase) };
+
+void JSPostgresSQLDatabase::finishCreation(VM& vm)
+{
+ Base::finishCreation(vm);
+ ASSERT(inherits(info()));
+}
+
+JSPostgresSQLDatabase* JSPostgresSQLDatabase::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, void* ctx)
+{
+ JSPostgresSQLDatabase* ptr = new (NotNull, JSC::allocateCell<JSPostgresSQLDatabase>(vm)) JSPostgresSQLDatabase(vm, structure, ctx);
+ ptr->finishCreation(vm);
+ return ptr;
+}
+
+extern "C" void* PostgresSQLDatabase__fromJS(JSC::EncodedJSValue value)
+{
+ JSC::JSValue decodedValue = JSC::JSValue::decode(value);
+ if (!decodedValue || decodedValue.isUndefinedOrNull())
+ return nullptr;
+
+ JSPostgresSQLDatabase* object = JSC::jsDynamicCast<JSPostgresSQLDatabase*>(decodedValue);
+
+ if (!object)
+ return nullptr;
+
+ return object->wrapped();
+}
+
+extern "C" bool PostgresSQLDatabase__dangerouslySetPtr(JSC::EncodedJSValue value, void* ptr)
+{
+ JSPostgresSQLDatabase* object = JSC::jsDynamicCast<JSPostgresSQLDatabase*>(JSValue::decode(value));
+ if (!object)
+ return false;
+
+ object->m_ctx = ptr;
+ return true;
+}
+
+extern "C" const size_t PostgresSQLDatabase__ptrOffset = JSPostgresSQLDatabase::offsetOfWrapped();
+
+void JSPostgresSQLDatabase::analyzeHeap(JSCell* cell, HeapAnalyzer& analyzer)
+{
+ auto* thisObject = jsCast<JSPostgresSQLDatabase*>(cell);
+ if (void* wrapped = thisObject->wrapped()) {
+ // if (thisObject->scriptExecutionContext())
+ // analyzer.setLabelForCell(cell, "url " + thisObject->scriptExecutionContext()->url().string());
+ }
+ Base::analyzeHeap(cell, analyzer);
+}
+
+JSObject* JSPostgresSQLDatabase::createPrototype(VM& vm, JSDOMGlobalObject* globalObject)
+{
+ return JSPostgresSQLDatabasePrototype::create(vm, globalObject, JSPostgresSQLDatabasePrototype::createStructure(vm, globalObject, globalObject->objectPrototype()));
+}
+
+extern "C" EncodedJSValue PostgresSQLDatabase__create(Zig::GlobalObject* globalObject, void* ptr)
+{
+ auto& vm = globalObject->vm();
+ JSC::Structure* structure = globalObject->JSPostgresSQLDatabaseStructure();
+ JSPostgresSQLDatabase* instance = JSPostgresSQLDatabase::create(vm, globalObject, structure, ptr);
+
+ return JSValue::encode(instance);
+}
+
+template<typename Visitor>
+void JSPostgresSQLDatabase::visitChildrenImpl(JSCell* cell, Visitor& visitor)
+{
+ JSPostgresSQLDatabase* thisObject = jsCast<JSPostgresSQLDatabase*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+ Base::visitChildren(thisObject, visitor);
+ visitor.append(thisObject->m_onClose);
+ visitor.append(thisObject->m_onNotice);
+ visitor.append(thisObject->m_onOpen);
+ visitor.append(thisObject->m_onTimeout);
+ visitor.append(thisObject->m_onDrain);
+
+ visitor.addOpaqueRoot(thisObject->wrapped());
+}
+
+DEFINE_VISIT_CHILDREN(JSPostgresSQLDatabase);
+
+template<typename Visitor>
+void JSPostgresSQLDatabase::visitAdditionalChildren(Visitor& visitor)
+{
+ JSPostgresSQLDatabase* thisObject = this;
+ ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+ visitor.append(thisObject->m_onClose);
+ visitor.append(thisObject->m_onNotice);
+ visitor.append(thisObject->m_onOpen);
+ visitor.append(thisObject->m_onTimeout);
+ visitor.append(thisObject->m_onDrain);
+
+ visitor.addOpaqueRoot(this->wrapped());
+}
+
+DEFINE_VISIT_ADDITIONAL_CHILDREN(JSPostgresSQLDatabase);
+
+template<typename Visitor>
+void JSPostgresSQLDatabase::visitOutputConstraintsImpl(JSCell* cell, Visitor& visitor)
+{
+ JSPostgresSQLDatabase* thisObject = jsCast<JSPostgresSQLDatabase*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+ thisObject->visitAdditionalChildren<Visitor>(visitor);
+}
+
+DEFINE_VISIT_OUTPUT_CONSTRAINTS(JSPostgresSQLDatabase);
class JSExpectPrototype final : public JSC::JSNonFinalObject {
public:
using Base = JSC::JSNonFinalObject;
diff --git a/src/bun.js/bindings/ZigGeneratedClasses.h b/src/bun.js/bindings/ZigGeneratedClasses.h
index aee32a315..2423c973a 100644
--- a/src/bun.js/bindings/ZigGeneratedClasses.h
+++ b/src/bun.js/bindings/ZigGeneratedClasses.h
@@ -959,6 +959,93 @@ public:
mutable JSC::WriteBarrier<JSC::Unknown> m_scriptSrc;
};
+class JSPostgresSQLDatabase final : public JSC::JSDestructibleObject {
+public:
+ using Base = JSC::JSDestructibleObject;
+ static JSPostgresSQLDatabase* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, void* ctx);
+
+ DECLARE_EXPORT_INFO;
+ template<typename, JSC::SubspaceAccess mode> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
+ {
+ if constexpr (mode == JSC::SubspaceAccess::Concurrently)
+ return nullptr;
+ return WebCore::subspaceForImpl<JSPostgresSQLDatabase, WebCore::UseCustomHeapCellType::No>(
+ vm,
+ [](auto& spaces) { return spaces.m_clientSubspaceForPostgresSQLDatabase.get(); },
+ [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForPostgresSQLDatabase = WTFMove(space); },
+ [](auto& spaces) { return spaces.m_subspaceForPostgresSQLDatabase.get(); },
+ [](auto& spaces, auto&& space) { spaces.m_subspaceForPostgresSQLDatabase = WTFMove(space); });
+ }
+
+ static void destroy(JSC::JSCell*);
+ static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
+ {
+ return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(static_cast<JSC::JSType>(0b11101110), StructureFlags), info());
+ }
+
+ static JSObject* createPrototype(VM& vm, JSDOMGlobalObject* globalObject);
+ ;
+
+ ~JSPostgresSQLDatabase();
+
+ void* wrapped() const { return m_ctx; }
+
+ void detach()
+ {
+ m_ctx = nullptr;
+ }
+
+ static void analyzeHeap(JSCell*, JSC::HeapAnalyzer&);
+ static ptrdiff_t offsetOfWrapped() { return OBJECT_OFFSETOF(JSPostgresSQLDatabase, m_ctx); }
+
+ void* m_ctx { nullptr };
+
+ JSPostgresSQLDatabase(JSC::VM& vm, JSC::Structure* structure, void* sinkPtr)
+ : Base(vm, structure)
+ {
+ m_ctx = sinkPtr;
+ m_weakThis = JSC::Weak<JSPostgresSQLDatabase>(this, getOwner());
+ }
+
+ void finishCreation(JSC::VM&);
+
+ JSC::Weak<JSPostgresSQLDatabase> m_weakThis;
+
+ static bool hasPendingActivity(void* ctx);
+
+ class Owner final : public JSC::WeakHandleOwner {
+ public:
+ bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void* context, JSC::AbstractSlotVisitor& visitor, const char** reason) final
+ {
+ auto* controller = JSC::jsCast<JSPostgresSQLDatabase*>(handle.slot()->asCell());
+ if (JSPostgresSQLDatabase::hasPendingActivity(controller->wrapped())) {
+ if (UNLIKELY(reason))
+ *reason = "has pending activity";
+ return true;
+ }
+
+ return visitor.containsOpaqueRoot(context);
+ }
+ void finalize(JSC::Handle<JSC::Unknown>, void* context) final {}
+ };
+
+ static JSC::WeakHandleOwner* getOwner()
+ {
+ static NeverDestroyed<Owner> m_owner;
+ return &m_owner.get();
+ }
+
+ DECLARE_VISIT_CHILDREN;
+ template<typename Visitor> void visitAdditionalChildren(Visitor&);
+ DECLARE_VISIT_OUTPUT_CONSTRAINTS;
+
+ mutable JSC::WriteBarrier<JSC::Unknown> m_onClose;
+ mutable JSC::WriteBarrier<JSC::Unknown> m_onNotice;
+ mutable JSC::WriteBarrier<JSC::Unknown> m_onOpen;
+ mutable JSC::WriteBarrier<JSC::Unknown> m_onTimeout;
+ mutable JSC::WriteBarrier<JSC::Unknown> m_onDrain;
+};
+
class JSExpect final : public JSC::JSDestructibleObject {
public:
using Base = JSC::JSDestructibleObject;
diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp
index d8593a9fa..e5b55f177 100644
--- a/src/bun.js/bindings/ZigGlobalObject.cpp
+++ b/src/bun.js/bindings/ZigGlobalObject.cpp
@@ -1080,6 +1080,8 @@ enum ReadableStreamTag : int32_t {
Bytes = 4,
};
+extern "C" EncodedJSValue Bun__PostgreSQL__connect(JSGlobalObject*, CallFrame*);
+
// we're trying out a new way to do this lazy loading
static JSC_DEFINE_HOST_FUNCTION(functionLazyLoad,
(JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame))
@@ -1099,6 +1101,7 @@ JSC:
static NeverDestroyed<const String> bunStreamString(MAKE_STATIC_STRING_IMPL("bun:stream"));
static NeverDestroyed<const String> noopString(MAKE_STATIC_STRING_IMPL("noop"));
static NeverDestroyed<const String> createImportMeta(MAKE_STATIC_STRING_IMPL("createImportMeta"));
+ static NeverDestroyed<const String> bunSql(MAKE_STATIC_STRING_IMPL("bun:sql"));
JSC::JSValue moduleName = callFrame->argument(0);
if (moduleName.isNumber()) {
@@ -1154,6 +1157,11 @@ JSC:
JSFunction::create(vm, globalObject, 1, fileURLToPathString, functionFileURLToPath, ImplementationVisibility::Public, NoIntrinsic));
}
+ if (string == bunSql) {
+ return JSC::JSValue::encode(
+ JSFunction::create(vm, globalObject, 1, bunSql, Bun__PostgreSQL__connect, ImplementationVisibility::Public, NoIntrinsic));
+ }
+
if (string == bunStreamString) {
auto* obj = constructEmptyObject(globalObject);
obj->putDirect(vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "BufferList"_s)), reinterpret_cast<Zig::GlobalObject*>(globalObject)->JSBufferList(), 0);
diff --git a/src/bun.js/bindings/bindings.zig b/src/bun.js/bindings/bindings.zig
index 942d4b4f1..d11e30498 100644
--- a/src/bun.js/bindings/bindings.zig
+++ b/src/bun.js/bindings/bindings.zig
@@ -2030,7 +2030,7 @@ pub const JSGlobalObject = extern struct {
}
pub fn createErrorInstance(this: *JSGlobalObject, comptime fmt: string, args: anytype) JSValue {
- if (comptime std.meta.fieldNames(@TypeOf(args)).len > 0) {
+ if (comptime std.meta.fields(@TypeOf(args)).len > 0) {
var stack_fallback = std.heap.stackFallback(1024 * 4, this.allocator());
var buf = bun.MutableString.init2048(stack_fallback.get()) catch unreachable;
defer buf.deinit();
@@ -2077,11 +2077,19 @@ pub const JSGlobalObject = extern struct {
err: anyerror,
comptime fmt: string,
) void {
- var str = ZigString.init(std.fmt.allocPrint(this.bunVM().allocator, "{s} " ++ fmt, .{@errorName(err)}) catch return);
+ this.vm().throwError(this, this.createError(err, fmt));
+ }
+
+ pub fn createError(
+ this: *JSGlobalObject,
+ err: anyerror,
+ comptime fmt: string,
+ ) JSValue {
+ var str = ZigString.init(std.fmt.allocPrint(this.bunVM().allocator, "{s} " ++ fmt, .{@errorName(err)}) catch return ZigString.static("error").toErrorInstance(this));
str.markUTF8();
- var err_value = str.toErrorInstance(this);
- this.vm().throwError(this, err_value);
+ const instance = str.toErrorInstance(this);
this.bunVM().allocator.free(ZigString.untagged(str.ptr)[0..str.len]);
+ return instance;
}
pub fn handleError(
diff --git a/src/bun.js/bindings/generated_classes.zig b/src/bun.js/bindings/generated_classes.zig
index c64acbef5..d2d61d549 100644
--- a/src/bun.js/bindings/generated_classes.zig
+++ b/src/bun.js/bindings/generated_classes.zig
@@ -1970,6 +1970,185 @@ pub const JSMatchedRoute = struct {
}
}
};
+pub const JSPostgresSQLDatabase = struct {
+ const PostgresSQLDatabase = Classes.PostgresSQLDatabase;
+ const GetterType = fn (*PostgresSQLDatabase, *JSC.JSGlobalObject) callconv(.C) JSC.JSValue;
+ const GetterTypeWithThisValue = fn (*PostgresSQLDatabase, JSC.JSValue, *JSC.JSGlobalObject) callconv(.C) JSC.JSValue;
+ const SetterType = fn (*PostgresSQLDatabase, *JSC.JSGlobalObject, JSC.JSValue) callconv(.C) bool;
+ const SetterTypeWithThisValue = fn (*PostgresSQLDatabase, JSC.JSValue, *JSC.JSGlobalObject, JSC.JSValue) callconv(.C) bool;
+ const CallbackType = fn (*PostgresSQLDatabase, *JSC.JSGlobalObject, *JSC.CallFrame) callconv(.C) JSC.JSValue;
+
+ /// Return the pointer to the wrapped object.
+ /// If the object does not match the type, return null.
+ pub fn fromJS(value: JSC.JSValue) ?*PostgresSQLDatabase {
+ JSC.markBinding(@src());
+ return PostgresSQLDatabase__fromJS(value);
+ }
+
+ extern fn PostgresSQLDatabasePrototype__onCloseSetCachedValue(JSC.JSValue, *JSC.JSGlobalObject, JSC.JSValue) void;
+
+ extern fn PostgresSQLDatabasePrototype__onCloseGetCachedValue(JSC.JSValue) JSC.JSValue;
+
+ /// `PostgresSQLDatabase.onClose` setter
+ /// This value will be visited by the garbage collector.
+ pub fn onCloseSetCached(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void {
+ JSC.markBinding(@src());
+ PostgresSQLDatabasePrototype__onCloseSetCachedValue(thisValue, globalObject, value);
+ }
+
+ /// `PostgresSQLDatabase.onClose` getter
+ /// This value will be visited by the garbage collector.
+ pub fn onCloseGetCached(thisValue: JSC.JSValue) ?JSC.JSValue {
+ JSC.markBinding(@src());
+ const result = PostgresSQLDatabasePrototype__onCloseGetCachedValue(thisValue);
+ if (result == .zero)
+ return null;
+
+ return result;
+ }
+
+ extern fn PostgresSQLDatabasePrototype__onNoticeSetCachedValue(JSC.JSValue, *JSC.JSGlobalObject, JSC.JSValue) void;
+
+ extern fn PostgresSQLDatabasePrototype__onNoticeGetCachedValue(JSC.JSValue) JSC.JSValue;
+
+ /// `PostgresSQLDatabase.onNotice` setter
+ /// This value will be visited by the garbage collector.
+ pub fn onNoticeSetCached(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void {
+ JSC.markBinding(@src());
+ PostgresSQLDatabasePrototype__onNoticeSetCachedValue(thisValue, globalObject, value);
+ }
+
+ /// `PostgresSQLDatabase.onNotice` getter
+ /// This value will be visited by the garbage collector.
+ pub fn onNoticeGetCached(thisValue: JSC.JSValue) ?JSC.JSValue {
+ JSC.markBinding(@src());
+ const result = PostgresSQLDatabasePrototype__onNoticeGetCachedValue(thisValue);
+ if (result == .zero)
+ return null;
+
+ return result;
+ }
+
+ extern fn PostgresSQLDatabasePrototype__onOpenSetCachedValue(JSC.JSValue, *JSC.JSGlobalObject, JSC.JSValue) void;
+
+ extern fn PostgresSQLDatabasePrototype__onOpenGetCachedValue(JSC.JSValue) JSC.JSValue;
+
+ /// `PostgresSQLDatabase.onOpen` setter
+ /// This value will be visited by the garbage collector.
+ pub fn onOpenSetCached(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void {
+ JSC.markBinding(@src());
+ PostgresSQLDatabasePrototype__onOpenSetCachedValue(thisValue, globalObject, value);
+ }
+
+ /// `PostgresSQLDatabase.onOpen` getter
+ /// This value will be visited by the garbage collector.
+ pub fn onOpenGetCached(thisValue: JSC.JSValue) ?JSC.JSValue {
+ JSC.markBinding(@src());
+ const result = PostgresSQLDatabasePrototype__onOpenGetCachedValue(thisValue);
+ if (result == .zero)
+ return null;
+
+ return result;
+ }
+
+ extern fn PostgresSQLDatabasePrototype__onTimeoutSetCachedValue(JSC.JSValue, *JSC.JSGlobalObject, JSC.JSValue) void;
+
+ extern fn PostgresSQLDatabasePrototype__onTimeoutGetCachedValue(JSC.JSValue) JSC.JSValue;
+
+ /// `PostgresSQLDatabase.onTimeout` setter
+ /// This value will be visited by the garbage collector.
+ pub fn onTimeoutSetCached(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void {
+ JSC.markBinding(@src());
+ PostgresSQLDatabasePrototype__onTimeoutSetCachedValue(thisValue, globalObject, value);
+ }
+
+ /// `PostgresSQLDatabase.onTimeout` getter
+ /// This value will be visited by the garbage collector.
+ pub fn onTimeoutGetCached(thisValue: JSC.JSValue) ?JSC.JSValue {
+ JSC.markBinding(@src());
+ const result = PostgresSQLDatabasePrototype__onTimeoutGetCachedValue(thisValue);
+ if (result == .zero)
+ return null;
+
+ return result;
+ }
+
+ extern fn PostgresSQLDatabasePrototype__onDrainSetCachedValue(JSC.JSValue, *JSC.JSGlobalObject, JSC.JSValue) void;
+
+ extern fn PostgresSQLDatabasePrototype__onDrainGetCachedValue(JSC.JSValue) JSC.JSValue;
+
+ /// `PostgresSQLDatabase.onDrain` setter
+ /// This value will be visited by the garbage collector.
+ pub fn onDrainSetCached(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void {
+ JSC.markBinding(@src());
+ PostgresSQLDatabasePrototype__onDrainSetCachedValue(thisValue, globalObject, value);
+ }
+
+ /// `PostgresSQLDatabase.onDrain` getter
+ /// This value will be visited by the garbage collector.
+ pub fn onDrainGetCached(thisValue: JSC.JSValue) ?JSC.JSValue {
+ JSC.markBinding(@src());
+ const result = PostgresSQLDatabasePrototype__onDrainGetCachedValue(thisValue);
+ if (result == .zero)
+ return null;
+
+ return result;
+ }
+
+ /// Create a new instance of PostgresSQLDatabase
+ pub fn toJS(this: *PostgresSQLDatabase, globalObject: *JSC.JSGlobalObject) JSC.JSValue {
+ JSC.markBinding(@src());
+ if (comptime Environment.allow_assert) {
+ const value__ = PostgresSQLDatabase__create(globalObject, this);
+ std.debug.assert(value__.as(PostgresSQLDatabase).? == this); // If this fails, likely a C ABI issue.
+ return value__;
+ } else {
+ return PostgresSQLDatabase__create(globalObject, this);
+ }
+ }
+
+ /// Modify the internal ptr to point to a new instance of PostgresSQLDatabase.
+ pub fn dangerouslySetPtr(value: JSC.JSValue, ptr: ?*PostgresSQLDatabase) bool {
+ JSC.markBinding(@src());
+ return PostgresSQLDatabase__dangerouslySetPtr(value, ptr);
+ }
+
+ /// Detach the ptr from the thisValue
+ pub fn detachPtr(_: *PostgresSQLDatabase, value: JSC.JSValue) void {
+ JSC.markBinding(@src());
+ std.debug.assert(PostgresSQLDatabase__dangerouslySetPtr(value, null));
+ }
+
+ extern fn PostgresSQLDatabase__fromJS(JSC.JSValue) ?*PostgresSQLDatabase;
+ extern fn PostgresSQLDatabase__getConstructor(*JSC.JSGlobalObject) JSC.JSValue;
+
+ extern fn PostgresSQLDatabase__create(globalObject: *JSC.JSGlobalObject, ptr: ?*PostgresSQLDatabase) JSC.JSValue;
+
+ extern fn PostgresSQLDatabase__dangerouslySetPtr(JSC.JSValue, ?*PostgresSQLDatabase) bool;
+
+ comptime {
+ if (@TypeOf(PostgresSQLDatabase.finalize) != (fn (*PostgresSQLDatabase) callconv(.C) void)) {
+ @compileLog("PostgresSQLDatabase.finalize is not a finalizer");
+ }
+
+ if (@TypeOf(PostgresSQLDatabase.close) != CallbackType)
+ @compileLog("Expected PostgresSQLDatabase.close to be a callback but received " ++ @typeName(@TypeOf(PostgresSQLDatabase.close)));
+ if (@TypeOf(PostgresSQLDatabase.query) != CallbackType)
+ @compileLog("Expected PostgresSQLDatabase.query to be a callback but received " ++ @typeName(@TypeOf(PostgresSQLDatabase.query)));
+ if (@TypeOf(PostgresSQLDatabase.ref) != CallbackType)
+ @compileLog("Expected PostgresSQLDatabase.ref to be a callback but received " ++ @typeName(@TypeOf(PostgresSQLDatabase.ref)));
+ if (@TypeOf(PostgresSQLDatabase.unref) != CallbackType)
+ @compileLog("Expected PostgresSQLDatabase.unref to be a callback but received " ++ @typeName(@TypeOf(PostgresSQLDatabase.unref)));
+ if (!JSC.is_bindgen) {
+ @export(PostgresSQLDatabase.close, .{ .name = "PostgresSQLDatabasePrototype__close" });
+ @export(PostgresSQLDatabase.finalize, .{ .name = "PostgresSQLDatabaseClass__finalize" });
+ @export(PostgresSQLDatabase.hasPendingActivity, .{ .name = "PostgresSQLDatabase__hasPendingActivity" });
+ @export(PostgresSQLDatabase.query, .{ .name = "PostgresSQLDatabasePrototype__query" });
+ @export(PostgresSQLDatabase.ref, .{ .name = "PostgresSQLDatabasePrototype__ref" });
+ @export(PostgresSQLDatabase.unref, .{ .name = "PostgresSQLDatabasePrototype__unref" });
+ }
+ }
+};
pub const JSExpect = struct {
const Expect = Classes.Expect;
const GetterType = fn (*Expect, *JSC.JSGlobalObject) callconv(.C) JSC.JSValue;
@@ -3306,6 +3485,7 @@ comptime {
_ = JSServerWebSocket;
_ = JSFileSystemRouter;
_ = JSMatchedRoute;
+ _ = JSPostgresSQLDatabase;
_ = JSExpect;
_ = JSTextDecoder;
_ = JSRequest;
diff --git a/src/bun.js/bindings/generated_classes_list.zig b/src/bun.js/bindings/generated_classes_list.zig
index 2eaf30e04..f5ae68260 100644
--- a/src/bun.js/bindings/generated_classes_list.zig
+++ b/src/bun.js/bindings/generated_classes_list.zig
@@ -24,4 +24,5 @@ pub const Classes = struct {
pub const MatchedRoute = JSC.API.MatchedRoute;
pub const Dirent = JSC.Node.Dirent;
pub const NodeJSFS = JSC.Node.NodeJSFS;
+ pub const PostgresSQLDatabase = JSC.API.Bun.PostgresSQLDatabase;
};
diff --git a/src/bun.js/module_loader.zig b/src/bun.js/module_loader.zig
index cf433414f..a0ba0219b 100644
--- a/src/bun.js/module_loader.zig
+++ b/src/bun.js/module_loader.zig
@@ -1593,6 +1593,15 @@ pub const ModuleLoader = struct {
.hash = 0,
};
},
+ .@"bun:sql" => {
+ return ResolvedSource{
+ .allocator = null,
+ .source_code = ZigString.init(jsModuleFromFile(jsc_vm.load_builtins_from_path, "sql.exports.js")),
+ .specifier = ZigString.init("bun:sql"),
+ .source_url = ZigString.init("bun:sql"),
+ .hash = 0,
+ };
+ },
.@"node:fs" => {
if (comptime Environment.isDebug) {
return ResolvedSource{
@@ -1977,6 +1986,7 @@ pub const HardcodedModule = enum {
@"bun:ffi",
@"bun:jsc",
@"bun:main",
+ @"bun:sql",
@"bun:sqlite",
@"detect-libc",
@"node:assert",
@@ -2020,6 +2030,7 @@ pub const HardcodedModule = enum {
.{ "bun:ffi", HardcodedModule.@"bun:ffi" },
.{ "bun:jsc", HardcodedModule.@"bun:jsc" },
.{ "bun:main", HardcodedModule.@"bun:main" },
+ .{ "bun:sql", HardcodedModule.@"bun:sql" },
.{ "bun:sqlite", HardcodedModule.@"bun:sqlite" },
.{ "depd", HardcodedModule.depd },
.{ "detect-libc", HardcodedModule.@"detect-libc" },
@@ -2062,6 +2073,7 @@ pub const HardcodedModule = enum {
.{ "bun", "bun" },
.{ "bun:ffi", "bun:ffi" },
.{ "bun:jsc", "bun:jsc" },
+ .{ "bun:sql", "bun:sql" },
.{ "bun:sqlite", "bun:sqlite" },
.{ "bun:wrap", "bun:wrap" },
.{ "child_process", "node:child_process" },
diff --git a/src/bun.js/postgres/postgres.exports.js b/src/bun.js/postgres/postgres.exports.js
new file mode 100644
index 000000000..beae64f24
--- /dev/null
+++ b/src/bun.js/postgres/postgres.exports.js
@@ -0,0 +1,8 @@
+var symbolFor = Symbol.for;
+
+const lazy = globalThis[symbolFor("Bun.lazy")];
+if (!lazy || typeof lazy !== "function") {
+ throw new Error(
+ "Something went wrong while loading Bun. Expected 'Bun.lazy' to be defined.",
+ );
+}
diff --git a/src/bun.js/rare_data.zig b/src/bun.js/rare_data.zig
index 4f760c0d6..b63db1d17 100644
--- a/src/bun.js/rare_data.zig
+++ b/src/bun.js/rare_data.zig
@@ -25,6 +25,8 @@ cleanup_hook: ?*CleanupHook = null,
file_polls_: ?*JSC.FilePoll.HiveArray = null,
+postgres_data: bun.JSC.API.Bun.PostgresData = .{},
+
pub fn filePolls(this: *RareData, vm: *JSC.VirtualMachine) *JSC.FilePoll.HiveArray {
return this.file_polls_ orelse {
this.file_polls_ = vm.allocator.create(JSC.FilePoll.HiveArray) catch unreachable;
diff --git a/src/bun.js/sql.exports.js b/src/bun.js/sql.exports.js
new file mode 100644
index 000000000..9f878ac2d
--- /dev/null
+++ b/src/bun.js/sql.exports.js
@@ -0,0 +1,436 @@
+var symbolFor = Symbol.for;
+
+const lazy = globalThis[symbolFor("Bun.lazy")];
+if (!lazy || typeof lazy !== "function") {
+ throw new Error(
+ "Something went wrong while loading Bun. Expected 'Bun.lazy' to be defined.",
+ );
+}
+
+var defineProperties = Object.defineProperties;
+const { createFIFO } = import.meta.primordials;
+
+var nativeConnect = lazy("bun:sql");
+
+export class SQL extends Promise {
+ #connection;
+
+ active = false;
+ #executed = false;
+ #resolve;
+ #reject;
+ #query;
+
+ get executed() {
+ return this.#executed;
+ }
+
+ constructor(connection, query) {
+ let resolve, reject;
+ super((resolve1, reject1) => {
+ resolve = resolve1;
+ reject = reject1;
+ });
+ this.#resolve = resolve;
+ this.#reject = reject;
+ this.#connection = connection;
+ this.#query = query;
+ }
+
+ static get [Symbol.species]() {
+ return Promise;
+ }
+
+ async #handle() {
+ if (this.#executed) {
+ return;
+ }
+
+ this.#executed = true;
+ var resolve = this.#resolve,
+ reject = this.#reject,
+ query = this.#query,
+ connection = this.#connection;
+ this.#reject = this.#resolve = this.#query = this.#connection = undefined;
+ connection.query(query, resolve, reject);
+ }
+
+ then() {
+ this.#handle();
+ return super.then.apply(this, arguments);
+ }
+
+ catch() {
+ this.#handle();
+ return super.catch.apply(this, arguments);
+ }
+
+ finally() {
+ this.#handle();
+ return super.finally.apply(this, arguments);
+ }
+}
+
+const readyStateConnecting = 0,
+ readyStateConnected = 1,
+ readyStateClosed = 2;
+
+const IS_DEBUG = Bun.version.includes("_debug");
+const connectionInternalTag = Symbol("connectionInternalTag");
+
+export class Connection {
+ #handle = undefined;
+ #hostIndex = 0;
+ host;
+ port;
+
+ #queue = createFIFO();
+ query;
+ #options;
+ #closeRequested = false;
+ #needsDrain = false;
+ #readyState;
+
+ constructor(options, internalTag) {
+ if (!IS_DEBUG && internalTag !== connectionInternalTag)
+ throw new Error("Cannot instantiate Connection directly");
+
+ this.#options = options;
+ this.host = options.host;
+ this.port = options.port;
+ this.#hostIndex = 0;
+ this.query = this.#queryEnqueue;
+ this.#closeRequested = false;
+
+ this.#connect(options);
+ }
+
+ get options() {
+ return this.#options;
+ }
+
+ #onClose(code) {
+ this.#updateReadyState(readyStateClosed);
+
+ var { onClose } = this.#options;
+ if (onClose) onClose(code);
+ }
+ #onNotice(notice) {}
+
+ // can be called before onOpen returns
+ #onOpen(handle) {
+ if (this.#handle !== handle) {
+ if (this.#handle) {
+ throw new Error("Internal error: handle mismatch");
+ }
+
+ this.#handle = handle;
+ }
+ this.#updateReadyState(readyStateConnected);
+
+ var { onOpen } = this.#options;
+ if (onOpen) onOpen(this);
+ }
+
+ #onTimeout() {
+ this.#updateReadyState(readyStateClosed);
+
+ var { onTimeout, onClose } = this.#options;
+ if (onTimeout) onTimeout();
+ else if (onClose) onClose("ERR_TIMEOUT");
+ }
+
+ #updateReadyState(readyState) {
+ this.#readyState = readyState;
+ switch (readyState) {
+ case readyStateClosed: {
+ this.#handle = undefined;
+ this.query = this.#queryEnqueueAndConnect;
+ break;
+ }
+ case readyStateConnected: {
+ this.query = this.#query;
+ break;
+ }
+ case readyStateConnecting: {
+ this.query = this.#queryEnqueue;
+ break;
+ }
+ }
+ }
+
+ #connect(options) {
+ this.#hostIndex = 0;
+
+ const handlers = {
+ onClose: (code) => this.#onClose(code),
+ onNotice: (notice) => this.#onNotice(notice),
+ onOpen: (handle) => this.#onOpen(handle),
+ onTimeout: () => this.#onTimeout(),
+ onDrain: () => this.#onDrain(),
+ };
+
+ const host = this.host,
+ hostCount = host.length,
+ port = this.port;
+ do {
+ try {
+ const hostIndex = this.#hostIndex;
+ this.#hostIndex = (this.#hostIndex + 1) % hostCount;
+
+ if (options.path) {
+ this.#handle = nativeConnect({
+ host: host[hostIndex],
+ port: port[hostIndex],
+ database: options.database,
+ user: options.user,
+ pass: options.pass,
+ path: options.path,
+ ...handlers,
+ });
+ } else {
+ this.#handle = nativeConnect({
+ host: host[hostIndex],
+ port: port[hostIndex],
+ database: options.database,
+ user: options.user,
+ pass: options.pass,
+ ...handlers,
+ });
+ }
+ } catch (e) {
+ if (e?.code !== "ERR_UNAVAILABLE") throw e;
+ }
+ } while (this.#hostIndex !== 0);
+ }
+
+ #queryEnqueueAndConnect(query, resolve, reject) {
+ this.#queue.push({ 0: query, 1: resolve, 2: reject });
+ this.#connect(this.#options);
+ }
+
+ // must be called from connecting state
+ #queryEnqueue(sql, resolve, reject) {
+ this.#queue.push({ 0: sql, 1: resolve, 2: reject });
+ }
+
+ #query(sql, resolve, reject) {
+ var queue = this.#queue;
+ if (!queue.isEmpty() || this.#needsDrain) {
+ queue.push({ 0: sql, 1: resolve, 2: reject });
+ return;
+ }
+
+ this.#needsDrain = this.#handle.query(sql, resolve, reject, false);
+ }
+
+ #onDrain() {
+ var queue = this.#queue,
+ remaining = queue.size(),
+ hasMore = remaining > 0,
+ canSendMore = false,
+ handle = this.#handle;
+
+ if (hasMore && handle) {
+ let sql, resolve, reject;
+ while (
+ (({ 0: sql, 1: resolve, 2: reject } = queue.shift()),
+ (hasMore = canSendMore =
+ handle.query(sql, resolve, reject, (hasMore = remaining-- > 1))),
+ hasMore)
+ ) {}
+ this.#needsDrain = !canSendMore;
+ } else {
+ this.#needsDrain = false;
+ }
+ }
+
+ ref() {
+ this.#handle?.ref?.();
+ }
+
+ unref() {
+ this.#handle?.unref?.();
+ }
+
+ close(force = false) {
+ var handle = this.#handle;
+ if (
+ !handle ||
+ this.#readyState === readyStateClosed ||
+ this.#closeRequested
+ )
+ return;
+ this.#closeRequested = true;
+
+ if (force || this.#queue.isEmpty()) {
+ handle.unref();
+ handle.close();
+ }
+ }
+}
+
+function database(a, b) {
+ const options = parseOptions(a, b);
+
+ const connection = new Connection(options);
+
+ function sql(strings, ...args) {
+ const query = strings[0];
+ if (!query || !query.length) {
+ throw new Error("SQL query must not be empty");
+ }
+
+ return new SQL(connection, query);
+ }
+
+ sql.connection = connection;
+ sql.ref = function ref() {
+ this.connection.ref();
+ };
+ sql.unref = function unref() {
+ this.connection.unref();
+ };
+
+ return sql;
+}
+
+// This code is thanks to postgres.js
+function parseOptions(a, b) {
+ if (a && a.shared) return a;
+
+ const env = process.env,
+ o = (typeof a === "string" ? b : a) || {},
+ { url, multihost } = parseUrl(a),
+ query = [...url.searchParams].reduce((a, [b, c]) => ((a[b] = c), a), {}),
+ host =
+ o.hostname ||
+ o.host ||
+ multihost ||
+ url.hostname ||
+ env.PGHOST ||
+ "localhost",
+ port = o.port || url.port || env.PGPORT || 5432,
+ user =
+ o.user ||
+ o.username ||
+ url.username ||
+ env.PGUSERNAME ||
+ env.PGUSER ||
+ osUsername();
+
+ const { protocol } = url;
+ if (
+ protocol &&
+ protocol.length &&
+ protocol !== "file:" &&
+ protocol !== "http:" &&
+ protocol !== "https:" &&
+ protocol !== "pg:" &&
+ protocol !== "pgx:" &&
+ protocol !== "postgres:" &&
+ protocol !== "postgresql:" &&
+ protocol !== "unix:"
+ ) {
+ throw new Error("Only PostgresSQL is supported by bun:sql");
+ }
+
+ o.no_prepare && (o.prepare = false);
+ query.sslmode && ((query.ssl = query.sslmode), delete query.sslmode);
+
+ const defaults = {
+ max: 10,
+ ssl: false,
+ idle_timeout: null,
+ connect_timeout: 30,
+ // max_lifetime: max_lifetime,
+ max_pipeline: 100,
+ // backoff: backoff,
+ keep_alive: 60,
+ prepare: true,
+ debug: false,
+ fetch_types: true,
+ publications: "alltables",
+ target_session_attrs: null,
+ };
+
+ return {
+ host: Array.isArray(host)
+ ? host
+ : host.split(",").map((x) => x.split(":")[0]),
+ port: Array.isArray(port)
+ ? port
+ : host.split(",").map((x) => parseInt(x.split(":")[1] || port)),
+ path: o.path || (host.indexOf("/") > -1 && host + "/.s.PGSQL." + port),
+ database:
+ o.database ||
+ o.db ||
+ (url.pathname || "").slice(1) ||
+ env.PGDATABASE ||
+ user,
+ user: user,
+ pass: o.pass || o.password || url.password || env.PGPASSWORD || "",
+ ...Object.entries(defaults).reduce(
+ (acc, [k, d]) => (
+ (acc[k] =
+ k in o
+ ? o[k]
+ : k in query
+ ? query[k] === "disable" || query[k] === "false"
+ ? false
+ : query[k]
+ : env["PG" + k.toUpperCase()] || d),
+ acc
+ ),
+ {},
+ ),
+ connection: {
+ application_name: "bun:sql",
+ ...o.connection,
+ ...Object.entries(query).reduce(
+ (acc, [k, v]) => (k in defaults || (acc[k] = v), acc),
+ {},
+ ),
+ },
+ onclose: o.onclose,
+ // types: o.types || {},
+ // TODO:
+ // target_session_attrs: tsa(o, url, env),
+ // onnotice: o.onnotice,
+ // onnotify: o.onnotify,
+ // onparameter: o.onparameter,
+
+ // socket: o.socket,
+ // transform: parseTransform(o.transform || { undefined: undefined }),
+ parameters: {},
+ shared: { retries: 0, typeArrayMap: {} },
+ };
+}
+
+function parseUrl(url) {
+ if (typeof url !== "string") return { url: { searchParams: new Map() } };
+
+ let host = url;
+ host = host.slice(host.indexOf("://") + 3).split(/[?/]/)[0];
+ host = decodeURIComponent(host.slice(host.indexOf("@") + 1));
+
+ return {
+ url: new URL(url.replace(host, host.split(",")[0])),
+ multihost: host.indexOf(",") > -1 && host,
+ };
+}
+
+function osUsername() {
+ try {
+ return import.meta.require("node:os").userInfo().username; // eslint-disable-line
+ } catch (_) {
+ return process.env.USERNAME || process.env.USER || process.env.LOGNAME; // eslint-disable-line
+ }
+}
+
+export default database;
+database[Symbol.for("CommonJS")] = 0;
+database.Connection = Connection;
+database.SQL = SQL;
+database.database = database;
+export { database };
diff --git a/src/bun.zig b/src/bun.zig
index 2ea39b2b9..c28457a70 100644
--- a/src/bun.zig
+++ b/src/bun.zig
@@ -756,3 +756,6 @@ pub fn enumMap(comptime T: type, comptime args: anytype) (fn (T) []const u8) {
return Map.get;
}
+
+pub const url = @import("./url.zig");
+pub const URL = url.URL;
diff --git a/src/deps/uws.zig b/src/deps/uws.zig
index 62821c85c..fdb347d09 100644
--- a/src/deps/uws.zig
+++ b/src/deps/uws.zig
@@ -39,10 +39,7 @@ pub fn NewSocketHandler(comptime ssl: bool) type {
return @ptrCast(*NativeSocketHandleType(ssl), us_socket_get_native_handle(comptime ssl_int, this.socket).?);
}
pub fn ext(this: ThisSocket, comptime ContextType: type) ?*ContextType {
- const alignment = if (ContextType == *anyopaque)
- @sizeOf(usize)
- else
- std.meta.alignment(ContextType);
+ const alignment = @sizeOf(usize);
var ptr = us_socket_ext(
comptime ssl_int,
diff --git a/test/bun.js/sql.test.ts b/test/bun.js/sql.test.ts
new file mode 100644
index 000000000..569841d7e
--- /dev/null
+++ b/test/bun.js/sql.test.ts
@@ -0,0 +1,10 @@
+import { expect, it, describe } from "bun:test";
+import { database } from "bun:sql";
+
+it("database", () => {
+ database({
+ host: "localhost",
+ database: "test123",
+ port: 8023,
+ });
+});