
-- name: ReadDir :many
WITH RECURSIVE nodes(id, parent, name, dir, created, modified, size, sha256sum, depth, path, permission) AS (
    SELECT r.id, r.parent, r.name, r.dir, r.created, r.modified, r.size, r.sha256sum, 0, ''::text, @permission::int
    FROM resources r
    WHERE r.id = @id::uuid
  UNION ALL
    SELECT r.id, r.parent, r.name, r.dir, r.created, r.modified, r.size, r.sha256sum, n.depth + 1, concat(n.path, '/', r.name),
      CASE
        WHEN p.permission > n.permission THEN p.permission
        ELSE n.permission
      END
    FROM resources r JOIN nodes n on r.parent = n.id
    LEFT JOIN permissions p
    ON r.id = p.resource_id 
    AND p.user_id = @user_id::int
    WHERE deleted IS NULL
    AND r.id != @id::uuid
    AND CASE WHEN @recursive::boolean THEN true ELSE depth < 1 END
)
SELECT * from nodes
WHERE CASE WHEN @include_root::boolean THEN true ELSE depth > 0 END;

-- name: ResourceByPath :one
WITH RECURSIVE nodes(id, parent, name, dir, created, modified, size, sha256sum, depth, path, search, permission) AS (
    SELECT r.id, r.parent, r.name, r.dir, r.created, r.modified, r.size, r.sha256sum, 0, ''::text, @search::text[], @permission::int
    FROM resources r
    WHERE r.id = @root::uuid
  UNION ALL
    SELECT r.id, r.parent, r.name, r.dir, r.created, r.modified, r.size, r.sha256sum, n.depth + 1, concat(n.path, '/', r.name), n.search,
      CASE
        WHEN p.permission > n.permission THEN p.permission
        ELSE n.permission
      END
    FROM resources r
    JOIN nodes n ON r.parent = n.id
    LEFT JOIN permissions p
    ON r.id = p.resource_id 
    AND p.user_id = @user_id::int
    WHERE deleted IS NULL
    AND r.name = n.search[n.depth + 1]
)
SELECT * FROM nodes WHERE cardinality(search) = depth;

-- name: ResourceByID :one
WITH RECURSIVE nodes(resid, id, parent, found, permission) AS (
  SELECT @resource_id::uuid, r.id, r.parent,
      CASE
        WHEN r.id = @root::uuid THEN true
        ELSE false
      END,
      CASE
        WHEN p.permission IS NOT NULL THEN p.permission
        ELSE 0
      END
    FROM resources r
    LEFT JOIN permissions p
    ON p.resource_id = r.id
    AND p.user_id = @user_id::int
    WHERE r.id = @resource_id::uuid 
  UNION ALL
    SELECT n.resid, r.id, r.parent,
      CASE
        WHEN r.id = @root::uuid THEN true
        ELSE n.found
      END,
      CASE
        WHEN p.permission > n.permission THEN p.permission
        ELSE n.permission
      END
    FROM resources r
    JOIN nodes n
    ON r.id = n.parent
    LEFT JOIN permissions p
    ON r.id = p.resource_id AND p.user_id = @user_id::int
)
SELECT resid AS id, found, permission, r.parent, name, dir, created, modified, deleted, size, sha256sum FROM nodes n
JOIN resources r
ON r.id = n.resid
WHERE n.parent IS NULL;

-- name: UpdatePermissionsForResource :exec
INSERT INTO permissions(resource_id, user_id, permission)
    VALUES(@resource_id::uuid, @user_id::int, @permission::int)
    ON CONFLICT(resource_id, user_id) DO UPDATE SET permission = @permission::int;

-- name: GetLocalPermissionsForResource :many
SELECT p.user_id, CAST(p.permission AS INT) AS permission
  FROM permissions p
  WHERE p.resource_id = @resource_id::uuid;


-- name: GetInheritedPermissionsForResource :many
WITH RECURSIVE nodes(id, parent) AS (
  SELECT r.id, r.parent
    FROM resources r
    WHERE r.id = @resource_id::uuid
  UNION ALL (
    SELECT r.id, r.parent
     FROM resources r
     JOIN nodes n
     ON r.id = n.parent
  )
)
SELECT p.user_id, CAST(MAX(p.permission) AS INT) AS permission
  FROM permissions p
  JOIN nodes n
  ON n.id = p.resource_id
  GROUP BY p.user_id;
