diff options
-rw-r--r-- | src/bun.js/bindings/bindings.cpp | 34 | ||||
-rw-r--r-- | src/bun.js/bindings/bindings.zig | 10 | ||||
-rw-r--r-- | src/bun.js/bindings/generated_classes_list.zig | 2 | ||||
-rw-r--r-- | src/bun.js/rare_data.zig | 2 | ||||
-rw-r--r-- | src/js/bun/sql.ts | 21 | ||||
-rw-r--r-- | src/js/out/InternalModuleRegistryConstants.h | 6 | ||||
-rw-r--r-- | src/jsc.zig | 1 | ||||
-rw-r--r-- | src/sql/postgres.zig | 280 |
8 files changed, 308 insertions, 48 deletions
diff --git a/src/bun.js/bindings/bindings.cpp b/src/bun.js/bindings/bindings.cpp index d06e8259e..a61a0221a 100644 --- a/src/bun.js/bindings/bindings.cpp +++ b/src/bun.js/bindings/bindings.cpp @@ -4689,6 +4689,40 @@ extern "C" EncodedJSValue JSC__JSValue__dateInstanceFromNullTerminatedString(JSC return JSValue::encode(date); } +// this is largely copied from dateProtoFuncToISOString +extern "C" int JSC__JSValue__toISOString(JSC::JSGlobalObject* globalObject, EncodedJSValue dateValue, char buffer[28]) +{ + JSC::DateInstance* thisDateObj = JSC::jsDynamicCast<JSC::DateInstance*>(JSC::JSValue::decode(dateValue)); + if (!thisDateObj) + return -1; + + if (!std::isfinite(thisDateObj->internalNumber())) + return -1; + + auto& vm = globalObject->vm(); + + const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(vm.dateCache); + if (!gregorianDateTime) + return -1; + + // If the year is outside the bounds of 0 and 9999 inclusive we want to use the extended year format (ES 15.9.1.15.1). + int ms = static_cast<int>(fmod(thisDateObj->internalNumber(), msPerSecond)); + if (ms < 0) + ms += msPerSecond; + + int charactersWritten; + if (gregorianDateTime->year() > 9999 || gregorianDateTime->year() < 0) + charactersWritten = snprintf(buffer, sizeof(buffer), "%+07d-%02d-%02dT%02d:%02d:%02d.%03dZ", gregorianDateTime->year(), gregorianDateTime->month() + 1, gregorianDateTime->monthDay(), gregorianDateTime->hour(), gregorianDateTime->minute(), gregorianDateTime->second(), ms); + else + charactersWritten = snprintf(buffer, sizeof(buffer), "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", gregorianDateTime->year(), gregorianDateTime->month() + 1, gregorianDateTime->monthDay(), gregorianDateTime->hour(), gregorianDateTime->minute(), gregorianDateTime->second(), ms); + + ASSERT(charactersWritten > 0 && static_cast<unsigned>(charactersWritten) < sizeof(buffer)); + if (static_cast<unsigned>(charactersWritten) >= sizeof(buffer)) + return -1; + + return charactersWritten; +} + #pragma mark - WebCore::DOMFormData CPP_DECL void WebCore__DOMFormData__append(WebCore__DOMFormData* arg0, ZigString* arg1, ZigString* arg2) diff --git a/src/bun.js/bindings/bindings.zig b/src/bun.js/bindings/bindings.zig index e6b218486..278ccd20e 100644 --- a/src/bun.js/bindings/bindings.zig +++ b/src/bun.js/bindings/bindings.zig @@ -3557,6 +3557,16 @@ pub const JSValue = enum(JSValueReprInt) { cppFn("push", .{ value, globalObject, out }); } + extern fn JSC__JSValue__toISOString(*JSC.JSGlobalObject, JSC.JSValue, *[28]u8) c_int; + pub fn toISOString(this: JSValue, globalObject: *JSC.JSGlobalObject, buf: *[28]u8) []const u8 { + const count = JSC__JSValue__toISOString(globalObject, this, buf); + if (count < 0) { + return ""; + } + + return buf[0..@as(usize, @intCast(count))]; + } + pub fn as(value: JSValue, comptime ZigType: type) ?*ZigType { if (value.isEmptyOrUndefinedOrNull()) return null; diff --git a/src/bun.js/bindings/generated_classes_list.zig b/src/bun.js/bindings/generated_classes_list.zig index 3b45f33b8..60b0b08c1 100644 --- a/src/bun.js/bindings/generated_classes_list.zig +++ b/src/bun.js/bindings/generated_classes_list.zig @@ -55,4 +55,6 @@ pub const Classes = struct { pub const DebugHTTPSServer = JSC.API.DebugHTTPSServer; pub const Crypto = JSC.WebCore.Crypto; pub const FFI = JSC.FFI; + pub const PostgresSQLConnection = JSC.Postgres.PostgresSQLConnection; + pub const PostgresSQLQuery = JSC.Postgres.PostgresSQLQuery; }; diff --git a/src/bun.js/rare_data.zig b/src/bun.js/rare_data.zig index c9d742d96..c9890d2dd 100644 --- a/src/bun.js/rare_data.zig +++ b/src/bun.js/rare_data.zig @@ -20,6 +20,8 @@ stderr_store: ?*Blob.Store = null, stdin_store: ?*Blob.Store = null, stdout_store: ?*Blob.Store = null, +postgresql_context: JSC.Postgres.PostgresSQLContext = .{}, + entropy_cache: ?*EntropyCache = null, hot_map: ?HotMap = null, diff --git a/src/js/bun/sql.ts b/src/js/bun/sql.ts index ff2d1b44e..9deed2ecb 100644 --- a/src/js/bun/sql.ts +++ b/src/js/bun/sql.ts @@ -145,15 +145,28 @@ function loadOptions(o) { var hostname, port, username, password, database, tls, url, query, adapter; const env = Bun.env; - if (typeof o === "undefined" || (typeof o === "string" && o?.length === 0)) { + if (typeof o === "undefined" || (typeof o === "string" && o.length === 0)) { const urlString = env.POSTGRES_URL || env.DATABASE_URL || env.PGURL || env.PG_URL; if (urlString) { - o = urlString; + url = new URL(urlString); + o = {}; } + } else if (o && typeof o === "object") { + if (o instanceof URL) { + url = o; + } else if (o?.url) { + const _url = o.url; + if (typeof _url === "string") { + url = new URL(_url); + } else if (_url && typeof _url === "object" && _url instanceof URL) { + url = _url; + } + } + } else if (typeof o === "string") { + url = new URL(o); } - if (typeof o === "string") { - url = new URL(o); + if (url) { ({ hostname, port, username, password, protocol: adapter } = o = url); if (adapter[adapter.length - 1] === ":") { adapter = adapter.slice(0, -1); diff --git a/src/js/out/InternalModuleRegistryConstants.h b/src/js/out/InternalModuleRegistryConstants.h index 73b5b1f49..0814ad631 100644 --- a/src/js/out/InternalModuleRegistryConstants.h +++ b/src/js/out/InternalModuleRegistryConstants.h @@ -10,7 +10,7 @@ static constexpr ASCIILiteral BunFFICode = "(function (){\"use strict\";// src/j // // -static constexpr ASCIILiteral BunSqlCode = "(function (){\"use strict\";// src/js/out/tmp/bun/sql.ts\nvar createConnection = function({ hostname, port, username, password, tls, query }, onConnected, onClose) {\n return new PostgresSQLConnection(hostname, port, username, password, tls, query, onConnected, onClose);\n}, normalizeStrings = function(strings) {\n if (@isJSArray(strings))\n return strings.join(\"\?\");\n return strings + \"\";\n}, loadOptions = function(o) {\n var hostname, port, username, password, database, tls, url, query, adapter;\n const env = Bun.env;\n if (typeof o === \"undefined\" || typeof o === \"string\" && o\?.length === 0) {\n const urlString = env.POSTGRES_URL || env.DATABASE_URL || env.PGURL || env.PG_URL;\n if (urlString)\n o = urlString;\n }\n if (typeof o === \"string\") {\n if (url = new URL(o), { hostname, port, username, password, protocol: adapter } = o = url, adapter[adapter.length - 1] === \":\")\n adapter = adapter.slice(0, -1);\n const queryObject = url.searchParams.toJSON();\n query = \"\";\n for (let key in queryObject)\n query += `${encodeURIComponent(key)}=${encodeURIComponent(queryObject[key])} `;\n query = query.trim();\n }\n if (!o)\n o = {};\n if (hostname ||= o.hostname || o.host || env.PGHOST || \"localhost\", port ||= Number(o.port || env.PGPORT || 5432), username ||= o.username || o.user || env.PGUSERNAME || env.PGUSER || env.USER || env.USERNAME || \"postgres\", database ||= o.database || o.db || (url\?.pathname \?\? \"\").slice(1) || env.PGDATABASE || username, password ||= o.password || o.pass || env.PGPASSWORD || \"\", tls ||= o.tls || o.ssl, adapter ||= o.adapter || \"postgres\", !Number.isSafeInteger(port) || port < 1 || port > 65535)\n throw new Error(`Invalid port: ${port}`);\n if (adapter && !(adapter === \"postgres\" || adapter === \"postgresql\"))\n throw new Error(`Unsupported adapter: ${adapter}. Only \\\"postgres\\\" is supported for now`);\n return { hostname, port, username, password, database, tls, query };\n}, SQL = function(o) {\n var connection, connected = !1, connecting = !1, closed = !1, onConnect = [], connectionInfo = loadOptions(o);\n function connectedHandler(query, handle, err) {\n if (err)\n return query.reject(err);\n if (!connected)\n return query.reject(new Error(\"Not connected\"));\n if (query.cancelled)\n return query.reject(new Error(\"Query cancelled\"));\n handle.run(connection, query);\n }\n function pendingConnectionHandler(query, handle) {\n if (onConnect.push((err) => connectedHandler(query, handle, err)), !connecting)\n connecting = !0, connection = createConnection(connectionInfo, onConnected, onClose);\n }\n function closedConnectionHandler(query, handle) {\n query.reject(new Error(\"Connection closed\"));\n }\n function onConnected(err) {\n connected = !err;\n for (let handler of onConnect)\n handler(err);\n onConnect = [];\n }\n function onClose(err) {\n closed = !0, onConnected(err);\n }\n function connectedSQL(strings, values) {\n return new Query(connection.query(normalizeStrings(strings), values), closedConnectionHandler);\n }\n function closedSQL(strings, values) {\n return new Query(@undefined, closedConnectionHandler);\n }\n function pendingSQL(strings, values) {\n return new Query(new PostgresSQLQuery(normalizeStrings(strings), values), pendingConnectionHandler);\n }\n function sql(strings, ...values) {\n if (closed)\n return closedSQL(strings, values);\n if (connected)\n return connectedSQL(strings, values);\n return pendingSQL(strings, values);\n }\n return sql.connect = () => {\n if (closed)\n return @Promise.reject(new Error(\"Connection closed\"));\n if (connected)\n return @Promise.resolve(sql);\n var { resolve, reject, promise } = @Promise.withResolvers();\n if (onConnect.push((err) => err \? reject(err) : resolve(sql)), !connecting)\n connecting = !0, connection = createConnection(connectionInfo, onConnected, onClose);\n return promise;\n }, sql.close = () => {\n if (closed)\n return @Promise.resolve();\n var { resolve, promise } = @Promise.withResolvers();\n return onConnect.push(resolve), connection.close(), promise;\n }, sql.flush = () => {\n if (closed || !connected)\n return;\n connection.flush();\n }, sql;\n}, queryStatus_active = 1 << 1, queryStatus_cancelled = 1 << 2, queryStatus_error = 1 << 3, queryStatus_executed = 1 << 4;\nvar _resolve = Symbol(\"resolve\"), _reject = Symbol(\"reject\"), _handle = Symbol(\"handle\"), _run = Symbol(\"run\"), _queryStatus = Symbol(\"status\"), _handler = Symbol(\"handler\"), PublicPromise = @Promise, { PostgresSQLConnection, PostgresSQLQuery, PostgresSQLStatement, init } = @lazy(\"bun:sql\");\nclass Query extends PublicPromise {\n [_resolve];\n [_reject];\n [_handle];\n [_handler];\n [_queryStatus] = 0;\n constructor(handle, handler) {\n var resolve_, reject_;\n super((resolve, reject) => {\n resolve_ = resolve, reject_ = reject;\n });\n this[_resolve] = resolve_, this[_reject] = reject_, this[_handle] = handle, this[_handler] = handler, this[_queryStatus] = handle \? 0 : queryStatus_cancelled;\n }\n async[_run]() {\n const { [_handle]: handle, [_handler]: handler, [_queryStatus]: status } = this;\n if (status & (queryStatus_executed | queryStatus_cancelled))\n return;\n return this[_queryStatus] |= queryStatus_executed, await 1, handler(this, handle);\n }\n get active() {\n return (this[_queryStatus] & queryStatus_active) !== 0;\n }\n set active(value) {\n if (this[_queryStatus] & (queryStatus_cancelled | queryStatus_error))\n return;\n if (value)\n this[_queryStatus] |= queryStatus_active;\n else\n this[_queryStatus] &= ~queryStatus_active;\n }\n get cancelled() {\n return (this[_queryStatus] & queryStatus_cancelled) !== 0;\n }\n resolve(x) {\n return this[_queryStatus] &= ~queryStatus_active, this[_resolve](x);\n }\n reject(x) {\n return this[_queryStatus] &= ~queryStatus_active, this[_queryStatus] |= queryStatus_error, this[_resolve](x);\n }\n cancel() {\n var status = this[_queryStatus];\n if (status & queryStatus_cancelled)\n return this;\n if (this[_queryStatus] |= queryStatus_cancelled, status & queryStatus_executed)\n this[_handle].cancel();\n return this;\n }\n execute() {\n return this[_run](), this;\n }\n raw() {\n return this[_handle].raw = 2, this;\n }\n values() {\n return this[_handle].raw = 1, this;\n }\n then() {\n return this[_run](), super.then(...arguments);\n }\n catch() {\n return this[_run](), super.catch(...arguments);\n }\n finally() {\n return this[_run](), super.finally(...arguments);\n }\n}\nObject.defineProperty(Query.prototype, Symbol.species, { value: PublicPromise });\nObject.defineProperty(Query.prototype, Symbol.toStringTag, { value: \"Query\" });\ninit(Query.prototype.resolve, Query.prototype.reject);\nvar lazyDefaultSQL, defaultSQLObject = function sql(strings, ...values) {\n if (!lazyDefaultSQL)\n lazyDefaultSQL = SQL(@undefined), Object.assign(defaultSQLObject, lazyDefaultSQL), exportsObject.default = exportsObject.sql = lazyDefaultSQL;\n return lazyDefaultSQL(strings, ...values);\n}, exportsObject = {\n sql: defaultSQLObject,\n default: defaultSQLObject,\n SQL,\n Query\n};\nreturn exportsObject})\n"_s; +static constexpr ASCIILiteral BunSqlCode = "(function (){\"use strict\";// src/js/out/tmp/bun/sql.ts\nvar createConnection = function({ hostname, port, username, password, tls, query }, onConnected, onClose) {\n return new PostgresSQLConnection(hostname, port, username, password, tls, query, onConnected, onClose);\n}, normalizeStrings = function(strings) {\n if (@isJSArray(strings))\n return strings.join(\"\?\");\n return strings + \"\";\n}, loadOptions = function(o) {\n var hostname, port, username, password, database, tls, url, query, adapter;\n const env = Bun.env;\n if (typeof o === \"undefined\" || typeof o === \"string\" && o.length === 0) {\n const urlString = env.POSTGRES_URL || env.DATABASE_URL || env.PGURL || env.PG_URL;\n if (urlString)\n url = new URL(urlString), o = {};\n } else if (o && typeof o === \"object\") {\n if (o instanceof URL)\n url = o;\n else if (o\?.url) {\n const _url = o.url;\n if (typeof _url === \"string\")\n url = new URL(_url);\n else if (_url && typeof _url === \"object\" && _url instanceof URL)\n url = _url;\n }\n } else if (typeof o === \"string\")\n url = new URL(o);\n if (url) {\n if ({ hostname, port, username, password, protocol: adapter } = o = url, adapter[adapter.length - 1] === \":\")\n adapter = adapter.slice(0, -1);\n const queryObject = url.searchParams.toJSON();\n query = \"\";\n for (let key in queryObject)\n query += `${encodeURIComponent(key)}=${encodeURIComponent(queryObject[key])} `;\n query = query.trim();\n }\n if (!o)\n o = {};\n if (hostname ||= o.hostname || o.host || env.PGHOST || \"localhost\", port ||= Number(o.port || env.PGPORT || 5432), username ||= o.username || o.user || env.PGUSERNAME || env.PGUSER || env.USER || env.USERNAME || \"postgres\", database ||= o.database || o.db || (url\?.pathname \?\? \"\").slice(1) || env.PGDATABASE || username, password ||= o.password || o.pass || env.PGPASSWORD || \"\", tls ||= o.tls || o.ssl, adapter ||= o.adapter || \"postgres\", !Number.isSafeInteger(port) || port < 1 || port > 65535)\n throw new Error(`Invalid port: ${port}`);\n if (adapter && !(adapter === \"postgres\" || adapter === \"postgresql\"))\n throw new Error(`Unsupported adapter: ${adapter}. Only \\\"postgres\\\" is supported for now`);\n return { hostname, port, username, password, database, tls, query };\n}, SQL = function(o) {\n var connection, connected = !1, connecting = !1, closed = !1, onConnect = [], connectionInfo = loadOptions(o);\n function connectedHandler(query, handle, err) {\n if (err)\n return query.reject(err);\n if (!connected)\n return query.reject(new Error(\"Not connected\"));\n if (query.cancelled)\n return query.reject(new Error(\"Query cancelled\"));\n handle.run(connection, query);\n }\n function pendingConnectionHandler(query, handle) {\n if (onConnect.push((err) => connectedHandler(query, handle, err)), !connecting)\n connecting = !0, connection = createConnection(connectionInfo, onConnected, onClose);\n }\n function closedConnectionHandler(query, handle) {\n query.reject(new Error(\"Connection closed\"));\n }\n function onConnected(err) {\n connected = !err;\n for (let handler of onConnect)\n handler(err);\n onConnect = [];\n }\n function onClose(err) {\n closed = !0, onConnected(err);\n }\n function connectedSQL(strings, values) {\n return new Query(connection.query(normalizeStrings(strings), values), closedConnectionHandler);\n }\n function closedSQL(strings, values) {\n return new Query(@undefined, closedConnectionHandler);\n }\n function pendingSQL(strings, values) {\n return new Query(new PostgresSQLQuery(normalizeStrings(strings), values), pendingConnectionHandler);\n }\n function sql(strings, ...values) {\n if (closed)\n return closedSQL(strings, values);\n if (connected)\n return connectedSQL(strings, values);\n return pendingSQL(strings, values);\n }\n return sql.connect = () => {\n if (closed)\n return @Promise.reject(new Error(\"Connection closed\"));\n if (connected)\n return @Promise.resolve(sql);\n var { resolve, reject, promise } = @Promise.withResolvers();\n if (onConnect.push((err) => err \? reject(err) : resolve(sql)), !connecting)\n connecting = !0, connection = createConnection(connectionInfo, onConnected, onClose);\n return promise;\n }, sql.close = () => {\n if (closed)\n return @Promise.resolve();\n var { resolve, promise } = @Promise.withResolvers();\n return onConnect.push(resolve), connection.close(), promise;\n }, sql.flush = () => {\n if (closed || !connected)\n return;\n connection.flush();\n }, sql;\n}, queryStatus_active = 1 << 1, queryStatus_cancelled = 1 << 2, queryStatus_error = 1 << 3, queryStatus_executed = 1 << 4;\nvar _resolve = Symbol(\"resolve\"), _reject = Symbol(\"reject\"), _handle = Symbol(\"handle\"), _run = Symbol(\"run\"), _queryStatus = Symbol(\"status\"), _handler = Symbol(\"handler\"), PublicPromise = @Promise, { PostgresSQLConnection, PostgresSQLQuery, PostgresSQLStatement, init } = @lazy(\"bun:sql\");\nclass Query extends PublicPromise {\n [_resolve];\n [_reject];\n [_handle];\n [_handler];\n [_queryStatus] = 0;\n constructor(handle, handler) {\n var resolve_, reject_;\n super((resolve, reject) => {\n resolve_ = resolve, reject_ = reject;\n });\n this[_resolve] = resolve_, this[_reject] = reject_, this[_handle] = handle, this[_handler] = handler, this[_queryStatus] = handle \? 0 : queryStatus_cancelled;\n }\n async[_run]() {\n const { [_handle]: handle, [_handler]: handler, [_queryStatus]: status } = this;\n if (status & (queryStatus_executed | queryStatus_cancelled))\n return;\n return this[_queryStatus] |= queryStatus_executed, await 1, handler(this, handle);\n }\n get active() {\n return (this[_queryStatus] & queryStatus_active) !== 0;\n }\n set active(value) {\n if (this[_queryStatus] & (queryStatus_cancelled | queryStatus_error))\n return;\n if (value)\n this[_queryStatus] |= queryStatus_active;\n else\n this[_queryStatus] &= ~queryStatus_active;\n }\n get cancelled() {\n return (this[_queryStatus] & queryStatus_cancelled) !== 0;\n }\n resolve(x) {\n return this[_queryStatus] &= ~queryStatus_active, this[_resolve](x);\n }\n reject(x) {\n return this[_queryStatus] &= ~queryStatus_active, this[_queryStatus] |= queryStatus_error, this[_resolve](x);\n }\n cancel() {\n var status = this[_queryStatus];\n if (status & queryStatus_cancelled)\n return this;\n if (this[_queryStatus] |= queryStatus_cancelled, status & queryStatus_executed)\n this[_handle].cancel();\n return this;\n }\n execute() {\n return this[_run](), this;\n }\n raw() {\n return this[_handle].raw = 2, this;\n }\n values() {\n return this[_handle].raw = 1, this;\n }\n then() {\n return this[_run](), super.then(...arguments);\n }\n catch() {\n return this[_run](), super.catch(...arguments);\n }\n finally() {\n return this[_run](), super.finally(...arguments);\n }\n}\nObject.defineProperty(Query.prototype, Symbol.species, { value: PublicPromise });\nObject.defineProperty(Query.prototype, Symbol.toStringTag, { value: \"Query\" });\ninit(Query.prototype.resolve, Query.prototype.reject);\nvar lazyDefaultSQL, defaultSQLObject = function sql(strings, ...values) {\n if (!lazyDefaultSQL)\n lazyDefaultSQL = SQL(@undefined), Object.assign(defaultSQLObject, lazyDefaultSQL), exportsObject.default = exportsObject.sql = lazyDefaultSQL;\n return lazyDefaultSQL(strings, ...values);\n}, exportsObject = {\n sql: defaultSQLObject,\n default: defaultSQLObject,\n SQL,\n Query\n};\nreturn exportsObject})\n"_s; // // @@ -263,7 +263,7 @@ static constexpr ASCIILiteral BunFFICode = "(function (){\"use strict\";// src/j // // -static constexpr ASCIILiteral BunSqlCode = "(function (){\"use strict\";// src/js/out/tmp/bun/sql.ts\nvar createConnection = function({ hostname, port, username, password, tls, query }, onConnected, onClose) {\n return new PostgresSQLConnection(hostname, port, username, password, tls, query, onConnected, onClose);\n}, normalizeStrings = function(strings) {\n if (@isJSArray(strings))\n return strings.join(\"\?\");\n return strings + \"\";\n}, loadOptions = function(o) {\n var hostname, port, username, password, database, tls, url, query, adapter;\n const env = Bun.env;\n if (typeof o === \"undefined\" || typeof o === \"string\" && o\?.length === 0) {\n const urlString = env.POSTGRES_URL || env.DATABASE_URL || env.PGURL || env.PG_URL;\n if (urlString)\n o = urlString;\n }\n if (typeof o === \"string\") {\n if (url = new URL(o), { hostname, port, username, password, protocol: adapter } = o = url, adapter[adapter.length - 1] === \":\")\n adapter = adapter.slice(0, -1);\n const queryObject = url.searchParams.toJSON();\n query = \"\";\n for (let key in queryObject)\n query += `${encodeURIComponent(key)}=${encodeURIComponent(queryObject[key])} `;\n query = query.trim();\n }\n if (!o)\n o = {};\n if (hostname ||= o.hostname || o.host || env.PGHOST || \"localhost\", port ||= Number(o.port || env.PGPORT || 5432), username ||= o.username || o.user || env.PGUSERNAME || env.PGUSER || env.USER || env.USERNAME || \"postgres\", database ||= o.database || o.db || (url\?.pathname \?\? \"\").slice(1) || env.PGDATABASE || username, password ||= o.password || o.pass || env.PGPASSWORD || \"\", tls ||= o.tls || o.ssl, adapter ||= o.adapter || \"postgres\", !Number.isSafeInteger(port) || port < 1 || port > 65535)\n throw new Error(`Invalid port: ${port}`);\n if (adapter && !(adapter === \"postgres\" || adapter === \"postgresql\"))\n throw new Error(`Unsupported adapter: ${adapter}. Only \\\"postgres\\\" is supported for now`);\n return { hostname, port, username, password, database, tls, query };\n}, SQL = function(o) {\n var connection, connected = !1, connecting = !1, closed = !1, onConnect = [], connectionInfo = loadOptions(o);\n function connectedHandler(query, handle, err) {\n if (err)\n return query.reject(err);\n if (!connected)\n return query.reject(new Error(\"Not connected\"));\n if (query.cancelled)\n return query.reject(new Error(\"Query cancelled\"));\n handle.run(connection, query);\n }\n function pendingConnectionHandler(query, handle) {\n if (onConnect.push((err) => connectedHandler(query, handle, err)), !connecting)\n connecting = !0, connection = createConnection(connectionInfo, onConnected, onClose);\n }\n function closedConnectionHandler(query, handle) {\n query.reject(new Error(\"Connection closed\"));\n }\n function onConnected(err) {\n connected = !err;\n for (let handler of onConnect)\n handler(err);\n onConnect = [];\n }\n function onClose(err) {\n closed = !0, onConnected(err);\n }\n function connectedSQL(strings, values) {\n return new Query(connection.query(normalizeStrings(strings), values), closedConnectionHandler);\n }\n function closedSQL(strings, values) {\n return new Query(@undefined, closedConnectionHandler);\n }\n function pendingSQL(strings, values) {\n return new Query(new PostgresSQLQuery(normalizeStrings(strings), values), pendingConnectionHandler);\n }\n function sql(strings, ...values) {\n if (closed)\n return closedSQL(strings, values);\n if (connected)\n return connectedSQL(strings, values);\n return pendingSQL(strings, values);\n }\n return sql.connect = () => {\n if (closed)\n return @Promise.reject(new Error(\"Connection closed\"));\n if (connected)\n return @Promise.resolve(sql);\n var { resolve, reject, promise } = @Promise.withResolvers();\n if (onConnect.push((err) => err \? reject(err) : resolve(sql)), !connecting)\n connecting = !0, connection = createConnection(connectionInfo, onConnected, onClose);\n return promise;\n }, sql.close = () => {\n if (closed)\n return @Promise.resolve();\n var { resolve, promise } = @Promise.withResolvers();\n return onConnect.push(resolve), connection.close(), promise;\n }, sql.flush = () => {\n if (closed || !connected)\n return;\n connection.flush();\n }, sql;\n}, queryStatus_active = 1 << 1, queryStatus_cancelled = 1 << 2, queryStatus_error = 1 << 3, queryStatus_executed = 1 << 4;\nvar _resolve = Symbol(\"resolve\"), _reject = Symbol(\"reject\"), _handle = Symbol(\"handle\"), _run = Symbol(\"run\"), _queryStatus = Symbol(\"status\"), _handler = Symbol(\"handler\"), PublicPromise = @Promise, { PostgresSQLConnection, PostgresSQLQuery, PostgresSQLStatement, init } = @lazy(\"bun:sql\");\nclass Query extends PublicPromise {\n [_resolve];\n [_reject];\n [_handle];\n [_handler];\n [_queryStatus] = 0;\n constructor(handle, handler) {\n var resolve_, reject_;\n super((resolve, reject) => {\n resolve_ = resolve, reject_ = reject;\n });\n this[_resolve] = resolve_, this[_reject] = reject_, this[_handle] = handle, this[_handler] = handler, this[_queryStatus] = handle \? 0 : queryStatus_cancelled;\n }\n async[_run]() {\n const { [_handle]: handle, [_handler]: handler, [_queryStatus]: status } = this;\n if (status & (queryStatus_executed | queryStatus_cancelled))\n return;\n return this[_queryStatus] |= queryStatus_executed, await 1, handler(this, handle);\n }\n get active() {\n return (this[_queryStatus] & queryStatus_active) !== 0;\n }\n set active(value) {\n if (this[_queryStatus] & (queryStatus_cancelled | queryStatus_error))\n return;\n if (value)\n this[_queryStatus] |= queryStatus_active;\n else\n this[_queryStatus] &= ~queryStatus_active;\n }\n get cancelled() {\n return (this[_queryStatus] & queryStatus_cancelled) !== 0;\n }\n resolve(x) {\n return this[_queryStatus] &= ~queryStatus_active, this[_resolve](x);\n }\n reject(x) {\n return this[_queryStatus] &= ~queryStatus_active, this[_queryStatus] |= queryStatus_error, this[_resolve](x);\n }\n cancel() {\n var status = this[_queryStatus];\n if (status & queryStatus_cancelled)\n return this;\n if (this[_queryStatus] |= queryStatus_cancelled, status & queryStatus_executed)\n this[_handle].cancel();\n return this;\n }\n execute() {\n return this[_run](), this;\n }\n raw() {\n return this[_handle].raw = 2, this;\n }\n values() {\n return this[_handle].raw = 1, this;\n }\n then() {\n return this[_run](), super.then(...arguments);\n }\n catch() {\n return this[_run](), super.catch(...arguments);\n }\n finally() {\n return this[_run](), super.finally(...arguments);\n }\n}\nObject.defineProperty(Query.prototype, Symbol.species, { value: PublicPromise });\nObject.defineProperty(Query.prototype, Symbol.toStringTag, { value: \"Query\" });\ninit(Query.prototype.resolve, Query.prototype.reject);\nvar lazyDefaultSQL, defaultSQLObject = function sql(strings, ...values) {\n if (!lazyDefaultSQL)\n lazyDefaultSQL = SQL(@undefined), Object.assign(defaultSQLObject, lazyDefaultSQL), exportsObject.default = exportsObject.sql = lazyDefaultSQL;\n return lazyDefaultSQL(strings, ...values);\n}, exportsObject = {\n sql: defaultSQLObject,\n default: defaultSQLObject,\n SQL,\n Query\n};\nreturn exportsObject})\n"_s; +static constexpr ASCIILiteral BunSqlCode = "(function (){\"use strict\";// src/js/out/tmp/bun/sql.ts\nvar createConnection = function({ hostname, port, username, password, tls, query }, onConnected, onClose) {\n return new PostgresSQLConnection(hostname, port, username, password, tls, query, onConnected, onClose);\n}, normalizeStrings = function(strings) {\n if (@isJSArray(strings))\n return strings.join(\"\?\");\n return strings + \"\";\n}, loadOptions = function(o) {\n var hostname, port, username, password, database, tls, url, query, adapter;\n const env = Bun.env;\n if (typeof o === \"undefined\" || typeof o === \"string\" && o.length === 0) {\n const urlString = env.POSTGRES_URL || env.DATABASE_URL || env.PGURL || env.PG_URL;\n if (urlString)\n url = new URL(urlString), o = {};\n } else if (o && typeof o === \"object\") {\n if (o instanceof URL)\n url = o;\n else if (o\?.url) {\n const _url = o.url;\n if (typeof _url === \"string\")\n url = new URL(_url);\n else if (_url && typeof _url === \"object\" && _url instanceof URL)\n url = _url;\n }\n } else if (typeof o === \"string\")\n url = new URL(o);\n if (url) {\n if ({ hostname, port, username, password, protocol: adapter } = o = url, adapter[adapter.length - 1] === \":\")\n adapter = adapter.slice(0, -1);\n const queryObject = url.searchParams.toJSON();\n query = \"\";\n for (let key in queryObject)\n query += `${encodeURIComponent(key)}=${encodeURIComponent(queryObject[key])} `;\n query = query.trim();\n }\n if (!o)\n o = {};\n if (hostname ||= o.hostname || o.host || env.PGHOST || \"localhost\", port ||= Number(o.port || env.PGPORT || 5432), username ||= o.username || o.user || env.PGUSERNAME || env.PGUSER || env.USER || env.USERNAME || \"postgres\", database ||= o.database || o.db || (url\?.pathname \?\? \"\").slice(1) || env.PGDATABASE || username, password ||= o.password || o.pass || env.PGPASSWORD || \"\", tls ||= o.tls || o.ssl, adapter ||= o.adapter || \"postgres\", !Number.isSafeInteger(port) || port < 1 || port > 65535)\n throw new Error(`Invalid port: ${port}`);\n if (adapter && !(adapter === \"postgres\" || adapter === \"postgresql\"))\n throw new Error(`Unsupported adapter: ${adapter}. Only \\\"postgres\\\" is supported for now`);\n return { hostname, port, username, password, database, tls, query };\n}, SQL = function(o) {\n var connection, connected = !1, connecting = !1, closed = !1, onConnect = [], connectionInfo = loadOptions(o);\n function connectedHandler(query, handle, err) {\n if (err)\n return query.reject(err);\n if (!connected)\n return query.reject(new Error(\"Not connected\"));\n if (query.cancelled)\n return query.reject(new Error(\"Query cancelled\"));\n handle.run(connection, query);\n }\n function pendingConnectionHandler(query, handle) {\n if (onConnect.push((err) => connectedHandler(query, handle, err)), !connecting)\n connecting = !0, connection = createConnection(connectionInfo, onConnected, onClose);\n }\n function closedConnectionHandler(query, handle) {\n query.reject(new Error(\"Connection closed\"));\n }\n function onConnected(err) {\n connected = !err;\n for (let handler of onConnect)\n handler(err);\n onConnect = [];\n }\n function onClose(err) {\n closed = !0, onConnected(err);\n }\n function connectedSQL(strings, values) {\n return new Query(connection.query(normalizeStrings(strings), values), closedConnectionHandler);\n }\n function closedSQL(strings, values) {\n return new Query(@undefined, closedConnectionHandler);\n }\n function pendingSQL(strings, values) {\n return new Query(new PostgresSQLQuery(normalizeStrings(strings), values), pendingConnectionHandler);\n }\n function sql(strings, ...values) {\n if (closed)\n return closedSQL(strings, values);\n if (connected)\n return connectedSQL(strings, values);\n return pendingSQL(strings, values);\n }\n return sql.connect = () => {\n if (closed)\n return @Promise.reject(new Error(\"Connection closed\"));\n if (connected)\n return @Promise.resolve(sql);\n var { resolve, reject, promise } = @Promise.withResolvers();\n if (onConnect.push((err) => err \? reject(err) : resolve(sql)), !connecting)\n connecting = !0, connection = createConnection(connectionInfo, onConnected, onClose);\n return promise;\n }, sql.close = () => {\n if (closed)\n return @Promise.resolve();\n var { resolve, promise } = @Promise.withResolvers();\n return onConnect.push(resolve), connection.close(), promise;\n }, sql.flush = () => {\n if (closed || !connected)\n return;\n connection.flush();\n }, sql;\n}, queryStatus_active = 1 << 1, queryStatus_cancelled = 1 << 2, queryStatus_error = 1 << 3, queryStatus_executed = 1 << 4;\nvar _resolve = Symbol(\"resolve\"), _reject = Symbol(\"reject\"), _handle = Symbol(\"handle\"), _run = Symbol(\"run\"), _queryStatus = Symbol(\"status\"), _handler = Symbol(\"handler\"), PublicPromise = @Promise, { PostgresSQLConnection, PostgresSQLQuery, PostgresSQLStatement, init } = @lazy(\"bun:sql\");\nclass Query extends PublicPromise {\n [_resolve];\n [_reject];\n [_handle];\n [_handler];\n [_queryStatus] = 0;\n constructor(handle, handler) {\n var resolve_, reject_;\n super((resolve, reject) => {\n resolve_ = resolve, reject_ = reject;\n });\n this[_resolve] = resolve_, this[_reject] = reject_, this[_handle] = handle, this[_handler] = handler, this[_queryStatus] = handle \? 0 : queryStatus_cancelled;\n }\n async[_run]() {\n const { [_handle]: handle, [_handler]: handler, [_queryStatus]: status } = this;\n if (status & (queryStatus_executed | queryStatus_cancelled))\n return;\n return this[_queryStatus] |= queryStatus_executed, await 1, handler(this, handle);\n }\n get active() {\n return (this[_queryStatus] & queryStatus_active) !== 0;\n }\n set active(value) {\n if (this[_queryStatus] & (queryStatus_cancelled | queryStatus_error))\n return;\n if (value)\n this[_queryStatus] |= queryStatus_active;\n else\n this[_queryStatus] &= ~queryStatus_active;\n }\n get cancelled() {\n return (this[_queryStatus] & queryStatus_cancelled) !== 0;\n }\n resolve(x) {\n return this[_queryStatus] &= ~queryStatus_active, this[_resolve](x);\n }\n reject(x) {\n return this[_queryStatus] &= ~queryStatus_active, this[_queryStatus] |= queryStatus_error, this[_resolve](x);\n }\n cancel() {\n var status = this[_queryStatus];\n if (status & queryStatus_cancelled)\n return this;\n if (this[_queryStatus] |= queryStatus_cancelled, status & queryStatus_executed)\n this[_handle].cancel();\n return this;\n }\n execute() {\n return this[_run](), this;\n }\n raw() {\n return this[_handle].raw = 2, this;\n }\n values() {\n return this[_handle].raw = 1, this;\n }\n then() {\n return this[_run](), super.then(...arguments);\n }\n catch() {\n return this[_run](), super.catch(...arguments);\n }\n finally() {\n return this[_run](), super.finally(...arguments);\n }\n}\nObject.defineProperty(Query.prototype, Symbol.species, { value: PublicPromise });\nObject.defineProperty(Query.prototype, Symbol.toStringTag, { value: \"Query\" });\ninit(Query.prototype.resolve, Query.prototype.reject);\nvar lazyDefaultSQL, defaultSQLObject = function sql(strings, ...values) {\n if (!lazyDefaultSQL)\n lazyDefaultSQL = SQL(@undefined), Object.assign(defaultSQLObject, lazyDefaultSQL), exportsObject.default = exportsObject.sql = lazyDefaultSQL;\n return lazyDefaultSQL(strings, ...values);\n}, exportsObject = {\n sql: defaultSQLObject,\n default: defaultSQLObject,\n SQL,\n Query\n};\nreturn exportsObject})\n"_s; // // @@ -517,7 +517,7 @@ static constexpr ASCIILiteral BunFFICode = "(function (){\"use strict\";// src/j // // -static constexpr ASCIILiteral BunSqlCode = "(function (){\"use strict\";// src/js/out/tmp/bun/sql.ts\nvar createConnection = function({ hostname, port, username, password, tls, query }, onConnected, onClose) {\n return new PostgresSQLConnection(hostname, port, username, password, tls, query, onConnected, onClose);\n}, normalizeStrings = function(strings) {\n if (@isJSArray(strings))\n return strings.join(\"\?\");\n return strings + \"\";\n}, loadOptions = function(o) {\n var hostname, port, username, password, database, tls, url, query, adapter;\n const env = Bun.env;\n if (typeof o === \"undefined\" || typeof o === \"string\" && o\?.length === 0) {\n const urlString = env.POSTGRES_URL || env.DATABASE_URL || env.PGURL || env.PG_URL;\n if (urlString)\n o = urlString;\n }\n if (typeof o === \"string\") {\n if (url = new URL(o), { hostname, port, username, password, protocol: adapter } = o = url, adapter[adapter.length - 1] === \":\")\n adapter = adapter.slice(0, -1);\n const queryObject = url.searchParams.toJSON();\n query = \"\";\n for (let key in queryObject)\n query += `${encodeURIComponent(key)}=${encodeURIComponent(queryObject[key])} `;\n query = query.trim();\n }\n if (!o)\n o = {};\n if (hostname ||= o.hostname || o.host || env.PGHOST || \"localhost\", port ||= Number(o.port || env.PGPORT || 5432), username ||= o.username || o.user || env.PGUSERNAME || env.PGUSER || env.USER || env.USERNAME || \"postgres\", database ||= o.database || o.db || (url\?.pathname \?\? \"\").slice(1) || env.PGDATABASE || username, password ||= o.password || o.pass || env.PGPASSWORD || \"\", tls ||= o.tls || o.ssl, adapter ||= o.adapter || \"postgres\", !Number.isSafeInteger(port) || port < 1 || port > 65535)\n throw new Error(`Invalid port: ${port}`);\n if (adapter && !(adapter === \"postgres\" || adapter === \"postgresql\"))\n throw new Error(`Unsupported adapter: ${adapter}. Only \\\"postgres\\\" is supported for now`);\n return { hostname, port, username, password, database, tls, query };\n}, SQL = function(o) {\n var connection, connected = !1, connecting = !1, closed = !1, onConnect = [], connectionInfo = loadOptions(o);\n function connectedHandler(query, handle, err) {\n if (err)\n return query.reject(err);\n if (!connected)\n return query.reject(new Error(\"Not connected\"));\n if (query.cancelled)\n return query.reject(new Error(\"Query cancelled\"));\n handle.run(connection, query);\n }\n function pendingConnectionHandler(query, handle) {\n if (onConnect.push((err) => connectedHandler(query, handle, err)), !connecting)\n connecting = !0, connection = createConnection(connectionInfo, onConnected, onClose);\n }\n function closedConnectionHandler(query, handle) {\n query.reject(new Error(\"Connection closed\"));\n }\n function onConnected(err) {\n connected = !err;\n for (let handler of onConnect)\n handler(err);\n onConnect = [];\n }\n function onClose(err) {\n closed = !0, onConnected(err);\n }\n function connectedSQL(strings, values) {\n return new Query(connection.query(normalizeStrings(strings), values), closedConnectionHandler);\n }\n function closedSQL(strings, values) {\n return new Query(@undefined, closedConnectionHandler);\n }\n function pendingSQL(strings, values) {\n return new Query(new PostgresSQLQuery(normalizeStrings(strings), values), pendingConnectionHandler);\n }\n function sql(strings, ...values) {\n if (closed)\n return closedSQL(strings, values);\n if (connected)\n return connectedSQL(strings, values);\n return pendingSQL(strings, values);\n }\n return sql.connect = () => {\n if (closed)\n return @Promise.reject(new Error(\"Connection closed\"));\n if (connected)\n return @Promise.resolve(sql);\n var { resolve, reject, promise } = @Promise.withResolvers();\n if (onConnect.push((err) => err \? reject(err) : resolve(sql)), !connecting)\n connecting = !0, connection = createConnection(connectionInfo, onConnected, onClose);\n return promise;\n }, sql.close = () => {\n if (closed)\n return @Promise.resolve();\n var { resolve, promise } = @Promise.withResolvers();\n return onConnect.push(resolve), connection.close(), promise;\n }, sql.flush = () => {\n if (closed || !connected)\n return;\n connection.flush();\n }, sql;\n}, queryStatus_active = 1 << 1, queryStatus_cancelled = 1 << 2, queryStatus_error = 1 << 3, queryStatus_executed = 1 << 4;\nvar _resolve = Symbol(\"resolve\"), _reject = Symbol(\"reject\"), _handle = Symbol(\"handle\"), _run = Symbol(\"run\"), _queryStatus = Symbol(\"status\"), _handler = Symbol(\"handler\"), PublicPromise = @Promise, { PostgresSQLConnection, PostgresSQLQuery, PostgresSQLStatement, init } = @lazy(\"bun:sql\");\nclass Query extends PublicPromise {\n [_resolve];\n [_reject];\n [_handle];\n [_handler];\n [_queryStatus] = 0;\n constructor(handle, handler) {\n var resolve_, reject_;\n super((resolve, reject) => {\n resolve_ = resolve, reject_ = reject;\n });\n this[_resolve] = resolve_, this[_reject] = reject_, this[_handle] = handle, this[_handler] = handler, this[_queryStatus] = handle \? 0 : queryStatus_cancelled;\n }\n async[_run]() {\n const { [_handle]: handle, [_handler]: handler, [_queryStatus]: status } = this;\n if (status & (queryStatus_executed | queryStatus_cancelled))\n return;\n return this[_queryStatus] |= queryStatus_executed, await 1, handler(this, handle);\n }\n get active() {\n return (this[_queryStatus] & queryStatus_active) !== 0;\n }\n set active(value) {\n if (this[_queryStatus] & (queryStatus_cancelled | queryStatus_error))\n return;\n if (value)\n this[_queryStatus] |= queryStatus_active;\n else\n this[_queryStatus] &= ~queryStatus_active;\n }\n get cancelled() {\n return (this[_queryStatus] & queryStatus_cancelled) !== 0;\n }\n resolve(x) {\n return this[_queryStatus] &= ~queryStatus_active, this[_resolve](x);\n }\n reject(x) {\n return this[_queryStatus] &= ~queryStatus_active, this[_queryStatus] |= queryStatus_error, this[_resolve](x);\n }\n cancel() {\n var status = this[_queryStatus];\n if (status & queryStatus_cancelled)\n return this;\n if (this[_queryStatus] |= queryStatus_cancelled, status & queryStatus_executed)\n this[_handle].cancel();\n return this;\n }\n execute() {\n return this[_run](), this;\n }\n raw() {\n return this[_handle].raw = 2, this;\n }\n values() {\n return this[_handle].raw = 1, this;\n }\n then() {\n return this[_run](), super.then(...arguments);\n }\n catch() {\n return this[_run](), super.catch(...arguments);\n }\n finally() {\n return this[_run](), super.finally(...arguments);\n }\n}\nObject.defineProperty(Query.prototype, Symbol.species, { value: PublicPromise });\nObject.defineProperty(Query.prototype, Symbol.toStringTag, { value: \"Query\" });\ninit(Query.prototype.resolve, Query.prototype.reject);\nvar lazyDefaultSQL, defaultSQLObject = function sql(strings, ...values) {\n if (!lazyDefaultSQL)\n lazyDefaultSQL = SQL(@undefined), Object.assign(defaultSQLObject, lazyDefaultSQL), exportsObject.default = exportsObject.sql = lazyDefaultSQL;\n return lazyDefaultSQL(strings, ...values);\n}, exportsObject = {\n sql: defaultSQLObject,\n default: defaultSQLObject,\n SQL,\n Query\n};\nreturn exportsObject})\n"_s; +static constexpr ASCIILiteral BunSqlCode = "(function (){\"use strict\";// src/js/out/tmp/bun/sql.ts\nvar createConnection = function({ hostname, port, username, password, tls, query }, onConnected, onClose) {\n return new PostgresSQLConnection(hostname, port, username, password, tls, query, onConnected, onClose);\n}, normalizeStrings = function(strings) {\n if (@isJSArray(strings))\n return strings.join(\"\?\");\n return strings + \"\";\n}, loadOptions = function(o) {\n var hostname, port, username, password, database, tls, url, query, adapter;\n const env = Bun.env;\n if (typeof o === \"undefined\" || typeof o === \"string\" && o.length === 0) {\n const urlString = env.POSTGRES_URL || env.DATABASE_URL || env.PGURL || env.PG_URL;\n if (urlString)\n url = new URL(urlString), o = {};\n } else if (o && typeof o === \"object\") {\n if (o instanceof URL)\n url = o;\n else if (o\?.url) {\n const _url = o.url;\n if (typeof _url === \"string\")\n url = new URL(_url);\n else if (_url && typeof _url === \"object\" && _url instanceof URL)\n url = _url;\n }\n } else if (typeof o === \"string\")\n url = new URL(o);\n if (url) {\n if ({ hostname, port, username, password, protocol: adapter } = o = url, adapter[adapter.length - 1] === \":\")\n adapter = adapter.slice(0, -1);\n const queryObject = url.searchParams.toJSON();\n query = \"\";\n for (let key in queryObject)\n query += `${encodeURIComponent(key)}=${encodeURIComponent(queryObject[key])} `;\n query = query.trim();\n }\n if (!o)\n o = {};\n if (hostname ||= o.hostname || o.host || env.PGHOST || \"localhost\", port ||= Number(o.port || env.PGPORT || 5432), username ||= o.username || o.user || env.PGUSERNAME || env.PGUSER || env.USER || env.USERNAME || \"postgres\", database ||= o.database || o.db || (url\?.pathname \?\? \"\").slice(1) || env.PGDATABASE || username, password ||= o.password || o.pass || env.PGPASSWORD || \"\", tls ||= o.tls || o.ssl, adapter ||= o.adapter || \"postgres\", !Number.isSafeInteger(port) || port < 1 || port > 65535)\n throw new Error(`Invalid port: ${port}`);\n if (adapter && !(adapter === \"postgres\" || adapter === \"postgresql\"))\n throw new Error(`Unsupported adapter: ${adapter}. Only \\\"postgres\\\" is supported for now`);\n return { hostname, port, username, password, database, tls, query };\n}, SQL = function(o) {\n var connection, connected = !1, connecting = !1, closed = !1, onConnect = [], connectionInfo = loadOptions(o);\n function connectedHandler(query, handle, err) {\n if (err)\n return query.reject(err);\n if (!connected)\n return query.reject(new Error(\"Not connected\"));\n if (query.cancelled)\n return query.reject(new Error(\"Query cancelled\"));\n handle.run(connection, query);\n }\n function pendingConnectionHandler(query, handle) {\n if (onConnect.push((err) => connectedHandler(query, handle, err)), !connecting)\n connecting = !0, connection = createConnection(connectionInfo, onConnected, onClose);\n }\n function closedConnectionHandler(query, handle) {\n query.reject(new Error(\"Connection closed\"));\n }\n function onConnected(err) {\n connected = !err;\n for (let handler of onConnect)\n handler(err);\n onConnect = [];\n }\n function onClose(err) {\n closed = !0, onConnected(err);\n }\n function connectedSQL(strings, values) {\n return new Query(connection.query(normalizeStrings(strings), values), closedConnectionHandler);\n }\n function closedSQL(strings, values) {\n return new Query(@undefined, closedConnectionHandler);\n }\n function pendingSQL(strings, values) {\n return new Query(new PostgresSQLQuery(normalizeStrings(strings), values), pendingConnectionHandler);\n }\n function sql(strings, ...values) {\n if (closed)\n return closedSQL(strings, values);\n if (connected)\n return connectedSQL(strings, values);\n return pendingSQL(strings, values);\n }\n return sql.connect = () => {\n if (closed)\n return @Promise.reject(new Error(\"Connection closed\"));\n if (connected)\n return @Promise.resolve(sql);\n var { resolve, reject, promise } = @Promise.withResolvers();\n if (onConnect.push((err) => err \? reject(err) : resolve(sql)), !connecting)\n connecting = !0, connection = createConnection(connectionInfo, onConnected, onClose);\n return promise;\n }, sql.close = () => {\n if (closed)\n return @Promise.resolve();\n var { resolve, promise } = @Promise.withResolvers();\n return onConnect.push(resolve), connection.close(), promise;\n }, sql.flush = () => {\n if (closed || !connected)\n return;\n connection.flush();\n }, sql;\n}, queryStatus_active = 1 << 1, queryStatus_cancelled = 1 << 2, queryStatus_error = 1 << 3, queryStatus_executed = 1 << 4;\nvar _resolve = Symbol(\"resolve\"), _reject = Symbol(\"reject\"), _handle = Symbol(\"handle\"), _run = Symbol(\"run\"), _queryStatus = Symbol(\"status\"), _handler = Symbol(\"handler\"), PublicPromise = @Promise, { PostgresSQLConnection, PostgresSQLQuery, PostgresSQLStatement, init } = @lazy(\"bun:sql\");\nclass Query extends PublicPromise {\n [_resolve];\n [_reject];\n [_handle];\n [_handler];\n [_queryStatus] = 0;\n constructor(handle, handler) {\n var resolve_, reject_;\n super((resolve, reject) => {\n resolve_ = resolve, reject_ = reject;\n });\n this[_resolve] = resolve_, this[_reject] = reject_, this[_handle] = handle, this[_handler] = handler, this[_queryStatus] = handle \? 0 : queryStatus_cancelled;\n }\n async[_run]() {\n const { [_handle]: handle, [_handler]: handler, [_queryStatus]: status } = this;\n if (status & (queryStatus_executed | queryStatus_cancelled))\n return;\n return this[_queryStatus] |= queryStatus_executed, await 1, handler(this, handle);\n }\n get active() {\n return (this[_queryStatus] & queryStatus_active) !== 0;\n }\n set active(value) {\n if (this[_queryStatus] & (queryStatus_cancelled | queryStatus_error))\n return;\n if (value)\n this[_queryStatus] |= queryStatus_active;\n else\n this[_queryStatus] &= ~queryStatus_active;\n }\n get cancelled() {\n return (this[_queryStatus] & queryStatus_cancelled) !== 0;\n }\n resolve(x) {\n return this[_queryStatus] &= ~queryStatus_active, this[_resolve](x);\n }\n reject(x) {\n return this[_queryStatus] &= ~queryStatus_active, this[_queryStatus] |= queryStatus_error, this[_resolve](x);\n }\n cancel() {\n var status = this[_queryStatus];\n if (status & queryStatus_cancelled)\n return this;\n if (this[_queryStatus] |= queryStatus_cancelled, status & queryStatus_executed)\n this[_handle].cancel();\n return this;\n }\n execute() {\n return this[_run](), this;\n }\n raw() {\n return this[_handle].raw = 2, this;\n }\n values() {\n return this[_handle].raw = 1, this;\n }\n then() {\n return this[_run](), super.then(...arguments);\n }\n catch() {\n return this[_run](), super.catch(...arguments);\n }\n finally() {\n return this[_run](), super.finally(...arguments);\n }\n}\nObject.defineProperty(Query.prototype, Symbol.species, { value: PublicPromise });\nObject.defineProperty(Query.prototype, Symbol.toStringTag, { value: \"Query\" });\ninit(Query.prototype.resolve, Query.prototype.reject);\nvar lazyDefaultSQL, defaultSQLObject = function sql(strings, ...values) {\n if (!lazyDefaultSQL)\n lazyDefaultSQL = SQL(@undefined), Object.assign(defaultSQLObject, lazyDefaultSQL), exportsObject.default = exportsObject.sql = lazyDefaultSQL;\n return lazyDefaultSQL(strings, ...values);\n}, exportsObject = {\n sql: defaultSQLObject,\n default: defaultSQLObject,\n SQL,\n Query\n};\nreturn exportsObject})\n"_s; // // diff --git a/src/jsc.zig b/src/jsc.zig index 5cdf739b3..82d4df1ce 100644 --- a/src/jsc.zig +++ b/src/jsc.zig @@ -46,6 +46,7 @@ pub const API = struct { pub const TLSSocket = @import("./bun.js/api/bun/socket.zig").TLSSocket; pub const Listener = @import("./bun.js/api/bun/socket.zig").Listener; }; +pub const Postgres = @import("./sql/postgres.zig"); pub const DNS = @import("./bun.js/api/bun/dns_resolver.zig"); pub const FFI = @import("./bun.js/api/ffi.zig").FFI; pub const Node = struct { diff --git a/src/sql/postgres.zig b/src/sql/postgres.zig index 37bc47b21..abc9b4e51 100644 --- a/src/sql/postgres.zig +++ b/src/sql/postgres.zig @@ -42,21 +42,58 @@ const Data = union(enum) { }; pub const protocol = struct { - pub fn NewWriterWrap(comptime Context: type, comptime writeFunction_: (fn (ctx: Context, bytes: []const u8) anyerror!void)) type { + pub const ArrayList = struct { + array: *std.ArrayList(u8), + + pub fn offset(this: @This()) usize { + return this.array.items.len; + } + + pub fn write(this: @This(), bytes: []const u8) anyerror!void { + try this.array.appendSlice(bytes); + } + + pub fn pwrite(this: @This(), bytes: []const u8, i: usize) anyerror!void { + @memcpy(this.array.items[i..][0..bytes.len], bytes); + } + + pub const Writer = NewWriter(@This()); + }; + + pub fn NewWriterWrap( + comptime Context: type, + comptime offsetFn_: (fn (ctx: Context) usize), + comptime writeFunction_: (fn (ctx: Context, bytes: []const u8) anyerror!void), + comptime pwriteFunction_: (fn (ctx: Context, bytes: []const u8, offset: usize) anyerror!void), + ) type { return struct { wrapped: Context, const writeFn = writeFunction_; + const pwriteFn = pwriteFunction_; + const offsetFn = offsetFn_; pub const Ctx = Context; pub inline fn write(this: @This(), data: []const u8) anyerror!void { try writeFn(this.wrapped, data); } + pub inline fn offset(this: @This()) usize { + return offsetFn(this.wrapped); + } + + pub inline fn pwrite(this: @This(), data: []const u8, i: usize) anyerror!void { + try pwriteFn(this.wrapped, data, i); + } + pub fn @"i32"(this: @This(), value: i32) !void { try this.write(std.mem.asBytes(&@byteSwap(value))); } + pub fn @"f64"(this: @This(), value: f64) !void { + try this.write(std.mem.asBytes(&@byteSwap(value))); + } + pub fn @"i16"(this: @This(), value: i16) !void { try this.write(std.mem.asBytes(&@byteSwap(value))); } @@ -73,7 +110,20 @@ pub const protocol = struct { try this.write(&[_]u8{0}); } + pub fn boolean(this: @This(), value: bool) !void { + try this.write(if (value) "t" else "f"); + } + + pub fn @"null"(this: @This()) !void { + try this.i32(0xFFFFFFFF); + } + pub fn String(this: @This(), value: bun.String) !void { + if (value.isEmpty()) { + try this.write(&[_]u8{0}); + return; + } + var sliced = value.toUTF8(bun.default_allocator); defer sliced.deinit(); var slice = sliced.slice(); @@ -276,7 +326,7 @@ pub const protocol = struct { } pub fn NewWriter(comptime Context: type) type { - return NewWriterWrap(Context, Context.writeData); + return NewWriterWrap(Context, Context.offset, Context.write, Context.pwrite); } comptime { @@ -1306,10 +1356,176 @@ const PreparedStatementsMap = std.HashMapUnmanaged(u64, *PostgresSQLStatement, b pub const PostgresSQLContext = struct { tcp: ?*uws.SocketContext = null, - ssl: ?*uws.SocketContext = null, - onQueryCompleteFn: JSC.Strong = .{}, - onStatementCompleteFn: JSC.Strong = .{}, + onQueryResolveFn: JSC.Strong = .{}, + onQueryRejectFn: JSC.Strong = .{}, +}; + +pub const PostgresSQLQuery = struct { + statement: ?*PostgresSQLStatement = null, + query: bun.String = bun.String.empty, + cursor_name: bun.String = bun.String.empty, + + pub fn constructor(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) ?*PostgresSQLQuery { + _ = callframe; + _ = globalThis; + } + + pub fn doRun(this: *PostgresSQLQuery, globalObject: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSC.JSValue { + var arguments_ = callframe.arguments(3); + const arguments = arguments_.slice(); + var connection = arguments[0].as(PostgresSQLConnection) orelse { + globalObject.throwTypeError("connection must be a PostgresSQLConnection"); + return .zero; + }; + _ = connection; + + var values_array = arguments[1]; + + var query = arguments[1]; + + if (!values_array.jsType().isArray()) { + globalObject.throwInvalidArgumentType("run", "values", "Array"); + return .zero; + } + if (!query.isString()) { + globalObject.throwInvalidArgumentType("run", "query", "string"); + return .zero; + } + + var statement = this.statement orelse {}; + _ = statement; + + return .undefined; + } + + pub fn doCancel(this: *PostgresSQLQuery, globalObject: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSC.JSValue { + _ = callframe; + _ = globalObject; + _ = this; + + return .undefined; + } +}; + +pub const PostgresRequest = struct { + pub fn writeBind( + statement: *PostgresSQLStatement, + cursor_name: bun.String, + globalObject: *JSC.JSGlobalObject, + values_array: JSC.JSValue, + comptime Context: type, + writer: protocol.NewWriter(Context), + ) !void { + try writer.bytes("B"); + const length_offset = writer.offset(); + try writer.i32(0); + + try writer.string(statement.name); + try writer.String(cursor_name); + + var iter = JSC.JSArrayIterator.init(values_array, globalObject); + + try writer.i16(@truncate(iter.len)); + + while (iter.next()) |value| { + if (value.isUndefinedOrNull()) { + try writer.i16(0); + continue; + } + + const tag = types.Tag.fromJS(globalObject, value); + switch (tag) { + .bytea, .number => { + try writer.i16(0); + }, + else => { + try writer.i16(1); + }, + } + } + + try writer.i16(@truncate(iter.len)); + + iter = JSC.JSArrayIterator.init(values_array, globalObject); + + while (iter.next()) |value| { + if (value.isUndefinedOrNull()) { + try writer.i32(4); + try writer.null(); + continue; + } + + const tag = types.Tag.fromJS(globalObject, value); + switch (tag) { + .number => { + if (value.isInt32()) { + try writer.i32(4); + try writer.i32(value.to(i32)); + } else { + try writer.i32(8); + try writer.f64(value.coerceToDouble(globalObject)); + } + }, + .json => { + var str = bun.String.empty; + value.jsonStringify(globalObject, 0, &str); + try writer.String(str); + }, + .boolean => { + try writer.boolean(value.toBoolean()); + try writer.write(&[_]u8{0}); + }, + .time, .datetime, .date => { + var buf = std.mem.zeroes([28]u8); + const str = value.toISOString(globalObject, &buf); + try writer.string(str); + }, + .bytea => { + var bytes: []const u8 = ""; + if (value.asArrayBuffer(globalObject)) |buf| { + bytes = buf.byteSlice(); + } + try writer.i32(@truncate(bytes.len)); + try writer.bytes(bytes); + }, + else => { + // TODO: check if this leaks + var str = value.toBunString(globalObject); + try writer.str(str); + }, + } + } + + try writer.pwrite(&@byteSwap(std.mem.toBytes(@as(i32, @intCast(writer.offset())))), length_offset); + } + + pub fn writeQuery( + query: bun.String, + statement: *PostgresSQLStatement, + comptime Context: type, + writer: protocol.NewWriter(Context), + ) !void { + { + var query_str = query.toUTF8(bun.default_allocator); + defer query_str.deinit(); + var q = protocol.Query{ + .message = Data{ + .temporary = query_str.slice(), + }, + }; + try q.writeInternal(Context, writer); + } + + { + var d = protocol.Describe{ + .p = .{ + .prepared_statement = statement.name, + }, + }; + try d.writeInternal(Context, writer); + } + } }; pub const PostgresSQLConnection = struct { @@ -1318,6 +1534,7 @@ pub const PostgresSQLConnection = struct { ref_count: u32 = 0, write_buffer: bun.ByteList = .{}, + requests: PostgresRequest.Queue, poll_ref: bun.JSC.PollRef = .{}, globalObject: *JSC.JSGlobalObject, @@ -1326,6 +1543,8 @@ pub const PostgresSQLConnection = struct { has_pending_activity: std.atomic.Atomic(bool) = std.atomic.Atomic(bool).init(false), js_value: JSC.JSValue = JSC.JSValue.undefined, + pub usingnamespace JSC.Codegen.JSPostgresSQLConnection; + pub fn hasPendingActivity(this: *PostgresSQLConnection) callconv(.C) bool { @fence(.Acquire); return this.has_pending_activity.load(.Acquire); @@ -1389,29 +1608,17 @@ pub const PostgresSQLConnection = struct { }; pub const PostgresSQLStatement = struct { - connection: ?*PostgresSQLConnection = null, + structure: JSC.Strong = .{}, name: []const u8 = "", ref_count: u32 = 0, - poll_ref: JSC.PollRef = .{}, - has_pending_activity: std.atomic.Atomic(bool) = std.atomic.Atomic(bool).init(false), - - pub fn hasPendingActivity(this: *PostgresSQLStatement) callconv(.C) bool { - return this.has_pending_activity.load(.Monotonic); - } + fields: []const protocol.FieldDescription = &[_]protocol.FieldDescription{}, - pub fn deinit(this: *PostgresSQLStatement) void { - if (this.connection) |conn| conn.deref(); - this.poll_ref.deactivate(JSC.VirtualMachine.get().event_loop_handle.?); - - bun.default_allocator.free(this.name); - bun.default_allocator.destroy(this); - } - - pub fn finalize(this: *PostgresSQLStatement) callconv(.C) void { - this.unref(); + pub fn ref(this: *@This()) void { + std.debug.assert(this.ref_count > 0); + this.ref_count += 1; } - pub fn unref(this: *PostgresSQLStatement) void { + pub fn deref(this: *@This()) void { const ref_count = this.ref_count; this.ref_count -= 1; @@ -1420,28 +1627,19 @@ pub const PostgresSQLStatement = struct { } } - pub fn doRef(this: *PostgresSQLStatement, globalObject: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) void { - _ = callframe; - this.poll_ref.ref(globalObject.bunVM()); - } + pub fn deinit(this: *PostgresSQLStatement) void { + std.debug.assert(this.ref_count == 0); - pub fn doUnref(this: *PostgresSQLStatement, globalObject: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) void { - _ = callframe; - this.poll_ref.unref(globalObject.bunVM()); + for (this.fields) |*field| { + field.deinit(); + } + bun.default_allocator.free(this.fields); + this.structure.deinit(); + bun.default_allocator.free(this.name); + bun.default_allocator.destroy(this); } }; -pub const Host = struct { - hostname: []const u8, - port: u16, - - database: []const u8, - user: []const u8, - password: []const u8 = "", - - ssl: bool = false, -}; - pub const Status = enum { disconnected, connecting, |