Add Phase 2 artifact repository: types, blob store, gRPC service
Build the complete artifact pillar with five packages: - artifacts: Artifact, Snapshot, Citation, Publisher types with Get/Store DB methods, tag/category management, metadata ops, YAML import - blob: content-addressable store (SHA256, hierarchical dir layout) - proto: protobuf definitions (common.proto, artifacts.proto) with buf linting and code generation - server: gRPC ArtifactService implementation (create/get artifacts, store/retrieve blobs, manage tags/categories, search by tag) All FK insertion ordering is correct (parent rows before children). Full test coverage across artifacts, blob, and server packages. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
42
artifacts/metadata.go
Normal file
42
artifacts/metadata.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package artifacts
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
|
||||
"git.wntrmute.dev/kyle/exo/core"
|
||||
)
|
||||
|
||||
// StoreMetadata persists metadata key-value pairs for the given owner ID.
|
||||
func StoreMetadata(ctx context.Context, tx *sql.Tx, id string, metadata core.Metadata) error {
|
||||
for key, value := range metadata {
|
||||
_, err := tx.ExecContext(ctx,
|
||||
`INSERT OR REPLACE INTO metadata (id, mkey, contents, type) VALUES (?, ?, ?, ?)`,
|
||||
id, key, value.Contents, value.Type)
|
||||
if err != nil {
|
||||
return fmt.Errorf("artifacts: failed to store metadata for %s: %w", id, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetMetadata retrieves all metadata key-value pairs for the given owner ID.
|
||||
func GetMetadata(ctx context.Context, tx *sql.Tx, id string) (core.Metadata, error) {
|
||||
metadata := core.Metadata{}
|
||||
rows, err := tx.QueryContext(ctx,
|
||||
`SELECT mkey, contents, type FROM metadata WHERE id=?`, id)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("artifacts: failed to retrieve metadata for %s: %w", id, err)
|
||||
}
|
||||
defer func() { _ = rows.Close() }()
|
||||
|
||||
for rows.Next() {
|
||||
var key, contents, ctype string
|
||||
if err := rows.Scan(&key, &contents, &ctype); err != nil {
|
||||
return nil, fmt.Errorf("artifacts: failed to scan metadata row: %w", err)
|
||||
}
|
||||
metadata[key] = core.Value{Contents: contents, Type: ctype}
|
||||
}
|
||||
return metadata, rows.Err()
|
||||
}
|
||||
Reference in New Issue
Block a user