Add and use a DB view for paths and tags
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:
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user