mirror of
https://codeberg.org/shroff/phylum.git
synced 2026-01-06 03:31:02 -06:00
[server] Fix new queries
This commit is contained in:
@@ -13,11 +13,9 @@ type DiskUsageInfo struct {
|
||||
|
||||
func (f filesystem) DiskUsage(r Resource) (DiskUsageInfo, error) {
|
||||
// TODO: #versions This is broken
|
||||
_, n, q := selectResourceTree(r.id, false, false, false, "content_length", "dir")
|
||||
n, q := selectResourceTree(r.id, false, "content_length", "dir")
|
||||
|
||||
q = q.
|
||||
From(n).
|
||||
ClearWhere().
|
||||
Select(
|
||||
goqu.SUM(n.Col("content_length")),
|
||||
goqu.COUNT("*"),
|
||||
@@ -28,6 +26,7 @@ func (f filesystem) DiskUsage(r Resource) (DiskUsageInfo, error) {
|
||||
row := f.db.QueryRow(query, args...)
|
||||
var size, count, dirs int64
|
||||
err := row.Scan(&size, &count, &dirs)
|
||||
|
||||
return DiskUsageInfo{
|
||||
TotalSize: size,
|
||||
Entities: count,
|
||||
|
||||
@@ -46,11 +46,13 @@ func (f filesystem) Delete(r Resource) (Resource, error) {
|
||||
|
||||
func softDelete(d db.Handler, id uuid.UUID) error {
|
||||
return d.RunInTx(func(db db.Handler) error {
|
||||
// Select all descendants, not including deleted ones
|
||||
_, _, q := selectResourceTree(id, false, false, false)
|
||||
n, q := selectResourceTree(id, false)
|
||||
r := goqu.T("resources")
|
||||
|
||||
// Set modified and deleted
|
||||
query, params, _ := q.
|
||||
From(r).
|
||||
Where(r.Col("id").Eq(pg.From(n).Select("id"))).
|
||||
Update().
|
||||
Set(
|
||||
goqu.Record{
|
||||
@@ -66,18 +68,21 @@ func softDelete(d db.Handler, id uuid.UUID) error {
|
||||
// Add to trash
|
||||
query, params, _ = pg.Insert(goqu.T("trash")).Cols("id").Vals(goqu.Vals{id}).ToSQL()
|
||||
_, err := db.Exec(query, params...)
|
||||
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
func (f filesystem) softDeleteChildren(id, parent uuid.UUID) error {
|
||||
err := f.runInTx(func(f filesystem) error {
|
||||
// Select non-deleted descendents excluding the tree root (id)
|
||||
_, _, s := selectResourceTree(id, true, false, false)
|
||||
n, s := selectResourceTree(id, false)
|
||||
r := goqu.T("resources")
|
||||
|
||||
// Mark deleted
|
||||
q, params, _ := s.Update().
|
||||
q, params, _ := s.
|
||||
From(r).
|
||||
Where(r.Col("id").Eq(pg.From(n).Select("id"))).
|
||||
Where(r.Col("id").Neq(id)).
|
||||
Update().
|
||||
Set(
|
||||
goqu.Record{
|
||||
"modified": goqu.L("NOW()"),
|
||||
@@ -120,12 +125,12 @@ func (f filesystem) DeleteForever(r Resource) error {
|
||||
}
|
||||
return f.runInTx(func(f filesystem) error {
|
||||
// Select all descendants, including deleted resources
|
||||
r, _, q := selectResourceTree(r.id, false, true, false)
|
||||
n, q := selectResourceTree(r.id, true)
|
||||
|
||||
if err := f.updateResourceModified(parent.id); err != nil {
|
||||
return err
|
||||
// deleteAllVersions needs to be called last, as it will enqueue the delete jobs
|
||||
} else if err := hardDeleteAllVersions(f.db, q, r); err != nil {
|
||||
} else if err := hardDeleteAllVersions(f.db, q, n); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
@@ -198,6 +203,7 @@ func (f filesystem) RestoreDeleted(r Resource, parentPathOrUUID string, name str
|
||||
return
|
||||
}
|
||||
|
||||
id := r.id
|
||||
err = f.runInTx(func(f filesystem) error {
|
||||
q, args, _ := pg.Delete(goqu.T("trash")).Where(goqu.C("id").Eq(r.id)).ToSQL()
|
||||
if _, err := f.db.Exec(q, args...); err != nil {
|
||||
@@ -205,7 +211,7 @@ func (f filesystem) RestoreDeleted(r Resource, parentPathOrUUID string, name str
|
||||
}
|
||||
|
||||
if parent.id != r.parentID.Bytes || r.name != name {
|
||||
if err := f.updateResourceNameParent(r.ID(), name, pgtype.UUID{Bytes: parent.id, Valid: true}); err != nil {
|
||||
if err := f.updateResourceNameParent(id, name, pgtype.UUID{Bytes: parent.id, Valid: true}); err != nil {
|
||||
return err
|
||||
} else {
|
||||
r.name = name
|
||||
@@ -213,8 +219,12 @@ func (f filesystem) RestoreDeleted(r Resource, parentPathOrUUID string, name str
|
||||
r.visibleParent = r.parentID
|
||||
}
|
||||
}
|
||||
_, _, s := selectResourceTree(r.id, false, false, false)
|
||||
query, params, _ := s.Update().Set(
|
||||
n, s := selectResourceTree(id, false)
|
||||
r := goqu.T("resources")
|
||||
query, params, _ := s.
|
||||
From(r).
|
||||
Where(r.Col("id").Eq(pg.From(n).Select("id"))).
|
||||
Update().Set(
|
||||
goqu.Record{
|
||||
"modified": goqu.L("NOW()"),
|
||||
"deleted": nil,
|
||||
@@ -224,7 +234,7 @@ func (f filesystem) RestoreDeleted(r Resource, parentPathOrUUID string, name str
|
||||
return err
|
||||
}
|
||||
|
||||
return f.recomputePermissions(r.id)
|
||||
return f.recomputePermissions(id)
|
||||
})
|
||||
r.deleted = pgtype.Timestamp{}
|
||||
res = r
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"codeberg.org/shroff/phylum/server/internal/jobs"
|
||||
"codeberg.org/shroff/phylum/server/internal/storage"
|
||||
"github.com/doug-martin/goqu/v9"
|
||||
"github.com/doug-martin/goqu/v9/exp"
|
||||
"github.com/google/uuid"
|
||||
"github.com/jackc/pgx/v5"
|
||||
)
|
||||
@@ -63,7 +64,11 @@ func (f filesystem) ReadDirDeleted(r Resource, recursive, includeDeleted bool) (
|
||||
if !recursive {
|
||||
_, q = selectDirectChildren(r.id, r.deleted, includeDeleted)
|
||||
} else {
|
||||
_, _, q = selectResourceTree(r.id, true, includeDeleted, true)
|
||||
n, qq := selectResourceTree(r.id, includeDeleted)
|
||||
id := r.id
|
||||
var r exp.AliasedExpression
|
||||
q, r = selectResources(qq, n)
|
||||
q = q.Where(r.Col("id").Neq(id))
|
||||
}
|
||||
|
||||
query, args, _ := q.ToSQL()
|
||||
|
||||
@@ -35,12 +35,11 @@ COALESCE(p.permissions, '{}'::JSONB) AS inherited_permissions
|
||||
FROM resources r LEFT JOIN resources p ON p.id = r.parent
|
||||
`
|
||||
|
||||
func selectResourceTree(id uuid.UUID, excludeTreeRoot, includeDeleted, includeSubQueries bool, extraCols ...string) (exp.IdentifierExpression, exp.AliasedExpression, *goqu.SelectDataset) {
|
||||
t := goqu.T("resources")
|
||||
r := t.As("r")
|
||||
func selectResourceTree(id uuid.UUID, includeDeleted bool, extraCols ...string) (exp.AliasedExpression, *goqu.SelectDataset) {
|
||||
r := goqu.T("resources").As("r")
|
||||
n := goqu.T("nodes").As("n")
|
||||
rec := pg.From(r).
|
||||
Select(r.Col("id"), r.Col("parent"), r.Col("deleted"), goqu.L("? + 1", goqu.I("n.depth")))
|
||||
Select(r.Col("id"), r.Col("parent"), r.Col("deleted"))
|
||||
if len(extraCols) != 0 {
|
||||
s := make([]interface{}, len(extraCols))
|
||||
for i, c := range extraCols {
|
||||
@@ -56,7 +55,7 @@ func selectResourceTree(id uuid.UUID, excludeTreeRoot, includeDeleted, includeSu
|
||||
|
||||
base := pg.
|
||||
From(r).
|
||||
Select(r.Col("id"), r.Col("parent"), r.Col("deleted"), goqu.L("0")).
|
||||
Select(r.Col("id"), r.Col("parent"), r.Col("deleted")).
|
||||
Where(r.Col("id").Eq(id))
|
||||
|
||||
if len(extraCols) != 0 {
|
||||
@@ -67,27 +66,27 @@ func selectResourceTree(id uuid.UUID, excludeTreeRoot, includeDeleted, includeSu
|
||||
base = base.SelectAppend(s...)
|
||||
}
|
||||
|
||||
cols := []string{"id", "parent", "deleted", "depth"}
|
||||
cols = slices.Insert(cols, 4, extraCols...)
|
||||
idSelect := pg.From(n).Select(n.Col("id"))
|
||||
if excludeTreeRoot {
|
||||
idSelect = idSelect.Where(n.Col("depth").Gt(0))
|
||||
}
|
||||
cols := []string{"id", "parent", "deleted"}
|
||||
cols = slices.Insert(cols, 3, extraCols...)
|
||||
|
||||
q := pg.
|
||||
From(t)
|
||||
if includeSubQueries {
|
||||
v := goqu.T("resource_versions").As("v")
|
||||
l := goqu.T("publinks").As("l")
|
||||
q = q.Select(
|
||||
t.All(),
|
||||
pg.Select(goqu.L(versionsQuery)).From(v).Where(v.Col("resource_id").Eq(t.Col("id"))),
|
||||
pg.Select(goqu.L(publinksQuery)).From(l).Where(l.Col("root").Eq(t.Col("id"))),
|
||||
From(n).
|
||||
WithRecursive("nodes("+strings.Join(cols, ",")+")", base.UnionAll(rec))
|
||||
return n, q
|
||||
}
|
||||
|
||||
func selectResources(q *goqu.SelectDataset, n exp.AliasedExpression) (*goqu.SelectDataset, exp.AliasedExpression) {
|
||||
r := goqu.T("resources").As("r")
|
||||
v := goqu.T("resource_versions").As("v")
|
||||
l := goqu.T("publinks").As("l")
|
||||
q = q.From(r).
|
||||
Join(n, goqu.On(r.Col("id").Eq(n.Col("id")))).
|
||||
Select(
|
||||
r.All(),
|
||||
pg.Select(goqu.L(versionsQuery)).From(v).Where(v.Col("resource_id").Eq(r.Col("id"))),
|
||||
pg.Select(goqu.L(publinksQuery)).From(l).Where(l.Col("root").Eq(r.Col("id"))),
|
||||
)
|
||||
}
|
||||
q = q.WithRecursive("nodes("+strings.Join(cols, ",")+")", base.UnionAll(rec)).
|
||||
Where(t.Col("id").Eq(idSelect))
|
||||
return t, n, q
|
||||
return q, r
|
||||
}
|
||||
|
||||
func selectDirectChildren(id uuid.UUID, deleted pgtype.Timestamp, includeDeleted bool) (exp.AliasedExpression, *goqu.SelectDataset) {
|
||||
|
||||
@@ -93,7 +93,7 @@ func TrashCompact(ctx context.Context, duration time.Duration) {
|
||||
func (f filesystem) TrashSummary() (int, int, error) {
|
||||
v := goqu.T("resource_versions").As("v")
|
||||
|
||||
n, q := f.selectTrash()
|
||||
n, q := f.selectTrash(time.Time{})
|
||||
q = q.LeftJoin(v, goqu.On(v.Col("resource_id").Eq(n.Col("id")))).
|
||||
Select(
|
||||
goqu.COALESCE(goqu.SUM(v.Col("size")), 0),
|
||||
@@ -108,20 +108,32 @@ func (f filesystem) TrashSummary() (int, int, error) {
|
||||
}
|
||||
|
||||
func (f filesystem) TrashEmpty() error {
|
||||
n, q := f.selectTrash()
|
||||
n, q := f.selectTrash(time.Time{})
|
||||
return hardDeleteAllVersions(f.db, q, n)
|
||||
}
|
||||
|
||||
func (f filesystem) selectTrash() (exp.AliasedExpression, *goqu.SelectDataset) {
|
||||
func (f filesystem) selectTrash(time time.Time) (exp.AliasedExpression, *goqu.SelectDataset) {
|
||||
r := goqu.T("resources").As("r")
|
||||
n := goqu.T("nodes").As("n")
|
||||
t := goqu.T("trash").As("t")
|
||||
|
||||
base := goqu.From(r).Select(r.Col("id"), r.Col("parent"), r.Col("deleted")).Join(t, goqu.On(t.Col("id").Eq(r.Col("id"))))
|
||||
base := pg.
|
||||
From(r).
|
||||
Select(r.Col("id"), r.Col("parent"), r.Col("deleted")).
|
||||
Join(t, goqu.On(t.Col("id").Eq(r.Col("id"))))
|
||||
if !f.fullAccess {
|
||||
base = base.Where(goqu.L("r.permissions[?]::INTEGER <> 0", f.userID))
|
||||
}
|
||||
rec := goqu.From(r).Select(r.Col("id"), r.Col("parent"), r.Col("deleted")).Join(n, goqu.On(r.Col("parent").Eq(n.Col("id"))))
|
||||
if !time.IsZero() {
|
||||
base = base.Where(r.Col("deleted").Lt(goqu.V(time.UTC())))
|
||||
}
|
||||
|
||||
rec := pg.
|
||||
From(r).
|
||||
Select(r.Col("id"), r.Col("parent"), r.Col("deleted")).
|
||||
Join(n, goqu.On(r.Col("parent").Eq(n.Col("id")))).
|
||||
// Some children may be independently trashed (at different times). Don't select those
|
||||
Where(goqu.L("? IS NOT DISTINCT FROM ?", r.Col("deleted"), n.Col("deleted")))
|
||||
|
||||
q := pg.From(n).WithRecursive("nodes(id, parent, deleted)", base.UnionAll(rec))
|
||||
|
||||
@@ -129,8 +141,7 @@ func (f filesystem) selectTrash() (exp.AliasedExpression, *goqu.SelectDataset) {
|
||||
}
|
||||
|
||||
func (f filesystem) hardDeleteOldResources(t time.Time) error {
|
||||
n, q := f.selectTrash()
|
||||
q = q.Where(n.Col("deleted").Lt(goqu.V(t.UTC())))
|
||||
n, q := f.selectTrash(t)
|
||||
return hardDeleteAllVersions(f.db, q, n)
|
||||
}
|
||||
|
||||
@@ -153,7 +164,11 @@ func hardDeleteAllVersions(db db.Handler, q *goqu.SelectDataset, n interface {
|
||||
}
|
||||
|
||||
r := goqu.T("resources")
|
||||
query, args, _ := q.From(r).Join(n, goqu.On(n.Col("id").Eq(r.Col("id")))).Delete().ToSQL()
|
||||
fmt.Println("DELETE QUERY")
|
||||
query, args, _ := q.
|
||||
From(r).
|
||||
Where(r.Col("id").Eq(pg.From(n).Select("id"))).
|
||||
Delete().ToSQL()
|
||||
|
||||
if _, err := db.Exec(query, args...); err != nil {
|
||||
return err
|
||||
|
||||
Reference in New Issue
Block a user