mirror of
https://github.com/oven-sh/bun
synced 2026-02-28 12:31:00 +01:00
Compare commits
64 Commits
claude/fix
...
ciro/fix-o
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c226a947c9 | ||
|
|
a6d749276c | ||
|
|
d83103fe49 | ||
|
|
4400f39b30 | ||
|
|
2bd01af7e8 | ||
|
|
b616fe1db6 | ||
|
|
b4a9f5f0ff | ||
|
|
ca80e070de | ||
|
|
2b66c6f4a4 | ||
|
|
a39179a109 | ||
|
|
5ddc772c50 | ||
|
|
324c72c537 | ||
|
|
019ccc338d | ||
|
|
6cc1e75d0f | ||
|
|
e5cc5d5b4b | ||
|
|
bb85cc40a7 | ||
|
|
00ce0847d9 | ||
|
|
07631e0742 | ||
|
|
155f0a8bbb | ||
|
|
61bd3e67da | ||
|
|
8a64dd86c6 | ||
|
|
a9a56e6230 | ||
|
|
477aa56aa4 | ||
|
|
1a5660ba39 | ||
|
|
8eb6b933b6 | ||
|
|
2cc90a7615 | ||
|
|
7d7c3daccf | ||
|
|
e557195dde | ||
|
|
32d5797866 | ||
|
|
bca76bf378 | ||
|
|
75fde6ce45 | ||
|
|
6d789e2eb7 | ||
|
|
09099b3747 | ||
|
|
1c0ae14239 | ||
|
|
ec1fc80111 | ||
|
|
054de551c2 | ||
|
|
38a798baa8 | ||
|
|
f763180b95 | ||
|
|
08f3270203 | ||
|
|
c4996b2d99 | ||
|
|
fa0febc520 | ||
|
|
f1a52633a3 | ||
|
|
b778121cf1 | ||
|
|
3e84a2964d | ||
|
|
7753820bd6 | ||
|
|
b79f0d1e39 | ||
|
|
c5fbe102e2 | ||
|
|
7c30edd20e | ||
|
|
60d4f92491 | ||
|
|
3d053712d4 | ||
|
|
173309ba95 | ||
|
|
b3d46fa99a | ||
|
|
edeca4602d | ||
|
|
f424308a31 | ||
|
|
07ca61f814 | ||
|
|
becf7777ef | ||
|
|
413dd86bf8 | ||
|
|
7eecefecf0 | ||
|
|
b809cd297e | ||
|
|
6f125e0375 | ||
|
|
edec93a475 | ||
|
|
3be879682e | ||
|
|
8bf8b8e32f | ||
|
|
4654a8a886 |
@@ -627,8 +627,8 @@ pub fn NewServer(protocol_enum: enum { http, https }, development_kind: enum { d
|
||||
}
|
||||
|
||||
pub fn jsValueAssertAlive(server: *ThisServer) jsc.JSValue {
|
||||
// With JSRef, we can safely access the JS value even after stop() via weak reference
|
||||
return server.js_value.get();
|
||||
bun.assert(server.js_value.isNotEmpty());
|
||||
return server.js_value.tryGet().?;
|
||||
}
|
||||
|
||||
pub fn requestIP(this: *ThisServer, request: *jsc.WebCore.Request) bun.JSError!jsc.JSValue {
|
||||
@@ -1124,7 +1124,7 @@ pub fn NewServer(protocol_enum: enum { http, https }, development_kind: enum { d
|
||||
|
||||
this.onReloadFromZig(&new_config, globalThis);
|
||||
|
||||
return this.js_value.get();
|
||||
return this.js_value.tryGet() orelse .js_undefined;
|
||||
}
|
||||
|
||||
pub fn onFetch(this: *ThisServer, ctx: *jsc.JSGlobalObject, callframe: *jsc.CallFrame) bun.JSError!jsc.JSValue {
|
||||
@@ -1426,7 +1426,7 @@ pub fn NewServer(protocol_enum: enum { http, https }, development_kind: enum { d
|
||||
|
||||
pub fn finalize(this: *ThisServer) void {
|
||||
httplog("finalize", .{});
|
||||
this.js_value.deinit();
|
||||
this.js_value.finalize();
|
||||
this.flags.has_js_deinited = true;
|
||||
this.deinitIfWeCan();
|
||||
}
|
||||
@@ -1539,8 +1539,7 @@ pub fn NewServer(protocol_enum: enum { http, https }, development_kind: enum { d
|
||||
}
|
||||
|
||||
pub fn stop(this: *ThisServer, abrupt: bool) void {
|
||||
const current_value = this.js_value.get();
|
||||
this.js_value.setWeak(current_value);
|
||||
this.js_value.downgrade();
|
||||
|
||||
if (this.config.allow_hot and this.config.id.len > 0) {
|
||||
if (this.globalThis.bunVM().hotMap()) |hot| {
|
||||
|
||||
@@ -1981,7 +1981,7 @@ pub fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool,
|
||||
this.flags.has_called_error_handler = true;
|
||||
const result = server.config.onError.call(
|
||||
server.globalThis,
|
||||
server.js_value.get(),
|
||||
server.js_value.tryGet() orelse .js_undefined,
|
||||
&.{value},
|
||||
) catch |err| server.globalThis.takeException(err);
|
||||
defer result.ensureStillAlive();
|
||||
|
||||
@@ -9,7 +9,7 @@ for (const type of types) {
|
||||
construct: true,
|
||||
finalize: true,
|
||||
configurable: false,
|
||||
hasPendingActivity: true,
|
||||
hasPendingActivity: type === "PostgresSQL",
|
||||
klass: {
|
||||
// escapeString: {
|
||||
// fn: "escapeString",
|
||||
@@ -60,7 +60,6 @@ for (const type of types) {
|
||||
construct: true,
|
||||
finalize: true,
|
||||
configurable: false,
|
||||
|
||||
JSType: "0b11101110",
|
||||
klass: {},
|
||||
proto: {
|
||||
|
||||
@@ -4,33 +4,28 @@ pub const JSRef = union(enum) {
|
||||
finalized: void,
|
||||
|
||||
pub fn initWeak(value: jsc.JSValue) @This() {
|
||||
bun.assert(!value.isEmptyOrUndefinedOrNull());
|
||||
return .{ .weak = value };
|
||||
}
|
||||
|
||||
pub fn initStrong(value: jsc.JSValue, globalThis: *jsc.JSGlobalObject) @This() {
|
||||
bun.assert(!value.isEmptyOrUndefinedOrNull());
|
||||
return .{ .strong = .create(value, globalThis) };
|
||||
}
|
||||
|
||||
pub fn empty() @This() {
|
||||
return .{ .weak = .zero };
|
||||
return .{ .weak = .js_undefined };
|
||||
}
|
||||
|
||||
pub fn get(this: *@This()) jsc.JSValue {
|
||||
pub fn tryGet(this: *const @This()) ?jsc.JSValue {
|
||||
return switch (this.*) {
|
||||
.weak => this.weak,
|
||||
.strong => this.strong.get() orelse .zero,
|
||||
.finalized => .zero,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn tryGet(this: *@This()) ?jsc.JSValue {
|
||||
return switch (this.*) {
|
||||
.weak => if (this.weak != .zero) this.weak else null,
|
||||
.weak => if (this.weak.isEmptyOrUndefinedOrNull()) null else this.weak,
|
||||
.strong => this.strong.get(),
|
||||
.finalized => null,
|
||||
};
|
||||
}
|
||||
pub fn setWeak(this: *@This(), value: jsc.JSValue) void {
|
||||
bun.assert(!value.isEmptyOrUndefinedOrNull());
|
||||
switch (this.*) {
|
||||
.weak => {},
|
||||
.strong => {
|
||||
@@ -44,6 +39,7 @@ pub const JSRef = union(enum) {
|
||||
}
|
||||
|
||||
pub fn setStrong(this: *@This(), value: jsc.JSValue, globalThis: *jsc.JSGlobalObject) void {
|
||||
bun.assert(!value.isEmptyOrUndefinedOrNull());
|
||||
if (this.* == .strong) {
|
||||
this.strong.set(globalThis, value);
|
||||
return;
|
||||
@@ -54,7 +50,7 @@ pub const JSRef = union(enum) {
|
||||
pub fn upgrade(this: *@This(), globalThis: *jsc.JSGlobalObject) void {
|
||||
switch (this.*) {
|
||||
.weak => {
|
||||
bun.assert(this.weak != .zero);
|
||||
bun.assert(!this.weak.isEmptyOrUndefinedOrNull());
|
||||
this.* = .{ .strong = .create(this.weak, globalThis) };
|
||||
},
|
||||
.strong => {},
|
||||
@@ -64,10 +60,41 @@ pub const JSRef = union(enum) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn downgrade(this: *@This()) void {
|
||||
switch (this.*) {
|
||||
.weak => {},
|
||||
.strong => |*strong| {
|
||||
const value = strong.trySwap() orelse .js_undefined;
|
||||
value.ensureStillAlive();
|
||||
strong.deinit();
|
||||
this.* = .{ .weak = value };
|
||||
},
|
||||
.finalized => {
|
||||
bun.debugAssert(false);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn isEmpty(this: *const @This()) bool {
|
||||
return switch (this.*) {
|
||||
.weak => this.weak.isEmptyOrUndefinedOrNull(),
|
||||
.strong => !this.strong.has(),
|
||||
.finalized => true,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn isNotEmpty(this: *const @This()) bool {
|
||||
return switch (this.*) {
|
||||
.weak => !this.weak.isEmptyOrUndefinedOrNull(),
|
||||
.strong => this.strong.has(),
|
||||
.finalized => false,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(this: *@This()) void {
|
||||
switch (this.*) {
|
||||
.weak => {
|
||||
this.weak = .zero;
|
||||
this.weak = .js_undefined;
|
||||
},
|
||||
.strong => {
|
||||
this.strong.deinit();
|
||||
@@ -75,6 +102,11 @@ pub const JSRef = union(enum) {
|
||||
.finalized => {},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn finalize(this: *@This()) void {
|
||||
this.deinit();
|
||||
this.* = .{ .finalized = {} };
|
||||
}
|
||||
};
|
||||
|
||||
const bun = @import("bun");
|
||||
|
||||
@@ -1548,9 +1548,18 @@ JSC_DEFINE_HOST_FUNCTION(functionQueueMicrotask,
|
||||
|
||||
auto* globalObject = defaultGlobalObject(lexicalGlobalObject);
|
||||
JSC::JSValue asyncContext = globalObject->m_asyncContextData.get()->getInternalField(0);
|
||||
auto function = globalObject->performMicrotaskFunction();
|
||||
#if ASSERT_ENABLED
|
||||
ASSERT_WITH_MESSAGE(function, "Invalid microtask function");
|
||||
ASSERT_WITH_MESSAGE(!callback.isEmpty(), "Invalid microtask callback");
|
||||
#endif
|
||||
|
||||
if (asyncContext.isEmpty()) {
|
||||
asyncContext = JSC::jsUndefined();
|
||||
}
|
||||
|
||||
// This is a JSC builtin function
|
||||
lexicalGlobalObject->queueMicrotask(globalObject->performMicrotaskFunction(), callback, asyncContext,
|
||||
lexicalGlobalObject->queueMicrotask(function, callback, asyncContext,
|
||||
JSC::JSValue {}, JSC::JSValue {});
|
||||
|
||||
return JSC::JSValue::encode(JSC::jsUndefined());
|
||||
@@ -4147,6 +4156,12 @@ extern "C" void JSC__JSGlobalObject__queueMicrotaskCallback(Zig::GlobalObject* g
|
||||
{
|
||||
JSFunction* function = globalObject->nativeMicrotaskTrampoline();
|
||||
|
||||
#if ASSERT_ENABLED
|
||||
ASSERT_WITH_MESSAGE(function, "Invalid microtask function");
|
||||
ASSERT_WITH_MESSAGE(ptr, "Invalid microtask context");
|
||||
ASSERT_WITH_MESSAGE(callback, "Invalid microtask callback");
|
||||
#endif
|
||||
|
||||
// Do not use JSCell* here because the GC will try to visit it.
|
||||
globalObject->queueMicrotask(function, JSValue(std::bit_cast<double>(reinterpret_cast<uintptr_t>(ptr))), JSValue(std::bit_cast<double>(reinterpret_cast<uintptr_t>(callback))), jsUndefined(), jsUndefined());
|
||||
}
|
||||
|
||||
@@ -3453,6 +3453,7 @@ void JSC__JSPromise__rejectOnNextTickWithHandled(JSC::JSPromise* promise, JSC::J
|
||||
JSC::EncodedJSValue encoedValue, bool handled)
|
||||
{
|
||||
JSC::JSValue value = JSC::JSValue::decode(encoedValue);
|
||||
|
||||
auto& vm = JSC::getVM(lexicalGlobalObject);
|
||||
auto scope = DECLARE_THROW_SCOPE(vm);
|
||||
uint32_t flags = promise->internalField(JSC::JSPromise::Field::Flags).get().asUInt32();
|
||||
@@ -3463,10 +3464,28 @@ void JSC__JSPromise__rejectOnNextTickWithHandled(JSC::JSPromise* promise, JSC::J
|
||||
|
||||
promise->internalField(JSC::JSPromise::Field::Flags).set(vm, promise, jsNumber(flags | JSC::JSPromise::isFirstResolvingFunctionCalledFlag));
|
||||
auto* globalObject = jsCast<Zig::GlobalObject*>(promise->globalObject());
|
||||
auto microtaskFunction = globalObject->performMicrotaskFunction();
|
||||
auto rejectPromiseFunction = globalObject->rejectPromiseFunction();
|
||||
|
||||
auto asyncContext = globalObject->m_asyncContextData.get()->getInternalField(0);
|
||||
|
||||
#if ASSERT_ENABLED
|
||||
ASSERT_WITH_MESSAGE(microtaskFunction, "Invalid microtask function");
|
||||
ASSERT_WITH_MESSAGE(rejectPromiseFunction, "Invalid microtask callback");
|
||||
ASSERT_WITH_MESSAGE(!value.isEmpty(), "Invalid microtask value");
|
||||
#endif
|
||||
|
||||
if (asyncContext.isEmpty()) {
|
||||
asyncContext = jsUndefined();
|
||||
}
|
||||
|
||||
if (value.isEmpty()) {
|
||||
value = jsUndefined();
|
||||
}
|
||||
|
||||
globalObject->queueMicrotask(
|
||||
globalObject->performMicrotaskFunction(),
|
||||
globalObject->rejectPromiseFunction(),
|
||||
microtaskFunction,
|
||||
rejectPromiseFunction,
|
||||
globalObject->m_asyncContextData.get()->getInternalField(0),
|
||||
promise,
|
||||
value);
|
||||
@@ -6121,8 +6140,9 @@ extern "C" void JSC__JSGlobalObject__queueMicrotaskJob(JSC::JSGlobalObject* arg0
|
||||
if (microtaskArgs[3].isEmpty()) {
|
||||
microtaskArgs[3] = jsUndefined();
|
||||
}
|
||||
|
||||
auto microTaskFunction = globalObject->performMicrotaskFunction();
|
||||
#if ASSERT_ENABLED
|
||||
ASSERT_WITH_MESSAGE(microTaskFunction, "Invalid microtask function");
|
||||
auto& vm = globalObject->vm();
|
||||
if (microtaskArgs[0].isCell()) {
|
||||
JSC::Integrity::auditCellFully(vm, microtaskArgs[0].asCell());
|
||||
@@ -6139,10 +6159,11 @@ extern "C" void JSC__JSGlobalObject__queueMicrotaskJob(JSC::JSGlobalObject* arg0
|
||||
if (microtaskArgs[3].isCell()) {
|
||||
JSC::Integrity::auditCellFully(vm, microtaskArgs[3].asCell());
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
globalObject->queueMicrotask(
|
||||
globalObject->performMicrotaskFunction(),
|
||||
microTaskFunction,
|
||||
WTFMove(microtaskArgs[0]),
|
||||
WTFMove(microtaskArgs[1]),
|
||||
WTFMove(microtaskArgs[2]),
|
||||
|
||||
@@ -98,8 +98,8 @@ for (let i = 0; i < nativeStartIndex; i++) {
|
||||
|
||||
// TODO: there is no reason this cannot be converted automatically.
|
||||
// import { ... } from '...' -> `const { ... } = require('...')`
|
||||
const scannedImports = t.scanImports(input);
|
||||
for (const imp of scannedImports) {
|
||||
const scannedImports = t.scan(input);
|
||||
for (const imp of scannedImports.imports) {
|
||||
if (imp.kind === "import-statement") {
|
||||
var isBuiltin = true;
|
||||
try {
|
||||
@@ -120,6 +120,14 @@ for (let i = 0; i < nativeStartIndex; i++) {
|
||||
}
|
||||
}
|
||||
|
||||
if (scannedImports.exports.includes("default") && scannedImports.exports.length > 1) {
|
||||
const err = new Error(
|
||||
`Using \`export default\` AND named exports together in builtin modules is unsupported. See src/js/README.md (from ${moduleList[i]})`,
|
||||
);
|
||||
err.name = "BunError";
|
||||
err.fileName = moduleList[i];
|
||||
throw err;
|
||||
}
|
||||
let importStatements: string[] = [];
|
||||
|
||||
const processed = sliceSourceCode(
|
||||
|
||||
@@ -291,7 +291,7 @@ const SQL: typeof Bun.SQL = function SQL(
|
||||
|
||||
reserved_sql.connect = () => {
|
||||
if (state.connectionState & ReservedConnectionState.closed) {
|
||||
return Promise.$reject(this.connectionClosedError());
|
||||
return Promise.$reject(pool.connectionClosedError());
|
||||
}
|
||||
return Promise.$resolve(reserved_sql);
|
||||
};
|
||||
@@ -322,7 +322,7 @@ const SQL: typeof Bun.SQL = function SQL(
|
||||
reserved_sql.beginDistributed = (name: string, fn: TransactionCallback) => {
|
||||
// begin is allowed the difference is that we need to make sure to use the same connection and never release it
|
||||
if (state.connectionState & ReservedConnectionState.closed) {
|
||||
return Promise.$reject(this.connectionClosedError());
|
||||
return Promise.$reject(pool.connectionClosedError());
|
||||
}
|
||||
let callback = fn;
|
||||
|
||||
@@ -346,7 +346,7 @@ const SQL: typeof Bun.SQL = function SQL(
|
||||
state.connectionState & ReservedConnectionState.closed ||
|
||||
!(state.connectionState & ReservedConnectionState.acceptQueries)
|
||||
) {
|
||||
return Promise.$reject(this.connectionClosedError());
|
||||
return Promise.$reject(pool.connectionClosedError());
|
||||
}
|
||||
let callback = fn;
|
||||
let options: string | undefined = options_or_fn as unknown as string;
|
||||
@@ -369,7 +369,7 @@ const SQL: typeof Bun.SQL = function SQL(
|
||||
|
||||
reserved_sql.flush = () => {
|
||||
if (state.connectionState & ReservedConnectionState.closed) {
|
||||
throw this.connectionClosedError();
|
||||
throw pool.connectionClosedError();
|
||||
}
|
||||
// Use pooled connection's flush if available, otherwise use adapter's flush
|
||||
if (pooledConnection.flush) {
|
||||
@@ -429,7 +429,7 @@ const SQL: typeof Bun.SQL = function SQL(
|
||||
state.connectionState & ReservedConnectionState.closed ||
|
||||
!(state.connectionState & ReservedConnectionState.acceptQueries)
|
||||
) {
|
||||
return Promise.$reject(this.connectionClosedError());
|
||||
return Promise.$reject(pool.connectionClosedError());
|
||||
}
|
||||
// just release the connection back to the pool
|
||||
state.connectionState |= ReservedConnectionState.closed;
|
||||
@@ -552,7 +552,7 @@ const SQL: typeof Bun.SQL = function SQL(
|
||||
|
||||
function run_internal_transaction_sql(string) {
|
||||
if (state.connectionState & ReservedConnectionState.closed) {
|
||||
return Promise.$reject(this.connectionClosedError());
|
||||
return Promise.$reject(pool.connectionClosedError());
|
||||
}
|
||||
return unsafeQueryFromTransaction(string, [], pooledConnection, state.queries);
|
||||
}
|
||||
@@ -564,7 +564,7 @@ const SQL: typeof Bun.SQL = function SQL(
|
||||
state.connectionState & ReservedConnectionState.closed ||
|
||||
!(state.connectionState & ReservedConnectionState.acceptQueries)
|
||||
) {
|
||||
return Promise.$reject(this.connectionClosedError());
|
||||
return Promise.$reject(pool.connectionClosedError());
|
||||
}
|
||||
if ($isArray(strings)) {
|
||||
// detect if is tagged template
|
||||
@@ -593,7 +593,7 @@ const SQL: typeof Bun.SQL = function SQL(
|
||||
|
||||
transaction_sql.connect = () => {
|
||||
if (state.connectionState & ReservedConnectionState.closed) {
|
||||
return Promise.$reject(this.connectionClosedError());
|
||||
return Promise.$reject(pool.connectionClosedError());
|
||||
}
|
||||
|
||||
return Promise.$resolve(transaction_sql);
|
||||
@@ -732,7 +732,7 @@ const SQL: typeof Bun.SQL = function SQL(
|
||||
state.connectionState & ReservedConnectionState.closed ||
|
||||
!(state.connectionState & ReservedConnectionState.acceptQueries)
|
||||
) {
|
||||
throw this.connectionClosedError();
|
||||
throw pool.connectionClosedError();
|
||||
}
|
||||
|
||||
if ($isCallable(name)) {
|
||||
@@ -816,7 +816,7 @@ const SQL: typeof Bun.SQL = function SQL(
|
||||
|
||||
sql.reserve = () => {
|
||||
if (pool.closed) {
|
||||
return Promise.$reject(this.connectionClosedError());
|
||||
return Promise.$reject(pool.connectionClosedError());
|
||||
}
|
||||
|
||||
// Check if adapter supports reserved connections
|
||||
@@ -831,7 +831,7 @@ const SQL: typeof Bun.SQL = function SQL(
|
||||
};
|
||||
sql.rollbackDistributed = async function (name: string) {
|
||||
if (pool.closed) {
|
||||
throw this.connectionClosedError();
|
||||
throw pool.connectionClosedError();
|
||||
}
|
||||
|
||||
if (!pool.getRollbackDistributedSQL) {
|
||||
@@ -844,7 +844,7 @@ const SQL: typeof Bun.SQL = function SQL(
|
||||
|
||||
sql.commitDistributed = async function (name: string) {
|
||||
if (pool.closed) {
|
||||
throw this.connectionClosedError();
|
||||
throw pool.connectionClosedError();
|
||||
}
|
||||
|
||||
if (!pool.getCommitDistributedSQL) {
|
||||
@@ -857,7 +857,7 @@ const SQL: typeof Bun.SQL = function SQL(
|
||||
|
||||
sql.beginDistributed = (name: string, fn: TransactionCallback) => {
|
||||
if (pool.closed) {
|
||||
return Promise.$reject(this.connectionClosedError());
|
||||
return Promise.$reject(pool.connectionClosedError());
|
||||
}
|
||||
let callback = fn;
|
||||
|
||||
@@ -876,7 +876,7 @@ const SQL: typeof Bun.SQL = function SQL(
|
||||
|
||||
sql.begin = (options_or_fn: string | TransactionCallback, fn?: TransactionCallback) => {
|
||||
if (pool.closed) {
|
||||
return Promise.$reject(this.connectionClosedError());
|
||||
return Promise.$reject(pool.connectionClosedError());
|
||||
}
|
||||
let callback = fn;
|
||||
let options: string | undefined = options_or_fn as unknown as string;
|
||||
@@ -896,7 +896,7 @@ const SQL: typeof Bun.SQL = function SQL(
|
||||
};
|
||||
sql.connect = () => {
|
||||
if (pool.closed) {
|
||||
return Promise.$reject(this.connectionClosedError());
|
||||
return Promise.$reject(pool.connectionClosedError());
|
||||
}
|
||||
|
||||
if (pool.isConnected()) {
|
||||
|
||||
@@ -344,10 +344,13 @@ class PooledMySQLConnection {
|
||||
/// queryCount is used to indicate the number of queries using the connection, if a connection is reserved or if its a transaction queryCount will be 1 independently of the number of queries
|
||||
queryCount: number = 0;
|
||||
|
||||
#onConnected(err, _) {
|
||||
#onConnected(err, connection) {
|
||||
if (err) {
|
||||
err = wrapError(err);
|
||||
} else {
|
||||
this.connection = connection;
|
||||
}
|
||||
|
||||
const connectionInfo = this.connectionInfo;
|
||||
if (connectionInfo?.onconnect) {
|
||||
connectionInfo.onconnect(err);
|
||||
@@ -413,12 +416,8 @@ class PooledMySQLConnection {
|
||||
this.#startConnection();
|
||||
}
|
||||
|
||||
async #startConnection() {
|
||||
this.connection = await PooledMySQLConnection.createConnection(
|
||||
this.connectionInfo,
|
||||
this.#onConnected.bind(this),
|
||||
this.#onClose.bind(this),
|
||||
);
|
||||
#startConnection() {
|
||||
PooledMySQLConnection.createConnection(this.connectionInfo, this.#onConnected.bind(this), this.#onClose.bind(this));
|
||||
}
|
||||
|
||||
onClose(onClose: (err: Error) => void) {
|
||||
@@ -482,7 +481,7 @@ class PooledMySQLConnection {
|
||||
}
|
||||
}
|
||||
|
||||
export class MySQLAdapter
|
||||
class MySQLAdapter
|
||||
implements
|
||||
DatabaseAdapter<PooledMySQLConnection, $ZigGeneratedClasses.MySQLConnection, $ZigGeneratedClasses.MySQLQuery>
|
||||
{
|
||||
|
||||
@@ -499,7 +499,7 @@ class PooledPostgresConnection {
|
||||
}
|
||||
}
|
||||
|
||||
export class PostgresAdapter
|
||||
class PostgresAdapter
|
||||
implements
|
||||
DatabaseAdapter<
|
||||
PooledPostgresConnection,
|
||||
|
||||
@@ -293,7 +293,7 @@ function parseSQLQuery(query: string): SQLParsedInfo {
|
||||
return { command, firstKeyword, hasReturning };
|
||||
}
|
||||
|
||||
export class SQLiteQueryHandle implements BaseQueryHandle<BunSQLiteModule.Database> {
|
||||
class SQLiteQueryHandle implements BaseQueryHandle<BunSQLiteModule.Database> {
|
||||
private mode = SQLQueryResultMode.objects;
|
||||
|
||||
private readonly sql: string;
|
||||
@@ -380,9 +380,7 @@ export class SQLiteQueryHandle implements BaseQueryHandle<BunSQLiteModule.Databa
|
||||
}
|
||||
}
|
||||
|
||||
export class SQLiteAdapter
|
||||
implements DatabaseAdapter<BunSQLiteModule.Database, BunSQLiteModule.Database, SQLiteQueryHandle>
|
||||
{
|
||||
class SQLiteAdapter implements DatabaseAdapter<BunSQLiteModule.Database, BunSQLiteModule.Database, SQLiteQueryHandle> {
|
||||
public readonly connectionInfo: Bun.SQL.__internal.DefinedSQLiteOptions;
|
||||
public db: BunSQLiteModule.Database | null = null;
|
||||
public storedError: Error | null = null;
|
||||
@@ -807,4 +805,5 @@ export default {
|
||||
SQLCommand,
|
||||
commandToString,
|
||||
parseSQLQuery,
|
||||
SQLiteQueryHandle,
|
||||
};
|
||||
|
||||
@@ -21,8 +21,7 @@ poll_ref: bun.Async.KeepAlive = .{},
|
||||
globalObject: *jsc.JSGlobalObject,
|
||||
vm: *jsc.VirtualMachine,
|
||||
|
||||
pending_activity_count: std.atomic.Value(u32) = std.atomic.Value(u32).init(0),
|
||||
js_value: JSValue = .js_undefined,
|
||||
js_value: jsc.JSRef = jsc.JSRef.empty(),
|
||||
|
||||
server_version: bun.ByteList = .{},
|
||||
connection_id: u32 = 0,
|
||||
@@ -122,14 +121,14 @@ pub const AuthState = union(enum) {
|
||||
};
|
||||
};
|
||||
|
||||
pub fn hasPendingActivity(this: *MySQLConnection) bool {
|
||||
return this.pending_activity_count.load(.acquire) > 0;
|
||||
}
|
||||
|
||||
fn updateHasPendingActivity(this: *MySQLConnection) void {
|
||||
const a: u32 = if (this.requests.readableLength() > 0) 1 else 0;
|
||||
const b: u32 = if (this.status != .disconnected) 1 else 0;
|
||||
this.pending_activity_count.store(a + b, .release);
|
||||
fn updateReferenceType(this: *MySQLConnection) void {
|
||||
if (this.js_value.isNotEmpty()) {
|
||||
if (this.requests.readableLength() > 0 or (this.status != .disconnected and this.status != .failed)) {
|
||||
this.js_value.upgrade(this.globalObject);
|
||||
return;
|
||||
}
|
||||
this.js_value.downgrade();
|
||||
}
|
||||
}
|
||||
|
||||
fn hasDataToSend(this: *@This()) bool {
|
||||
@@ -225,15 +224,16 @@ pub fn onConnectionTimeout(this: *@This()) bun.api.Timer.EventLoopTimer.Arm {
|
||||
.connected => {
|
||||
this.failFmt(error.IdleTimeout, "Idle timeout reached after {}", .{bun.fmt.fmtDurationOneDecimal(@as(u64, this.idle_timeout_interval_ms) *| std.time.ns_per_ms)});
|
||||
},
|
||||
else => {
|
||||
.connecting => {
|
||||
this.failFmt(error.ConnectionTimedOut, "Connection timeout after {}", .{bun.fmt.fmtDurationOneDecimal(@as(u64, this.connection_timeout_ms) *| std.time.ns_per_ms)});
|
||||
},
|
||||
.handshaking,
|
||||
.authenticating,
|
||||
.authentication_awaiting_pk,
|
||||
=> {
|
||||
this.failFmt(error.ConnectionTimedOut, "Connection timed out after {} (during authentication)", .{bun.fmt.fmtDurationOneDecimal(@as(u64, this.connection_timeout_ms) *| std.time.ns_per_ms)});
|
||||
this.failFmt(error.ConnectionTimedOut, "Connection timeout after {} (during authentication)", .{bun.fmt.fmtDurationOneDecimal(@as(u64, this.connection_timeout_ms) *| std.time.ns_per_ms)});
|
||||
},
|
||||
.disconnected, .failed => {},
|
||||
}
|
||||
return .disarm;
|
||||
}
|
||||
@@ -264,28 +264,24 @@ fn drainInternal(this: *@This()) void {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn finalize(this: *MySQLConnection) void {
|
||||
this.stopTimers();
|
||||
debug("MySQLConnection finalize", .{});
|
||||
|
||||
// Ensure we disconnect before finalizing
|
||||
if (this.status != .disconnected) {
|
||||
this.disconnect();
|
||||
}
|
||||
|
||||
this.js_value = .zero;
|
||||
this.js_value.finalize();
|
||||
this.deref();
|
||||
}
|
||||
|
||||
pub fn doRef(this: *@This(), _: *jsc.JSGlobalObject, _: *jsc.CallFrame) bun.JSError!JSValue {
|
||||
this.poll_ref.ref(this.vm);
|
||||
this.updateHasPendingActivity();
|
||||
this.updateReferenceType();
|
||||
return .js_undefined;
|
||||
}
|
||||
|
||||
pub fn doUnref(this: *@This(), _: *jsc.JSGlobalObject, _: *jsc.CallFrame) bun.JSError!JSValue {
|
||||
this.poll_ref.unref(this.vm);
|
||||
this.updateHasPendingActivity();
|
||||
this.updateReferenceType();
|
||||
return .js_undefined;
|
||||
}
|
||||
|
||||
@@ -352,7 +348,10 @@ pub fn stopTimers(this: *@This()) void {
|
||||
}
|
||||
|
||||
pub fn getQueriesArray(this: *const @This()) JSValue {
|
||||
return js.queriesGetCached(this.js_value) orelse .js_undefined;
|
||||
if (this.js_value.tryGet()) |value| {
|
||||
return js.queriesGetCached(value) orelse .js_undefined;
|
||||
}
|
||||
return .js_undefined;
|
||||
}
|
||||
pub fn failFmt(this: *@This(), error_code: AnyMySQLError.Error, comptime fmt: [:0]const u8, args: anytype) void {
|
||||
const message = bun.handleOom(std.fmt.allocPrint(bun.default_allocator, fmt, args));
|
||||
@@ -362,28 +361,35 @@ pub fn failFmt(this: *@This(), error_code: AnyMySQLError.Error, comptime fmt: [:
|
||||
this.failWithJSValue(err);
|
||||
}
|
||||
pub fn failWithJSValue(this: *MySQLConnection, value: JSValue) void {
|
||||
defer this.updateHasPendingActivity();
|
||||
defer this.updateReferenceType();
|
||||
this.stopTimers();
|
||||
if (this.status == .failed) return;
|
||||
this.setStatus(.failed);
|
||||
|
||||
this.ref();
|
||||
defer this.deref();
|
||||
// we defer the refAndClose so the on_close will be called first before we reject the pending requests
|
||||
defer this.refAndClose(value);
|
||||
const on_close = this.consumeOnCloseCallback(this.globalObject) orelse return;
|
||||
defer {
|
||||
// we defer the refAndClose so the on_close will be called first before we reject the pending requests
|
||||
this.refAndClose(value);
|
||||
this.deref();
|
||||
}
|
||||
|
||||
this.status = .failed;
|
||||
if (this.vm.isShuttingDown()) return;
|
||||
|
||||
const on_close = this.consumeOnCloseCallback(this.globalObject) orelse return;
|
||||
on_close.ensureStillAlive();
|
||||
const loop = this.vm.eventLoop();
|
||||
loop.enter();
|
||||
defer loop.exit();
|
||||
_ = on_close.call(
|
||||
this.globalObject,
|
||||
this.js_value,
|
||||
&[_]JSValue{
|
||||
value,
|
||||
this.getQueriesArray(),
|
||||
},
|
||||
) catch |e| this.globalObject.reportActiveExceptionAsUnhandled(e);
|
||||
|
||||
var js_error = value.toError() orelse value;
|
||||
if (js_error == .zero) {
|
||||
js_error = AnyMySQLError.mysqlErrorToJS(this.globalObject, "Connection closed", error.ConnectionClosed);
|
||||
}
|
||||
js_error.ensureStillAlive();
|
||||
|
||||
const queries_array = this.getQueriesArray();
|
||||
queries_array.ensureStillAlive();
|
||||
this.globalObject.queueMicrotask(on_close, &[_]JSValue{ js_error, queries_array });
|
||||
}
|
||||
|
||||
pub fn fail(this: *MySQLConnection, message: []const u8, err: AnyMySQLError.Error) void {
|
||||
@@ -392,30 +398,36 @@ pub fn fail(this: *MySQLConnection, message: []const u8, err: AnyMySQLError.Erro
|
||||
this.failWithJSValue(instance);
|
||||
}
|
||||
|
||||
pub fn onClose(this: *MySQLConnection) void {
|
||||
var vm = this.vm;
|
||||
defer vm.drainMicrotasks();
|
||||
pub fn onEnd(this: *MySQLConnection) void {
|
||||
// no more socket
|
||||
this.fail("Connection closed", error.ConnectionClosed);
|
||||
}
|
||||
|
||||
pub fn onClose(this: *MySQLConnection) void {
|
||||
// no more socket
|
||||
defer this.deref();
|
||||
this.onEnd();
|
||||
}
|
||||
|
||||
fn refAndClose(this: *@This(), js_reason: ?jsc.JSValue) void {
|
||||
// refAndClose is always called when we wanna to disconnect or when we are closed
|
||||
|
||||
// cleanup requests
|
||||
this.cleanUpRequests(js_reason);
|
||||
|
||||
if (!this.socket.isClosed()) {
|
||||
// event loop need to be alive to close the socket
|
||||
this.poll_ref.ref(this.vm);
|
||||
// will unref on socket close
|
||||
this.socket.close();
|
||||
}
|
||||
|
||||
// cleanup requests
|
||||
this.cleanUpRequests(js_reason);
|
||||
}
|
||||
|
||||
pub fn disconnect(this: *@This()) void {
|
||||
this.stopTimers();
|
||||
if (this.status == .connected) {
|
||||
this.setStatus(.disconnected);
|
||||
defer this.updateReferenceType();
|
||||
this.status = .disconnected;
|
||||
this.poll_ref.disable();
|
||||
|
||||
const requests = this.requests.readableSlice(0);
|
||||
@@ -721,12 +733,12 @@ fn SocketHandler(comptime ssl: bool) type {
|
||||
|
||||
pub fn onEnd(this: *MySQLConnection, socket: SocketType) void {
|
||||
_ = socket;
|
||||
this.onClose();
|
||||
this.onEnd();
|
||||
}
|
||||
|
||||
pub fn onConnectError(this: *MySQLConnection, socket: SocketType, _: i32) void {
|
||||
_ = socket;
|
||||
this.onClose();
|
||||
this.onEnd();
|
||||
}
|
||||
|
||||
pub fn onTimeout(this: *MySQLConnection, socket: SocketType) void {
|
||||
@@ -747,7 +759,7 @@ fn SocketHandler(comptime ssl: bool) type {
|
||||
}
|
||||
|
||||
pub fn onTimeout(this: *MySQLConnection) void {
|
||||
this.fail("Connection timed out", error.ConnectionTimedOut);
|
||||
this.fail("Connection timeout", error.ConnectionTimedOut);
|
||||
}
|
||||
|
||||
pub fn onDrain(this: *MySQLConnection) void {
|
||||
@@ -938,12 +950,11 @@ pub fn call(globalObject: *jsc.JSGlobalObject, callframe: *jsc.CallFrame) bun.JS
|
||||
}
|
||||
}
|
||||
ptr.setStatus(.connecting);
|
||||
ptr.updateHasPendingActivity();
|
||||
ptr.resetConnectionTimeout();
|
||||
ptr.poll_ref.ref(vm);
|
||||
const js_value = ptr.toJS(globalObject);
|
||||
js_value.ensureStillAlive();
|
||||
ptr.js_value = js_value;
|
||||
ptr.js_value.setStrong(js_value, globalObject);
|
||||
js.onconnectSetCached(js_value, globalObject, on_connect);
|
||||
js.oncloseSetCached(js_value, globalObject, on_close);
|
||||
|
||||
@@ -951,7 +962,6 @@ pub fn call(globalObject: *jsc.JSGlobalObject, callframe: *jsc.CallFrame) bun.JS
|
||||
}
|
||||
|
||||
pub fn deinit(this: *MySQLConnection) void {
|
||||
this.disconnect();
|
||||
this.stopTimers();
|
||||
debug("MySQLConnection deinit", .{});
|
||||
|
||||
@@ -962,10 +972,7 @@ pub fn deinit(this: *MySQLConnection) void {
|
||||
// Clear any pending requests first
|
||||
for (requests.readableSlice(0)) |request| {
|
||||
this.finishRequest(request);
|
||||
request.onError(.{
|
||||
.error_code = 2013,
|
||||
.error_message = .{ .temporary = "Connection closed" },
|
||||
}, this.globalObject);
|
||||
request.deref();
|
||||
}
|
||||
this.write_buffer.deinit(bun.default_allocator);
|
||||
this.read_buffer.deinit(bun.default_allocator);
|
||||
@@ -1002,10 +1009,11 @@ pub fn onOpen(this: *MySQLConnection, socket: Socket) void {
|
||||
this.socket = socket;
|
||||
if (socket == .SocketTCP) {
|
||||
// when upgrading to TLS the onOpen callback will be called again and at this moment we dont wanna to change the status to handshaking
|
||||
this.setStatus(.handshaking);
|
||||
this.status = .handshaking;
|
||||
this.ref(); // keep a ref for the socket
|
||||
}
|
||||
this.poll_ref.ref(this.vm);
|
||||
this.updateHasPendingActivity();
|
||||
this.updateReferenceType();
|
||||
}
|
||||
|
||||
pub fn onHandshake(this: *MySQLConnection, success: i32, ssl_error: uws.us_bun_verify_error_t) void {
|
||||
@@ -1143,11 +1151,12 @@ pub fn processPackets(this: *MySQLConnection, comptime Context: type, reader: Ne
|
||||
// Read packet header
|
||||
const header = PacketHeader.decode(reader.peek()) orelse return AnyMySQLError.Error.ShortRead;
|
||||
const header_length = header.length;
|
||||
const packet_length: usize = header_length + PacketHeader.size;
|
||||
debug("sequence_id: {d} header: {d}", .{ this.sequence_id, header_length });
|
||||
// Ensure we have the full packet
|
||||
reader.ensureCapacity(header_length + PacketHeader.size) catch return AnyMySQLError.Error.ShortRead;
|
||||
reader.ensureCapacity(packet_length) catch return AnyMySQLError.Error.ShortRead;
|
||||
// always skip the full packet, we dont care about padding or unreaded bytes
|
||||
defer reader.setOffsetFromStart(header_length + PacketHeader.size);
|
||||
defer reader.setOffsetFromStart(packet_length);
|
||||
reader.skip(PacketHeader.size);
|
||||
|
||||
// Update sequence id
|
||||
@@ -1270,24 +1279,35 @@ fn handleHandshakeDecodePublicKey(this: *MySQLConnection, comptime Context: type
|
||||
|
||||
pub fn consumeOnConnectCallback(this: *const @This(), globalObject: *jsc.JSGlobalObject) ?jsc.JSValue {
|
||||
debug("consumeOnConnectCallback", .{});
|
||||
const on_connect = js.onconnectGetCached(this.js_value) orelse return null;
|
||||
debug("consumeOnConnectCallback exists", .{});
|
||||
|
||||
js.onconnectSetCached(this.js_value, globalObject, .zero);
|
||||
return on_connect;
|
||||
if (this.js_value.tryGet()) |value| {
|
||||
const on_connect = js.onconnectGetCached(value) orelse return null;
|
||||
debug("consumeOnConnectCallback exists", .{});
|
||||
js.onconnectSetCached(value, globalObject, .zero);
|
||||
if (on_connect == .zero) {
|
||||
return null;
|
||||
}
|
||||
return on_connect;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
pub fn consumeOnCloseCallback(this: *const @This(), globalObject: *jsc.JSGlobalObject) ?jsc.JSValue {
|
||||
debug("consumeOnCloseCallback", .{});
|
||||
const on_close = js.oncloseGetCached(this.js_value) orelse return null;
|
||||
debug("consumeOnCloseCallback exists", .{});
|
||||
js.oncloseSetCached(this.js_value, globalObject, .zero);
|
||||
return on_close;
|
||||
if (this.js_value.tryGet()) |value| {
|
||||
const on_close = js.oncloseGetCached(value) orelse return null;
|
||||
debug("consumeOnCloseCallback exists", .{});
|
||||
js.oncloseSetCached(value, globalObject, .zero);
|
||||
if (on_close == .zero) {
|
||||
return null;
|
||||
}
|
||||
return on_close;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
pub fn setStatus(this: *@This(), status: ConnectionState) void {
|
||||
if (this.status == status) return;
|
||||
defer this.updateHasPendingActivity();
|
||||
defer this.updateReferenceType();
|
||||
|
||||
this.status = status;
|
||||
this.resetConnectionTimeout();
|
||||
@@ -1296,7 +1316,8 @@ pub fn setStatus(this: *@This(), status: ConnectionState) void {
|
||||
switch (status) {
|
||||
.connected => {
|
||||
const on_connect = this.consumeOnConnectCallback(this.globalObject) orelse return;
|
||||
const js_value = this.js_value;
|
||||
on_connect.ensureStillAlive();
|
||||
var js_value = this.js_value.tryGet() orelse .js_undefined;
|
||||
js_value.ensureStillAlive();
|
||||
this.globalObject.queueMicrotask(on_connect, &[_]JSValue{ JSValue.jsNull(), js_value });
|
||||
this.poll_ref.unref(this.vm);
|
||||
@@ -1306,8 +1327,8 @@ pub fn setStatus(this: *@This(), status: ConnectionState) void {
|
||||
}
|
||||
|
||||
pub fn updateRef(this: *@This()) void {
|
||||
this.updateHasPendingActivity();
|
||||
if (this.pending_activity_count.raw > 0) {
|
||||
this.updateReferenceType();
|
||||
if (this.js_value == .strong) {
|
||||
this.poll_ref.ref(this.vm);
|
||||
} else {
|
||||
this.poll_ref.unref(this.vm);
|
||||
@@ -1765,7 +1786,7 @@ fn handleResultSetOK(this: *MySQLConnection, request: *MySQLQuery, statement: *M
|
||||
request.onResult(
|
||||
statement.result_count,
|
||||
this.globalObject,
|
||||
this.js_value,
|
||||
this.getQueriesArray(),
|
||||
this.flags.is_ready_for_query,
|
||||
last_insert_id,
|
||||
affected_rows,
|
||||
@@ -1874,7 +1895,7 @@ pub fn handleResultSet(this: *MySQLConnection, comptime Context: type, reader: N
|
||||
var cached_structure: ?CachedStructure = null;
|
||||
switch (request.flags.result_mode) {
|
||||
.objects => {
|
||||
cached_structure = statement.structure(this.js_value, this.globalObject);
|
||||
cached_structure = if (this.js_value.tryGet()) |value| statement.structure(value, this.globalObject) else null;
|
||||
structure = cached_structure.?.jsValue() orelse .js_undefined;
|
||||
},
|
||||
.raw, .values => {
|
||||
@@ -1884,7 +1905,7 @@ pub fn handleResultSet(this: *MySQLConnection, comptime Context: type, reader: N
|
||||
defer row.deinit(allocator);
|
||||
try row.decode(allocator, reader);
|
||||
|
||||
const pending_value = MySQLQuery.js.pendingValueGetCached(request.thisValue.get()) orelse .zero;
|
||||
const pending_value = (if (request.thisValue.tryGet()) |value| MySQLQuery.js.pendingValueGetCached(value) else .js_undefined) orelse .js_undefined;
|
||||
|
||||
// Process row data
|
||||
const row_value = row.toJS(
|
||||
@@ -1902,8 +1923,10 @@ pub fn handleResultSet(this: *MySQLConnection, comptime Context: type, reader: N
|
||||
}
|
||||
statement.result_count += 1;
|
||||
|
||||
if (pending_value == .zero) {
|
||||
MySQLQuery.js.pendingValueSetCached(request.thisValue.get(), this.globalObject, row_value);
|
||||
if (pending_value.isEmptyOrUndefinedOrNull()) {
|
||||
if (request.thisValue.tryGet()) |value| {
|
||||
MySQLQuery.js.pendingValueSetCached(value, this.globalObject, row_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const MySQLQuery = @This();
|
||||
const RefCount = bun.ptr.ThreadSafeRefCount(@This(), "ref_count", deinit, .{});
|
||||
const RefCount = bun.ptr.RefCount(@This(), "ref_count", deinit, .{});
|
||||
|
||||
statement: ?*MySQLStatement = null,
|
||||
query: bun.String = bun.String.empty,
|
||||
@@ -42,12 +42,7 @@ pub const Status = enum(u8) {
|
||||
}
|
||||
};
|
||||
|
||||
pub fn hasPendingActivity(this: *@This()) bool {
|
||||
return this.ref_count.load(.monotonic) > 1;
|
||||
}
|
||||
|
||||
pub fn deinit(this: *@This()) void {
|
||||
this.thisValue.deinit();
|
||||
if (this.statement) |statement| {
|
||||
statement.deref();
|
||||
}
|
||||
@@ -66,11 +61,7 @@ pub fn finalize(this: *@This()) void {
|
||||
this.statement = null;
|
||||
}
|
||||
|
||||
if (this.thisValue == .weak) {
|
||||
// clean up if is a weak reference, if is a strong reference we need to wait until the query is done
|
||||
// if we are a strong reference, here is probably a bug because GC'd should not happen
|
||||
this.thisValue.weak = .zero;
|
||||
}
|
||||
this.thisValue.finalize();
|
||||
this.deref();
|
||||
}
|
||||
|
||||
@@ -81,24 +72,24 @@ pub fn onWriteFail(
|
||||
queries_array: JSValue,
|
||||
) void {
|
||||
this.status = .fail;
|
||||
const thisValue = this.thisValue.get();
|
||||
defer this.thisValue.deinit();
|
||||
const targetValue = this.getTarget(globalObject, true);
|
||||
if (thisValue == .zero or targetValue == .zero) {
|
||||
return;
|
||||
}
|
||||
const thisValue = this.thisValue.tryGet() orelse return;
|
||||
defer this.thisValue.downgrade();
|
||||
const targetValue = this.getTarget(globalObject, true) orelse return;
|
||||
|
||||
const instance = AnyMySQLError.mysqlErrorToJS(globalObject, "Failed to bind query", err);
|
||||
|
||||
const js_err = instance.toError() orelse instance;
|
||||
bun.assertf(js_err != .zero, "js_err is zero", .{});
|
||||
js_err.ensureStillAlive();
|
||||
const vm = jsc.VirtualMachine.get();
|
||||
const function = vm.rareData().mysql_context.onQueryRejectFn.get().?;
|
||||
const function = vm.rareData().mysql_context.onQueryRejectFn.get() orelse return;
|
||||
bun.assertf(function.isCallable(), "onQueryRejectFn is not callable", .{});
|
||||
const event_loop = vm.eventLoop();
|
||||
const js_array = if (queries_array == .zero) .js_undefined else queries_array;
|
||||
js_array.ensureStillAlive();
|
||||
event_loop.runCallback(function, globalObject, thisValue, &.{
|
||||
targetValue,
|
||||
// TODO: add mysql error to JS
|
||||
// postgresErrorToJS(globalObject, null, err),
|
||||
instance,
|
||||
queries_array,
|
||||
js_err,
|
||||
js_array,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -124,9 +115,9 @@ pub fn bindAndExecute(this: *MySQLQuery, writer: anytype, statement: *MySQLState
|
||||
}
|
||||
|
||||
fn bind(this: *MySQLQuery, execute: *PreparedStatement.Execute, globalObject: *jsc.JSGlobalObject) AnyMySQLError.Error!void {
|
||||
const thisValue = this.thisValue.get();
|
||||
const binding_value = js.bindingGetCached(thisValue) orelse .zero;
|
||||
const columns_value = js.columnsGetCached(thisValue) orelse .zero;
|
||||
const thisValue = this.thisValue.tryGet() orelse return error.InvalidState;
|
||||
const binding_value = js.bindingGetCached(thisValue) orelse .js_undefined;
|
||||
const columns_value = js.columnsGetCached(thisValue) orelse .js_undefined;
|
||||
|
||||
var iter = try QueryBindingIterator.init(binding_value, columns_value, globalObject);
|
||||
|
||||
@@ -167,24 +158,27 @@ pub fn onJSError(this: *@This(), err: jsc.JSValue, globalObject: *jsc.JSGlobalOb
|
||||
this.ref();
|
||||
defer this.deref();
|
||||
this.status = .fail;
|
||||
const thisValue = this.thisValue.get();
|
||||
defer this.thisValue.deinit();
|
||||
const targetValue = this.getTarget(globalObject, true);
|
||||
if (thisValue == .zero or targetValue == .zero) {
|
||||
return;
|
||||
}
|
||||
const thisValue = this.thisValue.tryGet() orelse return;
|
||||
defer this.thisValue.downgrade();
|
||||
const targetValue = this.getTarget(globalObject, true) orelse return;
|
||||
|
||||
var vm = jsc.VirtualMachine.get();
|
||||
const function = vm.rareData().mysql_context.onQueryRejectFn.get().?;
|
||||
const function = vm.rareData().mysql_context.onQueryRejectFn.get() orelse return;
|
||||
bun.assertf(function.isCallable(), "onQueryRejectFn is not callable", .{});
|
||||
const event_loop = vm.eventLoop();
|
||||
var js_error = err.toError() orelse err;
|
||||
if (js_error == .zero) {
|
||||
js_error = AnyMySQLError.mysqlErrorToJS(globalObject, "Query failed", error.UnknownError);
|
||||
}
|
||||
js_error.ensureStillAlive();
|
||||
event_loop.runCallback(function, globalObject, thisValue, &.{
|
||||
targetValue,
|
||||
err,
|
||||
js_error,
|
||||
});
|
||||
}
|
||||
pub fn getTarget(this: *@This(), globalObject: *jsc.JSGlobalObject, clean_target: bool) jsc.JSValue {
|
||||
const thisValue = this.thisValue.tryGet() orelse return .zero;
|
||||
const target = js.targetGetCached(thisValue) orelse return .zero;
|
||||
pub fn getTarget(this: *@This(), globalObject: *jsc.JSGlobalObject, clean_target: bool) ?jsc.JSValue {
|
||||
const thisValue = this.thisValue.tryGet() orelse return null;
|
||||
const target = js.targetGetCached(thisValue) orelse return null;
|
||||
if (clean_target) {
|
||||
js.targetSetCached(thisValue, globalObject, .zero);
|
||||
}
|
||||
@@ -197,17 +191,6 @@ fn consumePendingValue(thisValue: jsc.JSValue, globalObject: *jsc.JSGlobalObject
|
||||
return pending_value;
|
||||
}
|
||||
|
||||
pub fn allowGC(thisValue: jsc.JSValue, globalObject: *jsc.JSGlobalObject) void {
|
||||
if (thisValue == .zero) {
|
||||
return;
|
||||
}
|
||||
|
||||
defer thisValue.ensureStillAlive();
|
||||
js.bindingSetCached(thisValue, globalObject, .zero);
|
||||
js.pendingValueSetCached(thisValue, globalObject, .zero);
|
||||
js.targetSetCached(thisValue, globalObject, .zero);
|
||||
}
|
||||
|
||||
fn u64ToJSValue(value: u64) JSValue {
|
||||
if (value <= jsc.MAX_SAFE_INTEGER) {
|
||||
return JSValue.jsNumber(value);
|
||||
@@ -215,36 +198,39 @@ fn u64ToJSValue(value: u64) JSValue {
|
||||
return JSValue.jsBigInt(value);
|
||||
}
|
||||
|
||||
pub fn onResult(this: *@This(), result_count: u64, globalObject: *jsc.JSGlobalObject, connection: jsc.JSValue, is_last: bool, last_insert_id: u64, affected_rows: u64) void {
|
||||
pub fn onResult(this: *@This(), result_count: u64, globalObject: *jsc.JSGlobalObject, queries_array: jsc.JSValue, is_last: bool, last_insert_id: u64, affected_rows: u64) void {
|
||||
this.ref();
|
||||
defer this.deref();
|
||||
|
||||
const thisValue = this.thisValue.get();
|
||||
const targetValue = this.getTarget(globalObject, is_last);
|
||||
if (is_last) {
|
||||
this.status = .success;
|
||||
} else {
|
||||
this.status = .partial_response;
|
||||
}
|
||||
|
||||
const tag: CommandTag = .{ .SELECT = result_count };
|
||||
const js_tag = tag.toJSTag(globalObject) catch |e| return this.onJSError(globalObject.takeException(e), globalObject);
|
||||
js_tag.ensureStillAlive();
|
||||
|
||||
const thisValue = this.thisValue.tryGet() orelse return;
|
||||
|
||||
defer if (is_last) {
|
||||
allowGC(thisValue, globalObject);
|
||||
this.thisValue.deinit();
|
||||
this.thisValue.downgrade();
|
||||
};
|
||||
if (thisValue == .zero or targetValue == .zero) {
|
||||
return;
|
||||
}
|
||||
const targetValue = this.getTarget(globalObject, is_last) orelse return;
|
||||
|
||||
const vm = jsc.VirtualMachine.get();
|
||||
const function = vm.rareData().mysql_context.onQueryResolveFn.get().?;
|
||||
const function = vm.rareData().mysql_context.onQueryResolveFn.get() orelse return;
|
||||
bun.assertf(function.isCallable(), "onQueryResolveFn is not callable", .{});
|
||||
|
||||
const event_loop = vm.eventLoop();
|
||||
const tag: CommandTag = .{ .SELECT = result_count };
|
||||
|
||||
event_loop.runCallback(function, globalObject, thisValue, &.{
|
||||
targetValue,
|
||||
consumePendingValue(thisValue, globalObject) orelse .js_undefined,
|
||||
tag.toJSTag(globalObject),
|
||||
js_tag,
|
||||
tag.toJSNumber(),
|
||||
if (connection == .zero) .js_undefined else MySQLConnection.js.queriesGetCached(connection) orelse .js_undefined,
|
||||
queries_array,
|
||||
JSValue.jsBoolean(is_last),
|
||||
JSValue.jsNumber(last_insert_id),
|
||||
JSValue.jsNumber(affected_rows),
|
||||
@@ -324,9 +310,9 @@ pub fn call(globalThis: *jsc.JSGlobalObject, callframe: *jsc.CallFrame) bun.JSEr
|
||||
|
||||
return this_value;
|
||||
}
|
||||
pub fn setPendingValue(this: *@This(), globalObject: *jsc.JSGlobalObject, callframe: *jsc.CallFrame) bun.JSError!JSValue {
|
||||
pub fn setPendingValue(_: *@This(), globalObject: *jsc.JSGlobalObject, callframe: *jsc.CallFrame) bun.JSError!JSValue {
|
||||
const result = callframe.argument(0);
|
||||
const thisValue = this.thisValue.tryGet() orelse return .js_undefined;
|
||||
const thisValue = callframe.this();
|
||||
js.pendingValueSetCached(thisValue, globalObject, result);
|
||||
return .js_undefined;
|
||||
}
|
||||
@@ -364,7 +350,7 @@ pub fn doRun(this: *MySQLQuery, globalObject: *jsc.JSGlobalObject, callframe: *j
|
||||
return globalObject.throw("connection must be a MySQLConnection", .{});
|
||||
};
|
||||
|
||||
connection.poll_ref.ref(globalObject.bunVM());
|
||||
defer connection.updateRef();
|
||||
var query = arguments[1];
|
||||
|
||||
if (!query.isObject()) {
|
||||
|
||||
@@ -33,6 +33,8 @@ pub const Error = error{
|
||||
InvalidErrorPacket,
|
||||
UnexpectedPacket,
|
||||
ShortRead,
|
||||
UnknownError,
|
||||
InvalidState,
|
||||
};
|
||||
|
||||
pub fn mysqlErrorToJS(globalObject: *jsc.JSGlobalObject, message: ?[]const u8, err: Error) JSValue {
|
||||
@@ -64,6 +66,8 @@ pub fn mysqlErrorToJS(globalObject: *jsc.JSGlobalObject, message: ?[]const u8, e
|
||||
error.MissingAuthData => "ERR_MYSQL_MISSING_AUTH_DATA",
|
||||
error.FailedToEncryptPassword => "ERR_MYSQL_FAILED_TO_ENCRYPT_PASSWORD",
|
||||
error.InvalidPublicKey => "ERR_MYSQL_INVALID_PUBLIC_KEY",
|
||||
error.UnknownError => "ERR_MYSQL_UNKNOWN_ERROR",
|
||||
error.InvalidState => "ERR_MYSQL_INVALID_STATE",
|
||||
error.JSError => {
|
||||
return globalObject.takeException(error.JSError);
|
||||
},
|
||||
|
||||
@@ -19,7 +19,7 @@ pub fn createMySQLError(
|
||||
message: []const u8,
|
||||
options: MySQLErrorOptions,
|
||||
) bun.JSError!JSValue {
|
||||
const opts_obj = JSValue.createEmptyObject(globalObject, 18);
|
||||
const opts_obj = JSValue.createEmptyObject(globalObject, 0);
|
||||
opts_obj.ensureStillAlive();
|
||||
opts_obj.put(globalObject, JSC.ZigString.static("code"), try bun.String.createUTF8ForJS(globalObject, options.code));
|
||||
if (options.errno) |errno| {
|
||||
|
||||
@@ -29,7 +29,7 @@ pub const CommandTag = union(enum) {
|
||||
|
||||
other: []const u8,
|
||||
|
||||
pub fn toJSTag(this: CommandTag, globalObject: *jsc.JSGlobalObject) JSValue {
|
||||
pub fn toJSTag(this: CommandTag, globalObject: *jsc.JSGlobalObject) bun.JSError!jsc.JSValue {
|
||||
return switch (this) {
|
||||
.INSERT => JSValue.jsNumber(1),
|
||||
.DELETE => JSValue.jsNumber(2),
|
||||
@@ -39,7 +39,7 @@ pub const CommandTag = union(enum) {
|
||||
.MOVE => JSValue.jsNumber(6),
|
||||
.FETCH => JSValue.jsNumber(7),
|
||||
.COPY => JSValue.jsNumber(8),
|
||||
.other => |tag| jsc.ZigString.init(tag).toJS(globalObject),
|
||||
.other => |tag| bun.String.createUTF8ForJS(globalObject, tag),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -219,7 +219,7 @@ pub fn onConnectionTimeout(this: *PostgresSQLConnection) bun.api.Timer.EventLoop
|
||||
this.failFmt("ERR_POSTGRES_CONNECTION_TIMEOUT", "Connection timeout after {}", .{bun.fmt.fmtDurationOneDecimal(@as(u64, this.connection_timeout_ms) *| std.time.ns_per_ms)});
|
||||
},
|
||||
.sent_startup_message => {
|
||||
this.failFmt("ERR_POSTGRES_CONNECTION_TIMEOUT", "Connection timed out after {} (sent startup message, but never received response)", .{bun.fmt.fmtDurationOneDecimal(@as(u64, this.connection_timeout_ms) *| std.time.ns_per_ms)});
|
||||
this.failFmt("ERR_POSTGRES_CONNECTION_TIMEOUT", "Connection timeout after {} (sent startup message, but never received response)", .{bun.fmt.fmtDurationOneDecimal(@as(u64, this.connection_timeout_ms) *| std.time.ns_per_ms)});
|
||||
},
|
||||
}
|
||||
return .disarm;
|
||||
@@ -311,7 +311,7 @@ pub fn failWithJSValue(this: *PostgresSQLConnection, value: JSValue) void {
|
||||
this.stopTimers();
|
||||
if (this.status == .failed) return;
|
||||
|
||||
this.setStatus(.failed);
|
||||
this.status = .failed;
|
||||
|
||||
this.ref();
|
||||
defer this.deref();
|
||||
@@ -321,12 +321,17 @@ pub fn failWithJSValue(this: *PostgresSQLConnection, value: JSValue) void {
|
||||
|
||||
const loop = this.vm.eventLoop();
|
||||
loop.enter();
|
||||
var js_error = value.toError() orelse value;
|
||||
if (js_error == .zero) {
|
||||
js_error = postgresErrorToJS(this.globalObject, "Connection closed", error.ConnectionClosed);
|
||||
}
|
||||
js_error.ensureStillAlive();
|
||||
defer loop.exit();
|
||||
_ = on_close.call(
|
||||
this.globalObject,
|
||||
this.js_value,
|
||||
.js_undefined,
|
||||
&[_]JSValue{
|
||||
value.toError() orelse value,
|
||||
js_error,
|
||||
this.getQueriesArray(),
|
||||
},
|
||||
) catch |e| this.globalObject.reportActiveExceptionAsUnhandled(e);
|
||||
@@ -1350,6 +1355,9 @@ fn advance(this: *PostgresSQLConnection) void {
|
||||
}
|
||||
|
||||
pub fn getQueriesArray(this: *const PostgresSQLConnection) JSValue {
|
||||
if (this.js_value.isEmptyOrUndefinedOrNull()) {
|
||||
return .js_undefined;
|
||||
}
|
||||
return js.queriesGetCached(this.js_value) orelse .js_undefined;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const PostgresSQLQuery = @This();
|
||||
const RefCount = bun.ptr.ThreadSafeRefCount(@This(), "ref_count", deinit, .{});
|
||||
const RefCount = bun.ptr.RefCount(@This(), "ref_count", deinit, .{});
|
||||
statement: ?*PostgresSQLStatement = null,
|
||||
query: bun.String = bun.String.empty,
|
||||
cursor_name: bun.String = bun.String.empty,
|
||||
@@ -23,9 +23,9 @@ flags: packed struct(u8) {
|
||||
pub const ref = RefCount.ref;
|
||||
pub const deref = RefCount.deref;
|
||||
|
||||
pub fn getTarget(this: *PostgresSQLQuery, globalObject: *jsc.JSGlobalObject, clean_target: bool) jsc.JSValue {
|
||||
const thisValue = this.thisValue.tryGet() orelse return .zero;
|
||||
const target = js.targetGetCached(thisValue) orelse return .zero;
|
||||
pub fn getTarget(this: *PostgresSQLQuery, globalObject: *jsc.JSGlobalObject, clean_target: bool) ?jsc.JSValue {
|
||||
const thisValue = this.thisValue.tryGet() orelse return null;
|
||||
const target = js.targetGetCached(thisValue) orelse return null;
|
||||
if (clean_target) {
|
||||
js.targetSetCached(thisValue, globalObject, .zero);
|
||||
}
|
||||
@@ -51,12 +51,7 @@ pub const Status = enum(u8) {
|
||||
}
|
||||
};
|
||||
|
||||
pub fn hasPendingActivity(this: *@This()) bool {
|
||||
return this.ref_count.get() > 1;
|
||||
}
|
||||
|
||||
pub fn deinit(this: *@This()) void {
|
||||
this.thisValue.deinit();
|
||||
if (this.statement) |statement| {
|
||||
statement.deref();
|
||||
}
|
||||
@@ -67,11 +62,7 @@ pub fn deinit(this: *@This()) void {
|
||||
|
||||
pub fn finalize(this: *@This()) void {
|
||||
debug("PostgresSQLQuery finalize", .{});
|
||||
if (this.thisValue == .weak) {
|
||||
// clean up if is a weak reference, if is a strong reference we need to wait until the query is done
|
||||
// if we are a strong reference, here is probably a bug because GC'd should not happen
|
||||
this.thisValue.weak = .zero;
|
||||
}
|
||||
this.thisValue.finalize();
|
||||
this.deref();
|
||||
}
|
||||
|
||||
@@ -84,12 +75,9 @@ pub fn onWriteFail(
|
||||
this.ref();
|
||||
defer this.deref();
|
||||
this.status = .fail;
|
||||
const thisValue = this.thisValue.get();
|
||||
defer this.thisValue.deinit();
|
||||
const targetValue = this.getTarget(globalObject, true);
|
||||
if (thisValue == .zero or targetValue == .zero) {
|
||||
return;
|
||||
}
|
||||
const thisValue = this.thisValue.tryGet() orelse return;
|
||||
defer this.thisValue.downgrade();
|
||||
const targetValue = this.getTarget(globalObject, true) orelse return;
|
||||
|
||||
const vm = jsc.VirtualMachine.get();
|
||||
const function = vm.rareData().postgresql_context.onQueryRejectFn.get().?;
|
||||
@@ -105,12 +93,9 @@ pub fn onJSError(this: *@This(), err: jsc.JSValue, globalObject: *jsc.JSGlobalOb
|
||||
this.ref();
|
||||
defer this.deref();
|
||||
this.status = .fail;
|
||||
const thisValue = this.thisValue.get();
|
||||
defer this.thisValue.deinit();
|
||||
const targetValue = this.getTarget(globalObject, true);
|
||||
if (thisValue == .zero or targetValue == .zero) {
|
||||
return;
|
||||
}
|
||||
const thisValue = this.thisValue.tryGet() orelse return;
|
||||
defer this.thisValue.downgrade();
|
||||
const targetValue = this.getTarget(globalObject, true) orelse return;
|
||||
|
||||
var vm = jsc.VirtualMachine.get();
|
||||
const function = vm.rareData().postgresql_context.onQueryRejectFn.get().?;
|
||||
@@ -145,31 +130,30 @@ fn consumePendingValue(thisValue: jsc.JSValue, globalObject: *jsc.JSGlobalObject
|
||||
pub fn onResult(this: *@This(), command_tag_str: []const u8, globalObject: *jsc.JSGlobalObject, connection: jsc.JSValue, is_last: bool) void {
|
||||
this.ref();
|
||||
defer this.deref();
|
||||
|
||||
const thisValue = this.thisValue.get();
|
||||
const targetValue = this.getTarget(globalObject, is_last);
|
||||
if (is_last) {
|
||||
this.status = .success;
|
||||
} else {
|
||||
this.status = .partial_response;
|
||||
}
|
||||
const tag = CommandTag.init(command_tag_str);
|
||||
const js_tag = tag.toJSTag(globalObject) catch |e| return this.onJSError(globalObject.takeException(e), globalObject);
|
||||
js_tag.ensureStillAlive();
|
||||
|
||||
const thisValue = this.thisValue.tryGet() orelse return;
|
||||
defer if (is_last) {
|
||||
allowGC(thisValue, globalObject);
|
||||
this.thisValue.deinit();
|
||||
this.thisValue.downgrade();
|
||||
};
|
||||
if (thisValue == .zero or targetValue == .zero) {
|
||||
return;
|
||||
}
|
||||
const targetValue = this.getTarget(globalObject, is_last) orelse return;
|
||||
|
||||
const vm = jsc.VirtualMachine.get();
|
||||
const function = vm.rareData().postgresql_context.onQueryResolveFn.get().?;
|
||||
const event_loop = vm.eventLoop();
|
||||
const tag = CommandTag.init(command_tag_str);
|
||||
|
||||
event_loop.runCallback(function, globalObject, thisValue, &.{
|
||||
targetValue,
|
||||
consumePendingValue(thisValue, globalObject) orelse .js_undefined,
|
||||
tag.toJSTag(globalObject),
|
||||
js_tag,
|
||||
tag.toJSNumber(),
|
||||
if (connection == .zero) .js_undefined else PostgresSQLConnection.js.queriesGetCached(connection) orelse .js_undefined,
|
||||
JSValue.jsBoolean(is_last),
|
||||
@@ -257,9 +241,9 @@ pub fn doDone(this: *@This(), globalObject: *jsc.JSGlobalObject, _: *jsc.CallFra
|
||||
this.flags.is_done = true;
|
||||
return .js_undefined;
|
||||
}
|
||||
pub fn setPendingValue(this: *PostgresSQLQuery, globalObject: *jsc.JSGlobalObject, callframe: *jsc.CallFrame) bun.JSError!JSValue {
|
||||
pub fn setPendingValue(_: *PostgresSQLQuery, globalObject: *jsc.JSGlobalObject, callframe: *jsc.CallFrame) bun.JSError!JSValue {
|
||||
const result = callframe.argument(0);
|
||||
const thisValue = this.thisValue.tryGet() orelse return .js_undefined;
|
||||
const thisValue = callframe.this();
|
||||
js.pendingValueSetCached(thisValue, globalObject, result);
|
||||
return .js_undefined;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,10 @@ array_length: usize = 0,
|
||||
any_failed: bool = false,
|
||||
|
||||
pub fn next(this: *ObjectIterator) ?jsc.JSValue {
|
||||
if (this.array.isEmptyOrUndefinedOrNull() or this.columns.isEmptyOrUndefinedOrNull()) {
|
||||
this.any_failed = true;
|
||||
return null;
|
||||
}
|
||||
if (this.row_i >= this.array_length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -862,11 +862,6 @@ export function isDockerEnabled(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: investigate why its not starting on Linux arm64
|
||||
if ((isLinux && process.arch === "arm64") || isMacOS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
const info = execSync(`${dockerCLI} info`, { stdio: ["ignore", "pipe", "inherit"] });
|
||||
return info.toString().indexOf("Server Version:") !== -1;
|
||||
@@ -924,7 +919,7 @@ export async function describeWithContainer(
|
||||
return;
|
||||
}
|
||||
const { arch, platform } = process;
|
||||
if ((archs && !archs?.includes(arch)) || platform === "win32" || platform === "darwin") {
|
||||
if ((archs && !archs?.includes(arch)) || platform === "win32") {
|
||||
test.skip(`docker image is not supported on ${platform}/${arch}, skipped: ${image}`, () => {});
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -616,6 +616,7 @@ if (docker) {
|
||||
expect(e.message).toBe("password error");
|
||||
}
|
||||
});
|
||||
|
||||
test("Support dynamic async password function that throws", async () => {
|
||||
await using sql = new SQL({
|
||||
...options,
|
||||
@@ -633,6 +634,7 @@ if (docker) {
|
||||
expect(e.message).toBe("password error");
|
||||
}
|
||||
});
|
||||
|
||||
test("sql file", async () => {
|
||||
await using sql = new SQL(options);
|
||||
expect((await sql.file(rel("select.sql")))[0].x).toBe(1);
|
||||
@@ -884,7 +886,7 @@ if (docker) {
|
||||
} catch (e) {
|
||||
expect(e).toBeInstanceOf(Error);
|
||||
expect(e.code).toBe("ERR_MYSQL_CONNECTION_TIMEOUT");
|
||||
expect(e.message).toMatch(/Connection timed out after 200ms/);
|
||||
expect(e.message).toMatch(/Connection timeout after 200ms/);
|
||||
} finally {
|
||||
sql.close();
|
||||
server.close();
|
||||
|
||||
@@ -2685,7 +2685,7 @@ if (isDockerEnabled()) {
|
||||
expect(e).toBeInstanceOf(SQL.SQLError);
|
||||
expect(e).toBeInstanceOf(SQL.PostgresError);
|
||||
expect(e.code).toBe("ERR_POSTGRES_CONNECTION_TIMEOUT");
|
||||
expect(e.message).toMatch(/Connection timed out after 200ms/);
|
||||
expect(e.message).toMatch(/Connection timeout after 200ms/);
|
||||
} finally {
|
||||
sql.close();
|
||||
server.close();
|
||||
|
||||
Reference in New Issue
Block a user