Allow unlimited nesting of item classes
This commit is contained in:
parent
cdc73d1ac5
commit
ae4e583c2d
|
@ -0,0 +1,28 @@
|
|||
-- SPDX-FileCopyrightText: 2024 Simon Bruder <simon@sbruder.de>
|
||||
--
|
||||
-- SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
DROP VIEW item_class_tree;
|
||||
|
||||
DROP TRIGGER prevent_item_class_cycle ON item_classes;
|
||||
DROP FUNCTION check_item_class_cycle;
|
||||
|
||||
CREATE FUNCTION check_item_class_recursion_depth()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
IF NEW.parent IS NULL THEN
|
||||
RETURN NEW;
|
||||
END IF;
|
||||
|
||||
IF (SELECT parent FROM item_classes WHERE id = NEW.parent) IS NULL THEN
|
||||
RETURN NEW;
|
||||
END IF;
|
||||
|
||||
RAISE EXCEPTION 'Item classes may only be nested one level deep';
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE TRIGGER prevent_item_class_recursion
|
||||
BEFORE INSERT OR UPDATE ON item_classes
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION check_item_class_recursion_depth();
|
50
migrations/20240806120210_item_class_unlimited_depth.up.sql
Normal file
50
migrations/20240806120210_item_class_unlimited_depth.up.sql
Normal file
|
@ -0,0 +1,50 @@
|
|||
-- SPDX-FileCopyrightText: 2024 Simon Bruder <simon@sbruder.de>
|
||||
--
|
||||
-- SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
DROP TRIGGER prevent_item_class_recursion ON item_classes;
|
||||
DROP FUNCTION check_item_class_recursion_depth;
|
||||
|
||||
CREATE FUNCTION check_item_class_cycle()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
IF NEW.parent IS NULL THEN
|
||||
RETURN NEW;
|
||||
END IF;
|
||||
|
||||
IF NEW.id = NEW.parent THEN
|
||||
RAISE EXCEPTION 'Cycle detected';
|
||||
END IF;
|
||||
|
||||
IF (WITH RECURSIVE cte AS (
|
||||
SELECT id, parent
|
||||
FROM item_classes
|
||||
WHERE id = NEW.parent
|
||||
|
||||
UNION ALL
|
||||
|
||||
SELECT item_classes.id, item_classes.parent
|
||||
FROM item_classes, cte
|
||||
WHERE item_classes.id = cte.parent
|
||||
)
|
||||
SELECT 1
|
||||
FROM cte
|
||||
WHERE parent = NEW.id
|
||||
LIMIT 1) THEN
|
||||
RAISE EXCEPTION 'Cycle detected';
|
||||
END IF;
|
||||
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE TRIGGER prevent_item_class_cycle
|
||||
BEFORE INSERT OR UPDATE ON item_classes
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION check_item_class_cycle();
|
||||
|
||||
CREATE RECURSIVE VIEW item_class_tree (id, parents) AS (
|
||||
SELECT id, ARRAY[]::UUID[] AS parents FROM item_classes WHERE parent IS NULL
|
||||
UNION ALL
|
||||
SELECT item_classes.id, item_class_tree.parents || item_classes.parent FROM item_classes, item_class_tree WHERE item_classes.parent = item_class_tree.id
|
||||
);
|
|
@ -44,49 +44,45 @@ async fn get(
|
|||
let mut title = item_class.name.clone();
|
||||
title.push_str(" – Item Details");
|
||||
|
||||
let mut page_actions = vec![
|
||||
(PageActionGroup::Button {
|
||||
action: PageAction {
|
||||
method: PageActionMethod::Get,
|
||||
target: format!("/items/add?class={}", item_class.id),
|
||||
name: "Add Item".to_string(),
|
||||
},
|
||||
colour: Colour::Success,
|
||||
}),
|
||||
];
|
||||
if item_class.parent.is_none() {
|
||||
page_actions.push(PageActionGroup::Button {
|
||||
action: PageAction {
|
||||
method: PageActionMethod::Get,
|
||||
target: format!("/item-classes/add?parent={}", item_class.id),
|
||||
name: "Add Child".to_string(),
|
||||
},
|
||||
colour: Colour::Primary,
|
||||
});
|
||||
}
|
||||
page_actions.push(PageActionGroup::Button {
|
||||
action: PageAction {
|
||||
method: PageActionMethod::Get,
|
||||
target: format!("/item-class/{}/edit", item_class.id),
|
||||
name: "Edit".to_string(),
|
||||
},
|
||||
colour: Colour::Warning,
|
||||
});
|
||||
page_actions.push(PageActionGroup::Button {
|
||||
action: PageAction {
|
||||
method: PageActionMethod::Post,
|
||||
target: format!("/item-class/{}/delete", item_class.id),
|
||||
name: "Delete".to_string(),
|
||||
},
|
||||
colour: Colour::Danger,
|
||||
});
|
||||
|
||||
Ok(templates::base(
|
||||
TemplateConfig {
|
||||
path: &format!("/item-class/{}", item_class.id),
|
||||
title: Some(&title),
|
||||
page_title: Some(Box::new(item_class.name.clone())),
|
||||
page_actions,
|
||||
page_actions: vec![
|
||||
PageActionGroup::Button {
|
||||
action: PageAction {
|
||||
method: PageActionMethod::Get,
|
||||
target: format!("/items/add?class={}", item_class.id),
|
||||
name: "Add Item".to_string(),
|
||||
},
|
||||
colour: Colour::Success,
|
||||
},
|
||||
PageActionGroup::Button {
|
||||
action: PageAction {
|
||||
method: PageActionMethod::Get,
|
||||
target: format!("/item-classes/add?parent={}", item_class.id),
|
||||
name: "Add Child".to_string(),
|
||||
},
|
||||
colour: Colour::Primary,
|
||||
},
|
||||
PageActionGroup::Button {
|
||||
action: PageAction {
|
||||
method: PageActionMethod::Get,
|
||||
target: format!("/item-class/{}/edit", item_class.id),
|
||||
name: "Edit".to_string(),
|
||||
},
|
||||
colour: Colour::Warning,
|
||||
},
|
||||
PageActionGroup::Button {
|
||||
action: PageAction {
|
||||
method: PageActionMethod::Post,
|
||||
target: format!("/item-class/{}/delete", item_class.id),
|
||||
name: "Delete".to_string(),
|
||||
},
|
||||
colour: Colour::Danger,
|
||||
},
|
||||
],
|
||||
user: Some(user),
|
||||
..Default::default()
|
||||
},
|
||||
|
|
Loading…
Reference in a new issue