Changeset 0.22.2 (#96)
This commit is contained in:
@@ -45,6 +45,7 @@ type Stores struct {
|
||||
Workspaces WorkspaceStore
|
||||
GitCredentials GitCredentialStore
|
||||
CapOverrides CapabilityOverrideStore
|
||||
RoutingPolicies RoutingPolicyStore
|
||||
}
|
||||
|
||||
// =========================================
|
||||
@@ -587,6 +588,33 @@ type CapabilityOverrideStore interface {
|
||||
DeleteForProvider(ctx context.Context, providerConfigID string) error
|
||||
}
|
||||
|
||||
// =========================================
|
||||
// ROUTING POLICY STORE (v0.22.2)
|
||||
// =========================================
|
||||
|
||||
type RoutingPolicyStore interface {
|
||||
// Create adds a new routing policy.
|
||||
Create(ctx context.Context, p *models.RoutingPolicy) error
|
||||
|
||||
// Update modifies an existing routing policy.
|
||||
Update(ctx context.Context, p *models.RoutingPolicy) error
|
||||
|
||||
// Delete removes a routing policy by ID.
|
||||
Delete(ctx context.Context, id string) error
|
||||
|
||||
// GetByID returns a single policy.
|
||||
GetByID(ctx context.Context, id string) (*models.RoutingPolicy, error)
|
||||
|
||||
// ListActive returns all active policies, ordered by priority ASC.
|
||||
ListActive(ctx context.Context) ([]models.RoutingPolicy, error)
|
||||
|
||||
// ListAll returns all policies (including inactive), for admin listing.
|
||||
ListAll(ctx context.Context) ([]models.RoutingPolicy, error)
|
||||
|
||||
// ListForTeam returns active policies applicable to a team (team-scoped + global).
|
||||
ListForTeam(ctx context.Context, teamID string) ([]models.RoutingPolicy, error)
|
||||
}
|
||||
|
||||
// =========================================
|
||||
// SHARED TYPES
|
||||
// =========================================
|
||||
|
||||
110
server/store/postgres/routing_policy.go
Normal file
110
server/store/postgres/routing_policy.go
Normal file
@@ -0,0 +1,110 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
|
||||
"git.gobha.me/xcaliber/chat-switchboard/models"
|
||||
)
|
||||
|
||||
// RoutingPolicyStore implements store.RoutingPolicyStore for Postgres.
|
||||
type RoutingPolicyStore struct {
|
||||
db *sql.DB
|
||||
}
|
||||
|
||||
func NewRoutingPolicyStore(db *sql.DB) *RoutingPolicyStore {
|
||||
return &RoutingPolicyStore{db: db}
|
||||
}
|
||||
|
||||
func (s *RoutingPolicyStore) Create(ctx context.Context, p *models.RoutingPolicy) error {
|
||||
configJSON, err := json.Marshal(p.Config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return s.db.QueryRowContext(ctx, `
|
||||
INSERT INTO routing_policies (name, scope, team_id, priority, policy_type, config, is_active)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
||||
RETURNING id, created_at, updated_at
|
||||
`, p.Name, p.Scope, p.TeamID, p.Priority, p.Type, configJSON, p.IsActive,
|
||||
).Scan(&p.ID, &p.CreatedAt, &p.UpdatedAt)
|
||||
}
|
||||
|
||||
func (s *RoutingPolicyStore) Update(ctx context.Context, p *models.RoutingPolicy) error {
|
||||
configJSON, err := json.Marshal(p.Config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = s.db.ExecContext(ctx, `
|
||||
UPDATE routing_policies
|
||||
SET name = $2, scope = $3, team_id = $4, priority = $5,
|
||||
policy_type = $6, config = $7, is_active = $8
|
||||
WHERE id = $1
|
||||
`, p.ID, p.Name, p.Scope, p.TeamID, p.Priority, p.Type, configJSON, p.IsActive)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *RoutingPolicyStore) Delete(ctx context.Context, id string) error {
|
||||
_, err := s.db.ExecContext(ctx, `DELETE FROM routing_policies WHERE id = $1`, id)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *RoutingPolicyStore) GetByID(ctx context.Context, id string) (*models.RoutingPolicy, error) {
|
||||
var p models.RoutingPolicy
|
||||
var configJSON []byte
|
||||
err := s.db.QueryRowContext(ctx, `
|
||||
SELECT id, name, scope, team_id, priority, policy_type, config, is_active, created_at, updated_at
|
||||
FROM routing_policies WHERE id = $1
|
||||
`, id).Scan(&p.ID, &p.Name, &p.Scope, &p.TeamID, &p.Priority, &p.Type, &configJSON, &p.IsActive, &p.CreatedAt, &p.UpdatedAt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
json.Unmarshal(configJSON, &p.Config)
|
||||
return &p, nil
|
||||
}
|
||||
|
||||
func (s *RoutingPolicyStore) ListActive(ctx context.Context) ([]models.RoutingPolicy, error) {
|
||||
return s.query(ctx, `
|
||||
SELECT id, name, scope, team_id, priority, policy_type, config, is_active, created_at, updated_at
|
||||
FROM routing_policies
|
||||
WHERE is_active = true
|
||||
ORDER BY priority ASC, created_at ASC
|
||||
`)
|
||||
}
|
||||
|
||||
func (s *RoutingPolicyStore) ListAll(ctx context.Context) ([]models.RoutingPolicy, error) {
|
||||
return s.query(ctx, `
|
||||
SELECT id, name, scope, team_id, priority, policy_type, config, is_active, created_at, updated_at
|
||||
FROM routing_policies
|
||||
ORDER BY priority ASC, created_at ASC
|
||||
`)
|
||||
}
|
||||
|
||||
func (s *RoutingPolicyStore) ListForTeam(ctx context.Context, teamID string) ([]models.RoutingPolicy, error) {
|
||||
return s.query(ctx, `
|
||||
SELECT id, name, scope, team_id, priority, policy_type, config, is_active, created_at, updated_at
|
||||
FROM routing_policies
|
||||
WHERE is_active = true AND (scope = 'global' OR (scope = 'team' AND team_id = $1))
|
||||
ORDER BY priority ASC, created_at ASC
|
||||
`, teamID)
|
||||
}
|
||||
|
||||
func (s *RoutingPolicyStore) query(ctx context.Context, q string, args ...interface{}) ([]models.RoutingPolicy, error) {
|
||||
rows, err := s.db.QueryContext(ctx, q, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var result []models.RoutingPolicy
|
||||
for rows.Next() {
|
||||
var p models.RoutingPolicy
|
||||
var configJSON []byte
|
||||
if err := rows.Scan(&p.ID, &p.Name, &p.Scope, &p.TeamID, &p.Priority, &p.Type, &configJSON, &p.IsActive, &p.CreatedAt, &p.UpdatedAt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
json.Unmarshal(configJSON, &p.Config)
|
||||
result = append(result, p)
|
||||
}
|
||||
return result, rows.Err()
|
||||
}
|
||||
@@ -38,5 +38,6 @@ func NewStores(db *sql.DB) store.Stores {
|
||||
Workspaces: NewWorkspaceStore(),
|
||||
GitCredentials: &GitCredentialStore{},
|
||||
CapOverrides: NewCapOverrideStore(db),
|
||||
RoutingPolicies: NewRoutingPolicyStore(db),
|
||||
}
|
||||
}
|
||||
|
||||
116
server/store/sqlite/routing_policy.go
Normal file
116
server/store/sqlite/routing_policy.go
Normal file
@@ -0,0 +1,116 @@
|
||||
package sqlite
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"git.gobha.me/xcaliber/chat-switchboard/models"
|
||||
"git.gobha.me/xcaliber/chat-switchboard/store"
|
||||
)
|
||||
|
||||
// RoutingPolicyStore implements store.RoutingPolicyStore for SQLite.
|
||||
type RoutingPolicyStore struct{}
|
||||
|
||||
func NewRoutingPolicyStore() *RoutingPolicyStore { return &RoutingPolicyStore{} }
|
||||
|
||||
func (s *RoutingPolicyStore) Create(ctx context.Context, p *models.RoutingPolicy) error {
|
||||
p.ID = store.NewID()
|
||||
configJSON, err := json.Marshal(p.Config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
now := time.Now().UTC()
|
||||
p.CreatedAt = now
|
||||
p.UpdatedAt = now
|
||||
_, err = DB.ExecContext(ctx, `
|
||||
INSERT INTO routing_policies (id, name, scope, team_id, priority, policy_type, config, is_active, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
`, p.ID, p.Name, p.Scope, p.TeamID, p.Priority, p.Type, string(configJSON), boolToInt(p.IsActive), p.CreatedAt.Format(time.RFC3339), p.UpdatedAt.Format(time.RFC3339))
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *RoutingPolicyStore) Update(ctx context.Context, p *models.RoutingPolicy) error {
|
||||
configJSON, err := json.Marshal(p.Config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = DB.ExecContext(ctx, `
|
||||
UPDATE routing_policies
|
||||
SET name = ?, scope = ?, team_id = ?, priority = ?,
|
||||
policy_type = ?, config = ?, is_active = ?, updated_at = datetime('now')
|
||||
WHERE id = ?
|
||||
`, p.Name, p.Scope, p.TeamID, p.Priority, p.Type, string(configJSON), boolToInt(p.IsActive), p.ID)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *RoutingPolicyStore) Delete(ctx context.Context, id string) error {
|
||||
_, err := DB.ExecContext(ctx, `DELETE FROM routing_policies WHERE id = ?`, id)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *RoutingPolicyStore) GetByID(ctx context.Context, id string) (*models.RoutingPolicy, error) {
|
||||
var p models.RoutingPolicy
|
||||
var configJSON string
|
||||
var isActive int
|
||||
err := DB.QueryRowContext(ctx, `
|
||||
SELECT id, name, scope, team_id, priority, policy_type, config, is_active, created_at, updated_at
|
||||
FROM routing_policies WHERE id = ?
|
||||
`, id).Scan(&p.ID, &p.Name, &p.Scope, &p.TeamID, &p.Priority, &p.Type, &configJSON, &isActive, &p.CreatedAt, &p.UpdatedAt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.IsActive = isActive != 0
|
||||
json.Unmarshal([]byte(configJSON), &p.Config)
|
||||
return &p, nil
|
||||
}
|
||||
|
||||
func (s *RoutingPolicyStore) ListActive(ctx context.Context) ([]models.RoutingPolicy, error) {
|
||||
return s.query(ctx, `
|
||||
SELECT id, name, scope, team_id, priority, policy_type, config, is_active, created_at, updated_at
|
||||
FROM routing_policies
|
||||
WHERE is_active = 1
|
||||
ORDER BY priority ASC, created_at ASC
|
||||
`)
|
||||
}
|
||||
|
||||
func (s *RoutingPolicyStore) ListAll(ctx context.Context) ([]models.RoutingPolicy, error) {
|
||||
return s.query(ctx, `
|
||||
SELECT id, name, scope, team_id, priority, policy_type, config, is_active, created_at, updated_at
|
||||
FROM routing_policies
|
||||
ORDER BY priority ASC, created_at ASC
|
||||
`)
|
||||
}
|
||||
|
||||
func (s *RoutingPolicyStore) ListForTeam(ctx context.Context, teamID string) ([]models.RoutingPolicy, error) {
|
||||
return s.query(ctx, `
|
||||
SELECT id, name, scope, team_id, priority, policy_type, config, is_active, created_at, updated_at
|
||||
FROM routing_policies
|
||||
WHERE is_active = 1 AND (scope = 'global' OR (scope = 'team' AND team_id = ?))
|
||||
ORDER BY priority ASC, created_at ASC
|
||||
`, teamID)
|
||||
}
|
||||
|
||||
func (s *RoutingPolicyStore) query(ctx context.Context, q string, args ...interface{}) ([]models.RoutingPolicy, error) {
|
||||
rows, err := DB.QueryContext(ctx, q, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var result []models.RoutingPolicy
|
||||
for rows.Next() {
|
||||
var p models.RoutingPolicy
|
||||
var configJSON string
|
||||
var isActive int
|
||||
if err := rows.Scan(&p.ID, &p.Name, &p.Scope, &p.TeamID, &p.Priority, &p.Type, &configJSON, &isActive, &p.CreatedAt, &p.UpdatedAt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.IsActive = isActive != 0
|
||||
json.Unmarshal([]byte(configJSON), &p.Config)
|
||||
result = append(result, p)
|
||||
}
|
||||
return result, rows.Err()
|
||||
}
|
||||
|
||||
var _ store.RoutingPolicyStore = (*RoutingPolicyStore)(nil)
|
||||
@@ -38,5 +38,6 @@ func NewStores(db *sql.DB) store.Stores {
|
||||
Workspaces: NewWorkspaceStore(),
|
||||
GitCredentials: &GitCredentialStore{},
|
||||
CapOverrides: NewCapOverrideStore(),
|
||||
RoutingPolicies: NewRoutingPolicyStore(),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user