mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-10-14 16:17:25 +00:00
fix(store): provider CreateProvider uses UPSERT to handle orphaned duplicates (#295)
CreateProvider now uses ON CONFLICT (tenant_id, name) DO UPDATE instead of plain INSERT. When a provider with the same name already exists (e.g. orphaned after agent deletion), it updates the existing record instead of failing with a unique constraint violation. Applied to both PG and SQLite implementations.
This commit is contained in:
1 parent
bdfc0fadfb
commit
4ac611530a
2 files changed
+30
-6
No files matched your search
@@ -52,11 +52,22 @@ func (s *PGProviderStore) CreateProvider(ctx context.Context, p *store.LLMProvid
|
||||
p.UpdatedAt = now
|
||||
tid := tenantIDForInsert(ctx)
|
||||
p.TenantID = tid
|
||||
_, err := s.db.ExecContext(ctx,
|
||||
// UPSERT: if provider with same (tenant_id, name) exists, update it and return its ID.
|
||||
// This handles orphaned providers left after agent deletion (#295).
|
||||
var actualID uuid.UUID
|
||||
err := s.db.QueryRowContext(ctx,
|
||||
`INSERT INTO llm_providers (id, name, display_name, provider_type, api_base, api_key, enabled, settings, created_at, updated_at, tenant_id)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)`,
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
|
||||
ON CONFLICT (tenant_id, name) DO UPDATE SET
|
||||
display_name = EXCLUDED.display_name, provider_type = EXCLUDED.provider_type,
|
||||
api_base = EXCLUDED.api_base, api_key = EXCLUDED.api_key,
|
||||
enabled = EXCLUDED.enabled, settings = EXCLUDED.settings, updated_at = EXCLUDED.updated_at
|
||||
RETURNING id`,
|
||||
p.ID, p.Name, p.DisplayName, p.ProviderType, p.APIBase, apiKey, p.Enabled, settings, now, now, tid,
|
||||
)
|
||||
).Scan(&actualID)
|
||||
if err == nil {
|
||||
p.ID = actualID // sync in-memory ID with actual DB row
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -54,11 +54,24 @@ func (s *SQLiteProviderStore) CreateProvider(ctx context.Context, p *store.LLMPr
|
||||
p.UpdatedAt = now
|
||||
tid := tenantIDForInsert(ctx)
|
||||
p.TenantID = tid
|
||||
_, err := s.db.ExecContext(ctx,
|
||||
// UPSERT: if provider with same (tenant_id, name) exists, update it and return its ID.
|
||||
// This handles orphaned providers left after agent deletion (#295).
|
||||
var actualID string
|
||||
err := s.db.QueryRowContext(ctx,
|
||||
`INSERT INTO llm_providers (id, name, display_name, provider_type, api_base, api_key, enabled, settings, created_at, updated_at, tenant_id)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
ON CONFLICT(tenant_id, name) DO UPDATE SET
|
||||
display_name = excluded.display_name, provider_type = excluded.provider_type,
|
||||
api_base = excluded.api_base, api_key = excluded.api_key,
|
||||
enabled = excluded.enabled, settings = excluded.settings, updated_at = excluded.updated_at
|
||||
RETURNING id`,
|
||||
p.ID, p.Name, p.DisplayName, p.ProviderType, p.APIBase, apiKey, p.Enabled, settings, now, now, tid,
|
||||
)
|
||||
).Scan(&actualID)
|
||||
if err == nil {
|
||||
if parsed, parseErr := uuid.Parse(actualID); parseErr == nil {
|
||||
p.ID = parsed // sync in-memory ID with actual DB row
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user