Add and use a DB view for paths and tags
Alpine 3.24 Success
Debian Bookworm Success

The view is mainly useful for querying the database
with the command line sqlite3 utility.

Letting SQLite serialize the JSON is an inconsequential
performance improvement.
This commit is contained in:
2026-08-05 04:24:36 +02:00
parent 2d989b6eef
commit 739c1e2f6b
2 changed files with 52 additions and 24 deletions
+34
View File
@@ -104,3 +104,37 @@ CREATE TABLE IF NOT EXISTS tag_assignment(
) STRICT;
CREATE INDEX IF NOT EXISTS tag_assignment__tag ON tag_assignment(tag);
--
CREATE VIEW IF NOT EXISTS image_with_metadata AS
SELECT
i.*,
(
-- As in getImagePaths, with the sha1 injected from another field
WITH RECURSIVE paths(parent, path) AS (
SELECT parent, name FROM node WHERE sha1 = i.sha1
UNION ALL
SELECT n.parent, n.name || '/' || p.path
FROM node AS n JOIN paths AS p ON n.id = p.parent
)
SELECT json_group_array(path ORDER BY path)
FROM paths WHERE parent IS NULL
) AS paths,
(
-- As in getImageTags, with the sha1 injected from another field,
-- and grouped into JSON as (tag space -> tag name -> weight)
SELECT json_group_object(space, json(tags))
FROM (
SELECT
ts.name AS space,
json_group_object(t.name, ta.weight ORDER BY t.name) AS tags
FROM tag_assignment AS ta
JOIN tag AS t ON t.id = ta.tag
JOIN tag_space AS ts ON ts.id = t.space
WHERE ta.sha1 = i.sha1
GROUP BY ts.id
ORDER BY ts.name
)
) AS tags
FROM image AS i;
+18 -24
View File
@@ -793,12 +793,6 @@ func handleAPIOpen(w http.ResponseWriter, r *http.Request) {
http.Error(w, "no launcher", http.StatusInternalServerError)
}
func getImageDimensions(sha1 string) (w int64, h int64, err error) {
err = db.QueryRow(`SELECT width, height FROM image WHERE sha1 = ?`,
sha1).Scan(&w, &h)
return
}
func getImagePaths(sha1 string) (paths []string, err error) {
rows, err := db.Query(`WITH RECURSIVE paths(parent, path) AS (
SELECT parent, name AS path FROM node WHERE sha1 = ?
@@ -862,15 +856,14 @@ func handleAPIInfo(w http.ResponseWriter, r *http.Request) {
return
}
var result struct {
Width int64 `json:"width"`
Height int64 `json:"height"`
Paths []string `json:"paths"`
Tags map[string]map[string]float32 `json:"tags"`
}
var err error
result.Width, result.Height, err = getImageDimensions(params.SHA1)
// Let's not build JSON manually if SQLite can do this for us.
var (
width, height int64
paths, tags []byte
)
err := db.QueryRow(`SELECT width, height, paths, tags
FROM image_with_metadata WHERE sha1 = ?`, params.SHA1).
Scan(&width, &height, &paths, &tags)
if errors.Is(err, sql.ErrNoRows) {
http.Error(w, err.Error(), http.StatusNotFound)
return
@@ -879,15 +872,16 @@ func handleAPIInfo(w http.ResponseWriter, r *http.Request) {
return
}
result.Paths, err = getImagePaths(params.SHA1)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
result.Tags, err = getImageTags(params.SHA1)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
result := struct {
Width int64 `json:"width"`
Height int64 `json:"height"`
Paths json.RawMessage `json:"paths"`
Tags json.RawMessage `json:"tags"`
}{
Width: width,
Height: height,
Paths: json.RawMessage(paths),
Tags: json.RawMessage(tags),
}
if err := json.NewEncoder(w).Encode(result); err != nil {
log.Println(err)