mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-10-11 03:13:24 +00:00
feat(store): add Upsert() to BuiltinToolStore for additive tool seeding (#554)
Approved by github-maintain automation. Clean implementation of additive Upsert() for fork-specific tool seeding. Solves #336.
This commit is contained in:
1 parent
dc4cfddd31
commit
519df3dd17
3 files changed
+105
No files matched your search
@@ -29,6 +29,9 @@ type BuiltinToolStore interface {
|
||||
Get(ctx context.Context, name string) (*BuiltinToolDef, error)
|
||||
Update(ctx context.Context, name string, updates map[string]any) error
|
||||
Seed(ctx context.Context, tools []BuiltinToolDef) error
|
||||
// Upsert inserts/updates tools without reconcile — safe for additive fork-specific tools.
|
||||
// Does NOT delete rows not in the provided list.
|
||||
Upsert(ctx context.Context, tools []BuiltinToolDef) error
|
||||
ListEnabled(ctx context.Context) ([]BuiltinToolDef, error)
|
||||
GetSettings(ctx context.Context, name string) (json.RawMessage, error)
|
||||
}
|
||||
@@ -159,6 +159,57 @@ func (s *PGBuiltinToolStore) Seed(ctx context.Context, tools []store.BuiltinTool
|
||||
return tx.Commit()
|
||||
}
|
||||
|
||||
// Upsert inserts or updates builtin tool definitions without reconcile DELETE.
|
||||
// Safe for additive fork-specific tools -- does NOT delete rows not in the list.
|
||||
func (s *PGBuiltinToolStore) Upsert(ctx context.Context, tools []store.BuiltinToolDef) error {
|
||||
tx, err := s.db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer tx.Rollback()
|
||||
|
||||
stmt, err := tx.PrepareContext(ctx,
|
||||
`INSERT INTO builtin_tools (name, display_name, description, category, enabled, settings, requires, metadata, created_at, updated_at)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $9)
|
||||
ON CONFLICT (name) DO UPDATE SET
|
||||
display_name = EXCLUDED.display_name,
|
||||
description = EXCLUDED.description,
|
||||
category = EXCLUDED.category,
|
||||
requires = EXCLUDED.requires,
|
||||
metadata = EXCLUDED.metadata,
|
||||
settings = CASE
|
||||
WHEN builtin_tools.settings IS NULL OR builtin_tools.settings::text IN ('{}', 'null')
|
||||
THEN EXCLUDED.settings
|
||||
ELSE builtin_tools.settings
|
||||
END,
|
||||
updated_at = EXCLUDED.updated_at`)
|
||||
if err != nil {
|
||||
return fmt.Errorf("prepare upsert stmt: %w", err)
|
||||
}
|
||||
defer stmt.Close()
|
||||
|
||||
now := time.Now()
|
||||
for _, t := range tools {
|
||||
settings := t.Settings
|
||||
if settings == nil {
|
||||
settings = json.RawMessage("{}")
|
||||
}
|
||||
metadata := t.Metadata
|
||||
if metadata == nil {
|
||||
metadata = json.RawMessage("{}")
|
||||
}
|
||||
_, err := stmt.ExecContext(ctx,
|
||||
t.Name, t.DisplayName, t.Description, t.Category,
|
||||
t.Enabled, []byte(settings), pqStringArray(t.Requires), []byte(metadata), now,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("upsert tool %s: %w", t.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
return tx.Commit()
|
||||
}
|
||||
|
||||
func (s *PGBuiltinToolStore) scanTool(row *sql.Row) (*store.BuiltinToolDef, error) {
|
||||
var def store.BuiltinToolDef
|
||||
var settings []byte
|
||||
|
||||
@@ -168,6 +168,57 @@ func (s *SQLiteBuiltinToolStore) Seed(ctx context.Context, tools []store.Builtin
|
||||
return tx.Commit()
|
||||
}
|
||||
|
||||
// Upsert inserts or updates builtin tool definitions without reconcile DELETE.
|
||||
// Safe for additive fork-specific tools -- does NOT delete rows not in the list.
|
||||
func (s *SQLiteBuiltinToolStore) Upsert(ctx context.Context, tools []store.BuiltinToolDef) error {
|
||||
tx, err := s.db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer tx.Rollback()
|
||||
|
||||
stmt, err := tx.PrepareContext(ctx,
|
||||
`INSERT INTO builtin_tools (name, display_name, description, category, enabled, settings, requires, metadata, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
ON CONFLICT (name) DO UPDATE SET
|
||||
display_name = excluded.display_name,
|
||||
description = excluded.description,
|
||||
category = excluded.category,
|
||||
requires = excluded.requires,
|
||||
metadata = excluded.metadata,
|
||||
settings = CASE
|
||||
WHEN builtin_tools.settings IS NULL OR builtin_tools.settings IN ('{}', 'null')
|
||||
THEN excluded.settings
|
||||
ELSE builtin_tools.settings
|
||||
END,
|
||||
updated_at = excluded.updated_at`)
|
||||
if err != nil {
|
||||
return fmt.Errorf("prepare upsert stmt: %w", err)
|
||||
}
|
||||
defer stmt.Close()
|
||||
|
||||
now := time.Now()
|
||||
for _, t := range tools {
|
||||
settings := t.Settings
|
||||
if settings == nil {
|
||||
settings = json.RawMessage("{}")
|
||||
}
|
||||
metadata := t.Metadata
|
||||
if metadata == nil {
|
||||
metadata = json.RawMessage("{}")
|
||||
}
|
||||
_, err := stmt.ExecContext(ctx,
|
||||
t.Name, t.DisplayName, t.Description, t.Category,
|
||||
t.Enabled, []byte(settings), jsonStringArray(t.Requires), []byte(metadata), now, now,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("upsert tool %s: %w", t.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
return tx.Commit()
|
||||
}
|
||||
|
||||
func (s *SQLiteBuiltinToolStore) scanTool(row *sql.Row) (*store.BuiltinToolDef, error) {
|
||||
var def store.BuiltinToolDef
|
||||
var settings []byte
|
||||
|
||||
Reference in new issue
Block a user