feat(oracle): support safe trigger structure editing
This commit is contained in:
1 parent
0a5fbb6f8c
commit
fdaef62518
5 files changed
+44
-16
No files matched your search
@@ -41,6 +41,7 @@ import type { TableInfoTab, TableStructureEditorDraft, TableStructureEditorTarge
|
|||||||
import {
|
import {
|
||||||
applyManticoreDdlColumnExtras,
|
applyManticoreDdlColumnExtras,
|
||||||
buildStructureTargetLabel,
|
buildStructureTargetLabel,
|
||||||
|
canEditStructuredTriggerDraft,
|
||||||
canEditManticoreColumnProperties,
|
canEditManticoreColumnProperties,
|
||||||
combineDataTypeForDatabase,
|
combineDataTypeForDatabase,
|
||||||
combineDataTypeForDatabaseWithLengthUnit,
|
combineDataTypeForDatabaseWithLengthUnit,
|
||||||
@@ -2158,7 +2159,7 @@ function toggleDropTrigger(trigger: EditableStructureTrigger) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function canEditTriggerDraft(trigger: EditableStructureTrigger): boolean {
|
function canEditTriggerDraft(trigger: EditableStructureTrigger): boolean {
|
||||||
return !triggersLoading.value && canEditTriggers.value && !trigger.markedForDrop;
|
return !triggersLoading.value && canEditTriggers.value && !trigger.markedForDrop && canEditStructuredTriggerDraft(databaseType.value, trigger);
|
||||||
}
|
}
|
||||||
|
|
||||||
function primarySqlOperation(sql: string): string {
|
function primarySqlOperation(sql: string): string {
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
import {
|
import {
|
||||||
|
canEditStructuredTriggerDraft,
|
||||||
combineDataTypeForDatabase,
|
combineDataTypeForDatabase,
|
||||||
combineDataTypeForDatabaseWithLengthUnit,
|
combineDataTypeForDatabaseWithLengthUnit,
|
||||||
createColumnDrafts,
|
createColumnDrafts,
|
||||||
|
createTriggerDrafts,
|
||||||
dataTypeLengthInputValue,
|
dataTypeLengthInputValue,
|
||||||
dataTypeLengthUnitValue,
|
dataTypeLengthUnitValue,
|
||||||
DATA_TYPE_OPTIONS,
|
DATA_TYPE_OPTIONS,
|
||||||
@@ -24,6 +26,25 @@ import {
|
|||||||
} from "@/lib/table/tableStructureEditorState";
|
} from "@/lib/table/tableStructureEditorState";
|
||||||
|
|
||||||
describe("tableStructureEditorState", () => {
|
describe("tableStructureEditorState", () => {
|
||||||
|
it("keeps existing Oracle trigger drafts read-only until full source editing is available", () => {
|
||||||
|
const [existing] = createTriggerDrafts([{ name: "ORDERS_AUDIT", timing: "AFTER EACH ROW", event: "INSERT OR UPDATE", statement: "BEGIN NULL; END;" }]);
|
||||||
|
if (!existing) throw new Error("expected an existing trigger draft");
|
||||||
|
|
||||||
|
expect(canEditStructuredTriggerDraft("oracle", existing)).toBe(false);
|
||||||
|
expect(canEditStructuredTriggerDraft(undefined, existing)).toBe(false);
|
||||||
|
expect(canEditStructuredTriggerDraft("mysql", existing)).toBe(true);
|
||||||
|
expect(
|
||||||
|
canEditStructuredTriggerDraft("oracle", {
|
||||||
|
id: "new:trigger",
|
||||||
|
name: "ORDERS_AUDIT",
|
||||||
|
timing: "AFTER EACH ROW",
|
||||||
|
event: "INSERT",
|
||||||
|
statement: "BEGIN NULL; END;",
|
||||||
|
markedForDrop: false,
|
||||||
|
}),
|
||||||
|
).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
it("hydrates Kingbase type parameters returned separately from the data type", () => {
|
it("hydrates Kingbase type parameters returned separately from the data type", () => {
|
||||||
const columns = createColumnDrafts(
|
const columns = createColumnDrafts(
|
||||||
[
|
[
|
||||||
|
|||||||
@@ -816,6 +816,10 @@ export function createTriggerDrafts(triggers: TriggerInfo[]): EditableStructureT
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function canEditStructuredTriggerDraft(databaseType: DatabaseType | undefined, trigger: EditableStructureTrigger): boolean {
|
||||||
|
return !trigger.original || (databaseType !== undefined && databaseType !== "oracle");
|
||||||
|
}
|
||||||
|
|
||||||
export function toColumnNames(columns: string[]): string {
|
export function toColumnNames(columns: string[]): string {
|
||||||
return columns.join(", ");
|
return columns.join(", ");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3324,7 +3324,7 @@ fn builds_mysql_trigger_changes() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn builds_oracle_multi_event_row_trigger_change() {
|
fn rejects_editing_existing_oracle_trigger_without_complete_source() {
|
||||||
let mut existing = trigger(
|
let mut existing = trigger(
|
||||||
"DBX_TRIGGER_4320_AUDIT",
|
"DBX_TRIGGER_4320_AUDIT",
|
||||||
"AFTER EACH ROW",
|
"AFTER EACH ROW",
|
||||||
@@ -3350,12 +3350,10 @@ fn builds_oracle_multi_event_row_trigger_change() {
|
|||||||
original_table_comment: None,
|
original_table_comment: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
assert_eq!(result.warnings, Vec::<String>::new());
|
assert!(result.statements.is_empty());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.statements,
|
result.warnings,
|
||||||
vec![
|
vec!["Editing existing Oracle trigger \"DBX_TRIGGER_4320_AUDIT\" requires its complete source definition."]
|
||||||
"CREATE OR REPLACE TRIGGER \"APP\".\"DBX_TRIGGER_4320_AUDIT\" AFTER INSERT OR UPDATE OR DELETE ON \"APP\".\"DBX_TRIGGER_4320\"\nFOR EACH ROW\nDECLARE\n v_event VARCHAR2(10);\nBEGIN\n v_event := CASE WHEN INSERTING THEN 'INSERT' WHEN UPDATING THEN 'UPDATE' ELSE 'DELETE' END;\nEND;",
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3383,14 +3381,15 @@ fn builds_oracle_statement_trigger_without_row_clause() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn renaming_oracle_trigger_drops_old_name_before_create() {
|
fn drops_existing_oracle_trigger_without_reconstructing_it() {
|
||||||
let mut existing = trigger("ORDERS_AUDIT_V2", "AFTER EACH ROW", "INSERT", "BEGIN\n NULL;\nEND;");
|
let mut existing = trigger("ORDERS_AUDIT", "AFTER EACH ROW", "INSERT", "BEGIN\n NULL;\nEND;");
|
||||||
existing.original = Some(TriggerInfo {
|
existing.original = Some(TriggerInfo {
|
||||||
name: "ORDERS_AUDIT".to_string(),
|
name: "ORDERS_AUDIT".to_string(),
|
||||||
event: "INSERT".to_string(),
|
event: "INSERT".to_string(),
|
||||||
timing: "AFTER EACH ROW".to_string(),
|
timing: "AFTER EACH ROW".to_string(),
|
||||||
statement: Some("BEGIN\n NULL;\nEND;".to_string()),
|
statement: Some("BEGIN\n NULL;\nEND;".to_string()),
|
||||||
});
|
});
|
||||||
|
existing.marked_for_drop = true;
|
||||||
|
|
||||||
let result = build_table_structure_change_sql(TableStructureSqlOptions {
|
let result = build_table_structure_change_sql(TableStructureSqlOptions {
|
||||||
database_type: Some(DatabaseType::Oracle),
|
database_type: Some(DatabaseType::Oracle),
|
||||||
@@ -3405,13 +3404,7 @@ fn renaming_oracle_trigger_drops_old_name_before_create() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
assert_eq!(result.warnings, Vec::<String>::new());
|
assert_eq!(result.warnings, Vec::<String>::new());
|
||||||
assert_eq!(
|
assert_eq!(result.statements, vec!["DROP TRIGGER \"APP\".\"ORDERS_AUDIT\";"]);
|
||||||
result.statements,
|
|
||||||
vec![
|
|
||||||
"DROP TRIGGER \"APP\".\"ORDERS_AUDIT\";",
|
|
||||||
"CREATE OR REPLACE TRIGGER \"APP\".\"ORDERS_AUDIT_V2\" AFTER INSERT ON \"APP\".\"ORDERS\"\nFOR EACH ROW\nBEGIN\n NULL;\nEND;",
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -26,6 +26,15 @@ pub(super) fn build_trigger_sql(options: &TableStructureSqlOptions, warnings: &m
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(original) = &trigger.original {
|
if let Some(original) = &trigger.original {
|
||||||
|
if dialect == StructureDialect::Oracle {
|
||||||
|
if has_trigger_change(trigger, original) {
|
||||||
|
warnings.push(format!(
|
||||||
|
"Editing existing Oracle trigger \"{}\" requires its complete source definition.",
|
||||||
|
original.name
|
||||||
|
));
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if !has_trigger_change(trigger, original) {
|
if !has_trigger_change(trigger, original) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user