fix: PG array format for tags, entity slug prefixes, archive path handling
- knowledge.go: scan tags as []string from pgx (not JSON) - seed.go: convert tags to PG array format, fix runbook applies_to_type - convert-wiki.py: fix entity slug prefixes to match inventory.yaml (host: not proxmox-host:, ws: not workstation:, service:homelab-mcp with hyphen) - convert-wiki.py: read from archive/knowledge/ since wiki was archived
This commit is contained in:
@@ -2,10 +2,8 @@ package httpapi
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/dtoro/oikos/internal/httpapi/gen"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
func (s *Server) SearchKnowledge(ctx context.Context, request gen.SearchKnowledgeRequestObject) (gen.SearchKnowledgeResponseObject, error) {
|
||||
@@ -33,17 +31,15 @@ func (s *Server) SearchKnowledge(ctx context.Context, request gen.SearchKnowledg
|
||||
items := []gen.KnowledgeHit{}
|
||||
|
||||
for rows.Next() {
|
||||
var slug, eType, title, source, tagJSON string
|
||||
var slug, eType, title, source string
|
||||
var tags []string
|
||||
var rank float32
|
||||
var snippet *string
|
||||
|
||||
if err := rows.Scan(&slug, &eType, &title, &source, &tagJSON, &rank, &snippet); err != nil {
|
||||
if err := rows.Scan(&slug, &eType, &title, &source, &tags, &rank, &snippet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tags []string
|
||||
json.Unmarshal([]byte(tagJSON), &tags)
|
||||
|
||||
hitType := gen.Document
|
||||
switch eType {
|
||||
case "investigation":
|
||||
@@ -52,9 +48,6 @@ func (s *Server) SearchKnowledge(ctx context.Context, request gen.SearchKnowledg
|
||||
hitType = gen.Runbook
|
||||
}
|
||||
|
||||
id, _ := uuid.Parse("")
|
||||
_ = id // not needed for response since we use slug
|
||||
|
||||
items = append(items, gen.KnowledgeHit{
|
||||
Slug: slug,
|
||||
Title: title,
|
||||
@@ -107,13 +100,12 @@ func (s *Server) GetEntityKnowledge(ctx context.Context, request gen.GetEntityKn
|
||||
|
||||
items := []gen.KnowledgeHit{}
|
||||
for rows.Next() {
|
||||
var slug, eType, title, source, tagJSON string
|
||||
var slug, eType, title, source string
|
||||
var tags []string
|
||||
|
||||
if err := rows.Scan(&slug, &eType, &title, &source, &tagJSON); err != nil {
|
||||
if err := rows.Scan(&slug, &eType, &title, &source, &tags); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
json.Unmarshal([]byte(tagJSON), &tags)
|
||||
|
||||
hitType := gen.Document
|
||||
switch eType {
|
||||
|
||||
@@ -191,6 +191,9 @@ func ingestRunbook(ctx context.Context, tx pgx.Tx, m map[string]any) error {
|
||||
if riskClass != "" {
|
||||
attrs["risk_class"] = riskClass
|
||||
}
|
||||
if entityType != "" {
|
||||
attrs["applies_to_type"] = entityType
|
||||
}
|
||||
if len(procedure) > 0 {
|
||||
attrs["procedure"] = procedure
|
||||
}
|
||||
@@ -204,12 +207,6 @@ func ingestRunbook(ctx context.Context, tx pgx.Tx, m map[string]any) error {
|
||||
}
|
||||
}
|
||||
|
||||
if entityType != "" {
|
||||
if err := createEdge(ctx, tx, entitySlug, entityType, "procedure-for", nil); err != nil {
|
||||
return fmt.Errorf("link runbook: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -220,7 +217,7 @@ func upsertKnowledgeEntity(ctx context.Context, tx pgx.Tx, slug, entityType, tit
|
||||
}
|
||||
|
||||
hash := contentHash(content)
|
||||
tagsJSON, _ := json.Marshal(tags)
|
||||
tagArray := toPGArray(tags)
|
||||
|
||||
_, err = tx.Exec(ctx,
|
||||
`INSERT INTO knowledge_entities (entity_id, title, content, source, tags, content_hash, created_at, updated_at)
|
||||
@@ -228,7 +225,7 @@ func upsertKnowledgeEntity(ctx context.Context, tx pgx.Tx, slug, entityType, tit
|
||||
ON CONFLICT (entity_id) DO UPDATE SET
|
||||
title = $2, content = $3, source = $4, tags = $5,
|
||||
content_hash = $6, updated_at = now()`,
|
||||
id, title, content, source, string(tagsJSON), hash)
|
||||
id, title, content, source, tagArray, hash)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -273,4 +270,19 @@ func createEdge(ctx context.Context, tx pgx.Tx, sourceSlug, targetSlug, relType
|
||||
DO UPDATE SET attributes = EXCLUDED.attributes`,
|
||||
sourceID, targetID, relType, string(attrsBytes))
|
||||
return err
|
||||
}
|
||||
|
||||
func toPGArray(tags []string) string {
|
||||
if len(tags) == 0 {
|
||||
return "{}"
|
||||
}
|
||||
out := "{"
|
||||
for i, t := range tags {
|
||||
if i > 0 {
|
||||
out += ","
|
||||
}
|
||||
out += `"` + t + `"`
|
||||
}
|
||||
out += "}"
|
||||
return out
|
||||
}
|
||||
Reference in New Issue
Block a user