This commit is contained in:
Magnus Åhall 2025-07-05 07:50:59 +02:00
parent a6bb845c9d
commit cfd5bfd719
9 changed files with 213 additions and 111 deletions

79
node.go
View file

@ -4,9 +4,11 @@ import (
// External
werr "git.gibonuddevalla.se/go/wrappederror"
"github.com/jmoiron/sqlx"
"github.com/lib/pq"
// Standard
"encoding/json"
"errors"
"time"
)
@ -30,10 +32,11 @@ type Node struct {
Children []*Node
}
func GetNode(nodeID int) (node Node, err error) {
func GetNode(nodeID int) (node Node, err error) { // {{{
row := db.QueryRowx(`
SELECT
n.id,
COALESCE(n.parent_id, -1) AS parent_id,
n.name,
n.updated,
n.data AS data_raw,
@ -66,9 +69,9 @@ func GetNode(nodeID int) (node Node, err error) {
return
}
return
}
} // }}}
func GetNodeTree(startNodeID, maxDepth int) (topNode *Node, err error) {// {{{
func GetNodeTree(startNodeID, maxDepth int) (topNode *Node, err error) { // {{{
nodes := make(map[int]*Node)
var rows *sqlx.Rows
rows, err = GetNodeRows(startNodeID, maxDepth)
@ -96,47 +99,42 @@ func GetNodeTree(startNodeID, maxDepth int) (topNode *Node, err error) {// {{{
}
return
}// }}}
func GetNodeRows(startNodeID, maxDepth int) (rows *sqlx.Rows, err error) {// {{{
} // }}}
func GetNodeRows(startNodeID, maxDepth int) (rows *sqlx.Rows, err error) { // {{{
rows, err = db.Queryx(`
WITH RECURSIVE nodes AS (
SELECT
COALESCE(
(SELECT parent FROM connection WHERE child = $1),
0
) AS parent_id,
$1::int AS id,
0 AS depth
UNION
SELECT
c.parent,
c.child,
n.id,
ns.depth+1 AS depth
FROM connection c
INNER JOIN nodes ns ON ns.depth < $2 AND c.parent = ns.id
FROM node n
INNER JOIN nodes ns ON ns.depth < $2 AND n.parent_id = ns.id
)
SEARCH DEPTH FIRST BY id SET ordercol
SELECT
ns.parent_id,
COALESCE(n.parent_id, -1) AS parent_id,
n.id,
n.name,
CONCAT(REPEAT(' ', ns.depth), n.name) AS name,
n.type_id,
t.name AS type_name,
COALESCE(t.schema->>'icon', '') AS type_icon,
n.updated,
n.data AS data_raw,
COUNT(c.child) AS num_children
COUNT(node_children.id) AS num_children
FROM nodes ns
INNER JOIN public.node n ON ns.id = n.id
INNER JOIN public.type t ON n.type_id = t.id
LEFT JOIN public.connection c ON c.parent = n.id
LEFT JOIN node node_children ON node_children.parent_id = n.id
GROUP BY
ns.depth,
ns.parent_id,
n.parent_id,
n.id,
t.name,
t.schema,
@ -152,8 +150,8 @@ func GetNodeRows(startNodeID, maxDepth int) (rows *sqlx.Rows, err error) {// {{{
}
return
}// }}}
func ComposeTree(nodes map[int]*Node, node *Node) {// {{{
} // }}}
func ComposeTree(nodes map[int]*Node, node *Node) { // {{{
if node.Children == nil {
node.Children = []*Node{}
}
@ -168,18 +166,17 @@ func ComposeTree(nodes map[int]*Node, node *Node) {// {{{
}
nodes[node.ID] = node
}// }}}
} // }}}
func UpdateNode(nodeID int, data []byte) (err error) {// {{{
func UpdateNode(nodeID int, data []byte) (err error) { // {{{
_, err = db.Exec(`UPDATE public.node SET data=$2 WHERE id=$1`, nodeID, data)
return
}// }}}
func RenameNode(nodeID int, name string) (err error) {// {{{
} // }}}
func RenameNode(nodeID int, name string) (err error) { // {{{
_, err = db.Exec(`UPDATE node SET name=$2 WHERE id=$1`, nodeID, name)
return
}// }}}
func CreateNode(parentNodeID, typeID int, name string) (err error) {// {{{
} // }}}
func CreateNode(parentNodeID, typeID int, name string) (nodeID int, err error) { // {{{
j, _ := json.Marshal(
struct {
New bool `json:"x-new"`
@ -188,22 +185,28 @@ func CreateNode(parentNodeID, typeID int, name string) (err error) {// {{{
})
row := db.QueryRow(`
INSERT INTO node(type_id, name, data)
VALUES($1, $2, $3::jsonb)
INSERT INTO node(parent_id, type_id, name, data)
VALUES($1, $2, $3, $4::jsonb)
RETURNING id
`,
typeID, name, j)
var id int
err = row.Scan(&id)
parentNodeID, typeID, name, j)
err = row.Scan(&nodeID)
if err != nil {
err = werr.Wrap(err)
return
}
_, err = db.Exec(`INSERT INTO connection("parent", "child") VALUES($1, $2)`, parentNodeID, id)
return
}// }}}
} // }}}
func DeleteNode(nodeID int) (err error) { // {{{
_, err = db.Exec(`DELETE FROM node WHERE id=$1`, nodeID)
if err != nil {
pqErr, ok := err.(*pq.Error)
if ok && pqErr.Code == "23503" {
err = errors.New("Can't delete a node with children.")
return
}
}
return
} // }}}
// vim: foldmethod=marker