fix(editor): hide commit/rollback for clean mysql/pg manual transactions
Closes #9018
This commit is contained in:
1 parent
91b8fa0aa8
commit
e9be6d0419
15 files changed
+1016
-137
No files matched your search
@@ -21,6 +21,7 @@ import {
|
||||
supportsTableVacuum,
|
||||
supportsTransaction,
|
||||
usesOracleStickyTransactionState,
|
||||
usesProvenReadOnlyStickyTransactionState,
|
||||
usesConnectionOnlyQueryTarget,
|
||||
usesTreeSchemaMode,
|
||||
schemaNodeHasLoadableName,
|
||||
@@ -215,7 +216,7 @@ describe("defaultAutoCommitForDbType", () => {
|
||||
});
|
||||
|
||||
describe("usesOracleStickyTransactionState", () => {
|
||||
it("enables sticky manual-transaction state for Oracle family", () => {
|
||||
it("marks only the Oracle family for schema-change compensation", () => {
|
||||
expect(usesOracleStickyTransactionState("oracle")).toBe(true);
|
||||
expect(usesOracleStickyTransactionState("oceanbase-oracle")).toBe(true);
|
||||
});
|
||||
@@ -228,6 +229,31 @@ describe("usesOracleStickyTransactionState", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("usesProvenReadOnlyStickyTransactionState", () => {
|
||||
it("enables the sticky toolbar for the Oracle family, MySQL and PostgreSQL", () => {
|
||||
expect(usesProvenReadOnlyStickyTransactionState("oracle")).toBe(true);
|
||||
expect(usesProvenReadOnlyStickyTransactionState("oceanbase-oracle")).toBe(true);
|
||||
expect(usesProvenReadOnlyStickyTransactionState("mysql")).toBe(true);
|
||||
expect(usesProvenReadOnlyStickyTransactionState("postgres")).toBe(true);
|
||||
});
|
||||
|
||||
it("keeps databases without manual-transaction support on the legacy toolbar", () => {
|
||||
expect(usesProvenReadOnlyStickyTransactionState("doris")).toBe(false);
|
||||
expect(usesProvenReadOnlyStickyTransactionState("kingbase")).toBe(false);
|
||||
expect(usesProvenReadOnlyStickyTransactionState("jdbc")).toBe(false);
|
||||
expect(usesProvenReadOnlyStickyTransactionState("redis")).toBe(false);
|
||||
expect(usesProvenReadOnlyStickyTransactionState(undefined)).toBe(false);
|
||||
});
|
||||
|
||||
it("only enables sticky state where manual mode is reachable", () => {
|
||||
// The sticky UX gates commit/rollback in manual mode; a member without
|
||||
// transaction support could never reach it. Guards against drift.
|
||||
for (const dbType of ["oracle", "oceanbase-oracle", "mysql", "postgres"]) {
|
||||
expect(supportsTransaction(dbType)).toBe(true);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("supportsSqlInListPaste", () => {
|
||||
it("allows generic and SQL-like editors", () => {
|
||||
expect(supportsSqlInListPaste(undefined)).toBe(true);
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { normalizeDetachedTabRuntime, type DetachedTabRuntimeState } from "@/lib/app/detachedTabHandoff";
|
||||
|
||||
describe("normalizeDetachedTabRuntime", () => {
|
||||
it("migrates a legacy-only oracleTxnPossiblyDirty key to txnPossiblyDirty", () => {
|
||||
// Detached handoffs persist to disk, so payloads written by pre-#9018
|
||||
// builds can still carry the old key; the sticky dirty bit must survive.
|
||||
const runtime: DetachedTabRuntimeState = { oracleTxnPossiblyDirty: true };
|
||||
expect(normalizeDetachedTabRuntime(runtime)).toEqual({ txnPossiblyDirty: true });
|
||||
});
|
||||
|
||||
it("prefers the renamed key when both are present", () => {
|
||||
const runtime: DetachedTabRuntimeState = { txnPossiblyDirty: false, oracleTxnPossiblyDirty: true };
|
||||
expect(normalizeDetachedTabRuntime(runtime)).toEqual({ txnPossiblyDirty: false });
|
||||
});
|
||||
|
||||
it("keeps a legacy clean bit as clean", () => {
|
||||
const runtime: DetachedTabRuntimeState = { txnSessionId: "txn-1", oracleTxnPossiblyDirty: false };
|
||||
expect(normalizeDetachedTabRuntime(runtime)).toEqual({ txnSessionId: "txn-1", txnPossiblyDirty: false });
|
||||
});
|
||||
|
||||
it("leaves runtimes without either key untouched", () => {
|
||||
expect(normalizeDetachedTabRuntime({ txnSessionId: "txn-1" })).toEqual({ txnSessionId: "txn-1" });
|
||||
});
|
||||
});
|
||||
@@ -8,10 +8,24 @@ export interface DetachedTabRuntimeState {
|
||||
editorSelection?: QueryTab["editorSelection"];
|
||||
txnSessionId?: string;
|
||||
txnAutoRolledBack?: boolean;
|
||||
txnPossiblyDirty?: boolean;
|
||||
/** Legacy key from before the #9018 rename. Handoffs persist to disk
|
||||
* (DETACHED_TABS_STATE_KEY), so payloads written by older builds may still
|
||||
* carry it; run restored runtimes through normalizeDetachedTabRuntime. */
|
||||
oracleTxnPossiblyDirty?: boolean;
|
||||
activeOutputView?: DetachedOutputView;
|
||||
}
|
||||
|
||||
/** Migrates a restored handoff runtime: prefer the renamed key, fall back to
|
||||
* the pre-#9018 key, and drop the legacy field so it never leaks onto a tab. */
|
||||
export function normalizeDetachedTabRuntime(runtime: DetachedTabRuntimeState): DetachedTabRuntimeState {
|
||||
const { oracleTxnPossiblyDirty, ...rest } = runtime;
|
||||
if (rest.txnPossiblyDirty === undefined && oracleTxnPossiblyDirty !== undefined) {
|
||||
rest.txnPossiblyDirty = oracleTxnPossiblyDirty;
|
||||
}
|
||||
return rest;
|
||||
}
|
||||
|
||||
export interface DetachedTabHandoff {
|
||||
schemaVersion: 1;
|
||||
tabId: string;
|
||||
|
||||
@@ -259,11 +259,21 @@ export function usesPostgresLikeStructureCopy(dbType?: DatabaseType): boolean {
|
||||
|
||||
const TRANSACTION_SUPPORTED_TYPES: readonly string[] = ["postgres", "mysql", "oracle", "jdbc", "oceanbase-oracle"];
|
||||
|
||||
/** Oracle-family databases that use the sticky manual-transaction UX. OceanBase
|
||||
* Oracle mode runs the same transaction model as Oracle, so it shares the
|
||||
* commit/rollback dirty-state behavior rather than the generic transaction path. */
|
||||
/** Oracle-family databases, kept ONLY for the Oracle-specific ALTER SESSION SET
|
||||
* CURRENT_SCHEMA compensation in queryStore. Do not use for toolbar/dirty-bit
|
||||
* gating — that is {@link usesProvenReadOnlyStickyTransactionState} so MySQL and
|
||||
* PostgreSQL participate without dragging Oracle schema-change compensation in. */
|
||||
const ORACLE_STICKY_TRANSACTION_TYPES: ReadonlySet<string> = new Set(["oracle", "oceanbase-oracle"]);
|
||||
|
||||
/** Databases whose manual-transaction toolbar hides Commit/Rollback until an
|
||||
* unproven statement dirties the session. Mirrors the Rust proof gate
|
||||
* (crates/dbx-core/src/query.rs + sql_risk.rs `prove_read_only_for_database`).
|
||||
* Every member must also be in TRANSACTION_SUPPORTED_TYPES above: a database
|
||||
* cannot reach manual mode (and this UX) without explicit transaction control
|
||||
* (#9018). Family members like doris/kingbase join only when their transaction
|
||||
* support lands. */
|
||||
const PROVEN_READ_ONLY_STICKY_TYPES: ReadonlySet<string> = new Set(["oracle", "oceanbase-oracle", "mysql", "postgres"]);
|
||||
|
||||
/**
|
||||
* Returns true if the given database type supports explicit transaction control
|
||||
* (i.e. toggling between auto-commit and manual transaction mode via BEGIN/COMMIT).
|
||||
@@ -317,13 +327,22 @@ export function rejectsAliasReferenceInHaving(dbType?: string): boolean {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the database type uses Oracle's sticky manual-transaction state
|
||||
* (commit/rollback hidden until an unproven statement dirties the session).
|
||||
* Returns true if the database type participates in Oracle's schema-change
|
||||
* compensation under manual transactions. Toolbar/dirty-bit gating must use
|
||||
* `usesProvenReadOnlyStickyTransactionState` instead.
|
||||
*/
|
||||
export function usesOracleStickyTransactionState(dbType?: string): boolean {
|
||||
return !!dbType && ORACLE_STICKY_TRANSACTION_TYPES.has(dbType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the database type uses the sticky manual-transaction UX:
|
||||
* commit/rollback hidden while the session is clean (no unproven statement).
|
||||
*/
|
||||
export function usesProvenReadOnlyStickyTransactionState(dbType?: string): boolean {
|
||||
return !!dbType && PROVEN_READ_ONLY_STICKY_TYPES.has(dbType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Default auto-commit mode when opening a query tab for the given database type.
|
||||
* Query tabs default to auto-commit; users can explicitly switch to manual transactions.
|
||||
|
||||
Reference in new issue
Block a user