package main import ( // External "github.com/jmoiron/sqlx" // Standard "time" ) type ChecklistItem struct { ID int GroupID int `db:"checklist_group_id"` Order int Label string Checked bool } type ChecklistGroup struct { ID int NodeID int `db:"node_id"` Order int Label string Items []ChecklistItem } type Node struct { ID int UserID int `db:"user_id"` ParentID int `db:"parent_id"` CryptoKeyID int `db:"crypto_key_id"` Name string Content string Updated time.Time Children []Node Crumbs []Node Files []File Complete bool Level int ChecklistGroups []ChecklistGroup ContentEncrypted string `db:"content_encrypted" json:"-"` Markdown bool } func NodeTree(userID, startNodeID int) (nodes []Node, err error) { // {{{ var rows *sqlx.Rows rows, err = db.Queryx(` WITH RECURSIVE nodetree AS ( SELECT *, array[name::text] AS path, 0 AS level FROM node WHERE user_id = $1 AND CASE $2::int WHEN 0 THEN parent_id IS NULL ELSE parent_id = $2 END UNION ALL SELECT n.*, path||n.name::text AS path, nt.level + 1 AS level FROM node n INNER JOIN nodetree nt ON n.parent_id = nt.id ) SELECT id, user_id, COALESCE(parent_id, 0) AS parent_id, name, updated, level FROM nodetree ORDER BY path ASC `, userID, startNodeID, ) if err != nil { return } defer rows.Close() type resultRow struct { Node Level int } nodes = []Node{} for rows.Next() { node := Node{} node.Complete = false node.Crumbs = []Node{} node.Children = []Node{} node.Files = []File{} if err = rows.StructScan(&node); err != nil { return } nodes = append(nodes, node) } return } // }}}