wip
This commit is contained in:
parent
04c101982f
commit
13d0b15fd9
15 changed files with 507 additions and 1246 deletions
306
node.go
306
node.go
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue