This commit is contained in:
Magnus Åhall 2024-12-03 22:08:45 +01:00
parent 04c101982f
commit 13d0b15fd9
15 changed files with 507 additions and 1246 deletions

306
node.go
View file

@ -38,15 +38,13 @@ type TreeNode struct {
}
type Node struct {
ID int
UserID int `db:"user_id"`
ParentID int `db:"parent_id"`
CryptoKeyID int `db:"crypto_key_id"`
UUID string
UserID int `db:"user_id"`
ParentUUID string `db:"parent_uuid"`
CryptoKeyID int `db:"crypto_key_id"`
Name string
Content string
Updated time.Time
Children []Node
Crumbs []Node
Files []File
Complete bool
Level int
@ -58,7 +56,7 @@ type Node struct {
}
func NodeTree(userID, offset int, synced uint64) (nodes []TreeNode, maxSeq uint64, moreRowsExist bool, err error) { // {{{
const LIMIT = 8
const LIMIT = 100
var rows *sqlx.Rows
rows, err = db.Queryx(`
SELECT
@ -84,7 +82,7 @@ func NodeTree(userID, offset int, synced uint64) (nodes []TreeNode, maxSeq uint6
LIMIT $2 OFFSET $3
`,
userID,
LIMIT + 1,
LIMIT+1,
offset,
synced,
)
@ -122,244 +120,58 @@ func NodeTree(userID, offset int, synced uint64) (nodes []TreeNode, maxSeq uint6
return
} // }}}
func RetrieveNode(userID, nodeID int) (node Node, err error) { // {{{
if nodeID == 0 {
return RootNode(userID)
}
var rows *sqlx.Rows
rows, err = db.Queryx(`
WITH RECURSIVE recurse AS (
SELECT
id,
user_id,
COALESCE(parent_id, 0) AS parent_id,
COALESCE(crypto_key_id, 0) AS crypto_key_id,
name,
content,
content_encrypted,
markdown,
0 AS level
FROM node
WHERE
user_id = $1 AND
id = $2
UNION
SELECT
n.id,
n.user_id,
n.parent_id,
COALESCE(n.crypto_key_id, 0) AS crypto_key_id,
n.name,
'' AS content,
'' AS content_encrypted,
false AS markdown,
r.level + 1 AS level
FROM node n
INNER JOIN recurse r ON n.parent_id = r.id AND r.level = 0
WHERE
n.user_id = $1
)
SELECT * FROM recurse ORDER BY level ASC
`,
userID,
nodeID,
)
if err != nil {
return
}
defer rows.Close()
type resultRow struct {
Node
Level int
}
node = Node{}
node.Children = []Node{}
for rows.Next() {
row := resultRow{}
if err = rows.StructScan(&row); err != nil {
return
}
if row.Level == 0 {
node.ID = row.ID
node.UserID = row.UserID
node.ParentID = row.ParentID
node.CryptoKeyID = row.CryptoKeyID
node.Name = row.Name
node.Complete = true
node.Markdown = row.Markdown
if node.CryptoKeyID > 0 {
node.Content = row.ContentEncrypted
} else {
node.Content = row.Content
}
node.retrieveChecklist()
}
if row.Level == 1 {
node.Children = append(node.Children, Node{
ID: row.ID,
UserID: row.UserID,
ParentID: row.ParentID,
CryptoKeyID: row.CryptoKeyID,
Name: row.Name,
})
}
}
node.Crumbs, err = NodeCrumbs(node.ID)
node.Files, err = Files(userID, node.ID, 0)
return
} // }}}
func RootNode(userID int) (node Node, err error) { // {{{
var rows *sqlx.Rows
rows, err = db.Queryx(`
SELECT
id,
user_id,
0 AS parent_id,
name
FROM node
WHERE
user_id = $1 AND
parent_id IS NULL
`,
userID,
)
if err != nil {
return
}
defer rows.Close()
node.Name = "Start"
node.UserID = userID
node.Complete = true
node.Children = []Node{}
node.Crumbs = []Node{}
node.Files = []File{}
for rows.Next() {
row := Node{}
if err = rows.StructScan(&row); err != nil {
return
}
node.Children = append(node.Children, Node{
ID: row.ID,
UserID: row.UserID,
ParentID: row.ParentID,
Name: row.Name,
})
}
return
} // }}}
func (node *Node) retrieveChecklist() (err error) { // {{{
var rows *sqlx.Rows
rows, err = db.Queryx(`
func RetrieveNode(userID int, nodeUUID string) (node Node, err error) { // {{{
var rows *sqlx.Row
rows = db.QueryRowx(`
SELECT
g.id AS group_id,
g.order AS group_order,
g.label AS group_label,
COALESCE(i.id, 0) AS item_id,
COALESCE(i.order, 0) AS item_order,
COALESCE(i.label, '') AS item_label,
COALESCE(i.checked, false) AS checked
FROM public.checklist_group g
LEFT JOIN public.checklist_item i ON i.checklist_group_id = g.id
uuid,
user_id,
COALESCE(parent_uuid, '') AS parent_uuid,
/*COALESCE(crypto_key_id, 0) AS crypto_key_id,*/
name,
content,
content_encrypted,
markdown,
0 AS level
FROM node
WHERE
g.node_id = $1
ORDER BY
g.order DESC,
i.order DESC
`, node.ID)
if err != nil {
user_id = $1 AND
uuid = $2
`,
userID,
nodeUUID,
)
node = Node{}
if err = rows.StructScan(&node); err != nil {
return
}
defer rows.Close()
groups := make(map[int]*ChecklistGroup)
var found bool
var group *ChecklistGroup
var item ChecklistItem
for rows.Next() {
row := struct {
GroupID int `db:"group_id"`
GroupOrder int `db:"group_order"`
GroupLabel string `db:"group_label"`
ItemID int `db:"item_id"`
ItemOrder int `db:"item_order"`
ItemLabel string `db:"item_label"`
Checked bool
}{}
err = rows.StructScan(&row)
if err != nil {
return
}
if group, found = groups[row.GroupID]; !found {
group = new(ChecklistGroup)
group.ID = row.GroupID
group.NodeID = node.ID
group.Order = row.GroupOrder
group.Label = row.GroupLabel
group.Items = []ChecklistItem{}
groups[group.ID] = group
}
item = ChecklistItem{}
item.ID = row.ItemID
item.GroupID = row.GroupID
item.Order = row.ItemOrder
item.Label = row.ItemLabel
item.Checked = row.Checked
if item.ID > 0 {
group.Items = append(group.Items, item)
}
}
node.ChecklistGroups = []ChecklistGroup{}
for _, group := range groups {
node.ChecklistGroups = append(node.ChecklistGroups, *group)
}
return
} // }}}
func NodeCrumbs(nodeID int) (nodes []Node, err error) { // {{{
func NodeCrumbs(nodeUUID string) (nodes []Node, err error) { // {{{
var rows *sqlx.Rows
rows, err = db.Queryx(`
WITH RECURSIVE nodes AS (
SELECT
id,
COALESCE(parent_id, 0) AS parent_id,
uuid,
COALESCE(parent_uuid, '') AS parent_uuid,
name
FROM node
WHERE
id = $1
uuid = $1
UNION
SELECT
n.id,
COALESCE(n.parent_id, 0) AS parent_id,
n.uuid,
COALESCE(n.parent_uuid, 0) AS parent_uuid,
n.name
FROM node n
INNER JOIN nodes nr ON n.id = nr.parent_id
INNER JOIN nodes nr ON n.uuid = nr.parent_uuid
)
SELECT * FROM nodes
`, nodeID)
`, nodeUUID)
if err != nil {
return
}
@ -375,3 +187,49 @@ func NodeCrumbs(nodeID int) (nodes []Node, err error) { // {{{
}
return
} // }}}
func TestData() (err error) {
for range 10 {
hash1, name1, _ := generateOneTestNode("", "G")
for range 10 {
hash2, name2, _ := generateOneTestNode(hash1, name1)
for range 10 {
hash3, name3, _ := generateOneTestNode(hash2, name2)
for range 10 {
generateOneTestNode(hash3, name3)
}
}
}
}
return
}
func generateOneTestNode(parentUUID, parentPath string) (hash, name string, err error) {
var sqlParentUUID sql.NullString
if parentUUID != "" {
sqlParentUUID.String = parentUUID
sqlParentUUID.Valid = true
}
query := `
INSERT INTO node(user_id, parent_uuid, name)
VALUES(
1,
$1,
CONCAT(
$2::text,
'-',
LPAD(nextval('test_data')::text, 4, '0')
)
)
RETURNING uuid, name`
var row *sql.Row
row = db.QueryRow(query, sqlParentUUID, parentPath)
err = row.Scan(&hash, &name)
if err != nil {
return
}
return
}