chore(repo): reinitialize repository
This commit is contained in:
@@ -0,0 +1,404 @@
|
||||
package sqlite
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"inbox/internal/domain/role"
|
||||
)
|
||||
|
||||
func (s *Store) GetRole(ctx context.Context, name string) (role.Definition, error) {
|
||||
row := s.db.QueryRowContext(ctx, `
|
||||
SELECT name, title, executor_kind, description, is_enabled, is_builtin, sort_order, created_at, updated_at
|
||||
FROM roles
|
||||
WHERE name = ?
|
||||
`, name)
|
||||
return scanRole(row)
|
||||
}
|
||||
|
||||
func (s *Store) ListRoles(ctx context.Context) ([]role.Definition, error) {
|
||||
rows, err := s.db.QueryContext(ctx, `
|
||||
SELECT name, title, executor_kind, description, is_enabled, is_builtin, sort_order, created_at, updated_at
|
||||
FROM roles
|
||||
ORDER BY sort_order, name
|
||||
`)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("list roles: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var out []role.Definition
|
||||
for rows.Next() {
|
||||
item, err := scanRole(rows)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out = append(out, item)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, fmt.Errorf("iterate roles: %w", err)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (s *Store) UpsertRole(ctx context.Context, value role.Definition, changedBy string) (role.Definition, error) {
|
||||
_ = changedBy
|
||||
value = role.NormalizeDefinition(value)
|
||||
if err := value.Validate(); err != nil {
|
||||
return role.Definition{}, err
|
||||
}
|
||||
tx, err := s.db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return role.Definition{}, fmt.Errorf("begin upsert role: %w", err)
|
||||
}
|
||||
defer tx.Rollback()
|
||||
|
||||
before, err := getRoleTx(ctx, tx, value.Name)
|
||||
if err != nil && !errors.Is(err, sql.ErrNoRows) {
|
||||
return role.Definition{}, err
|
||||
}
|
||||
now := s.now()
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
value.CreatedAt = now
|
||||
} else {
|
||||
value.CreatedAt = before.CreatedAt
|
||||
}
|
||||
value.UpdatedAt = now
|
||||
|
||||
if _, err := tx.ExecContext(ctx, `
|
||||
INSERT INTO roles(name, title, executor_kind, description, is_enabled, is_builtin, sort_order, created_at, updated_at)
|
||||
VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
ON CONFLICT(name) DO UPDATE SET
|
||||
title = excluded.title,
|
||||
executor_kind = excluded.executor_kind,
|
||||
description = excluded.description,
|
||||
is_enabled = excluded.is_enabled,
|
||||
is_builtin = excluded.is_builtin,
|
||||
sort_order = excluded.sort_order,
|
||||
updated_at = excluded.updated_at
|
||||
`,
|
||||
value.Name,
|
||||
value.Title,
|
||||
string(value.ExecutorKind),
|
||||
value.Description,
|
||||
boolToInt(value.IsEnabled),
|
||||
boolToInt(value.IsBuiltin),
|
||||
value.SortOrder,
|
||||
value.CreatedAt,
|
||||
value.UpdatedAt,
|
||||
); err != nil {
|
||||
return role.Definition{}, fmt.Errorf("upsert role %q: %w", value.Name, err)
|
||||
}
|
||||
after, err := getRoleTx(ctx, tx, value.Name)
|
||||
if err != nil {
|
||||
return role.Definition{}, err
|
||||
}
|
||||
if err := tx.Commit(); err != nil {
|
||||
return role.Definition{}, fmt.Errorf("commit upsert role: %w", err)
|
||||
}
|
||||
return after, nil
|
||||
}
|
||||
|
||||
func (s *Store) UpsertRolePrompt(ctx context.Context, value role.Prompt, changedBy string) (role.Prompt, error) {
|
||||
if err := value.Validate(); err != nil {
|
||||
return role.Prompt{}, err
|
||||
}
|
||||
return upsertVersionedConfig(ctx, s, value, changedBy, versionedConfigUpsertSpec[role.Prompt]{
|
||||
entityName: "role prompt",
|
||||
idKind: "role-prompt",
|
||||
loadTx: func(ctx context.Context, tx *sql.Tx) (role.Prompt, error) {
|
||||
return getRolePromptTx(ctx, tx, value.RoleName, value.WorkspaceID, value.PromptKind)
|
||||
},
|
||||
current: func(item role.Prompt) versionedConfigCurrent {
|
||||
return versionedConfigCurrent{
|
||||
ID: item.ID,
|
||||
Version: item.Version,
|
||||
CreatedAt: item.CreatedAt,
|
||||
}
|
||||
},
|
||||
applyMetadata: func(item *role.Prompt, meta versionedConfigMetadata) {
|
||||
item.ID = meta.ID
|
||||
item.Version = meta.Version
|
||||
item.CreatedAt = meta.CreatedAt
|
||||
item.UpdatedAt = meta.UpdatedAt
|
||||
},
|
||||
writeTx: func(ctx context.Context, tx *sql.Tx, item role.Prompt) error {
|
||||
_, err := tx.ExecContext(ctx, `
|
||||
INSERT INTO role_prompts(id, role_name, workspace_id, prompt_kind, content_markdown, version, updated_by, created_at, updated_at)
|
||||
VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
ON CONFLICT(id) DO UPDATE SET
|
||||
content_markdown = excluded.content_markdown,
|
||||
version = excluded.version,
|
||||
updated_by = excluded.updated_by,
|
||||
updated_at = excluded.updated_at
|
||||
`,
|
||||
item.ID,
|
||||
item.RoleName,
|
||||
nullableString(item.WorkspaceID),
|
||||
string(item.PromptKind),
|
||||
item.ContentMarkdown,
|
||||
item.Version,
|
||||
coalesceString(changedBy, item.UpdatedBy),
|
||||
item.CreatedAt,
|
||||
item.UpdatedAt,
|
||||
)
|
||||
return err
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Store) ListRolePrompts(ctx context.Context, roleName string) ([]role.Prompt, error) {
|
||||
rows, err := s.db.QueryContext(ctx, `
|
||||
SELECT id, role_name, workspace_id, prompt_kind, content_markdown, version, updated_by, created_at, updated_at
|
||||
FROM role_prompts
|
||||
WHERE role_name = ?
|
||||
ORDER BY prompt_kind, workspace_id, updated_at
|
||||
`, roleName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("list role prompts: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var out []role.Prompt
|
||||
for rows.Next() {
|
||||
item, err := scanRolePrompt(rows)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out = append(out, item)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, fmt.Errorf("iterate role prompts: %w", err)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (s *Store) UpsertRoleConfig(ctx context.Context, value role.Config, changedBy string) (role.Config, error) {
|
||||
_ = changedBy
|
||||
value = role.NormalizeConfig(value)
|
||||
if err := value.Validate(); err != nil {
|
||||
return role.Config{}, err
|
||||
}
|
||||
tx, err := s.db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return role.Config{}, fmt.Errorf("begin upsert role config: %w", err)
|
||||
}
|
||||
defer tx.Rollback()
|
||||
|
||||
result, err := tx.ExecContext(ctx, `
|
||||
UPDATE roles
|
||||
SET config_toml = ?, auth_json = ?, updated_at = ?
|
||||
WHERE name = ?
|
||||
`, value.ConfigTOML, value.AuthJSON, s.now(), value.RoleName)
|
||||
if err != nil {
|
||||
return role.Config{}, fmt.Errorf("upsert role config: %w", err)
|
||||
}
|
||||
if err := ensureAffected(result, sql.ErrNoRows); err != nil {
|
||||
return role.Config{}, err
|
||||
}
|
||||
after, err := getRoleConfigTx(ctx, tx, value.RoleName)
|
||||
if err != nil {
|
||||
return role.Config{}, err
|
||||
}
|
||||
if err := tx.Commit(); err != nil {
|
||||
return role.Config{}, fmt.Errorf("commit upsert role config: %w", err)
|
||||
}
|
||||
return after, nil
|
||||
}
|
||||
|
||||
func (s *Store) GetRoleConfig(ctx context.Context, roleName string) (role.Config, error) {
|
||||
row := s.db.QueryRowContext(ctx, `
|
||||
SELECT name, config_toml, auth_json
|
||||
FROM roles
|
||||
WHERE name = ?
|
||||
`, roleName)
|
||||
return scanRoleConfig(row)
|
||||
}
|
||||
|
||||
func (s *Store) UpsertRoleSkillBinding(ctx context.Context, value role.SkillBinding, changedBy string) (role.SkillBinding, error) {
|
||||
if err := value.Validate(); err != nil {
|
||||
return role.SkillBinding{}, err
|
||||
}
|
||||
return upsertVersionedConfig(ctx, s, value, changedBy, versionedConfigUpsertSpec[role.SkillBinding]{
|
||||
entityName: "role skill binding",
|
||||
idKind: "role-skill-binding",
|
||||
loadTx: func(ctx context.Context, tx *sql.Tx) (role.SkillBinding, error) {
|
||||
return getRoleSkillBindingTx(ctx, tx, value.RoleName, value.WorkspaceID, value.SkillID)
|
||||
},
|
||||
current: func(item role.SkillBinding) versionedConfigCurrent {
|
||||
return versionedConfigCurrent{
|
||||
ID: item.ID,
|
||||
Version: item.Version,
|
||||
CreatedAt: item.CreatedAt,
|
||||
}
|
||||
},
|
||||
applyMetadata: func(item *role.SkillBinding, meta versionedConfigMetadata) {
|
||||
item.ID = meta.ID
|
||||
item.Version = meta.Version
|
||||
item.CreatedAt = meta.CreatedAt
|
||||
item.UpdatedAt = meta.UpdatedAt
|
||||
},
|
||||
writeTx: func(ctx context.Context, tx *sql.Tx, item role.SkillBinding) error {
|
||||
configJSON, err := marshalJSONMapAny(item.Config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.ExecContext(ctx, `
|
||||
INSERT INTO role_skill_bindings(id, role_name, workspace_id, skill_id, is_enabled, sort_order, config_json, version, updated_by, created_at, updated_at)
|
||||
VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
ON CONFLICT(id) DO UPDATE SET
|
||||
is_enabled = excluded.is_enabled,
|
||||
sort_order = excluded.sort_order,
|
||||
config_json = excluded.config_json,
|
||||
version = excluded.version,
|
||||
updated_by = excluded.updated_by,
|
||||
updated_at = excluded.updated_at
|
||||
`,
|
||||
item.ID,
|
||||
item.RoleName,
|
||||
nullableString(item.WorkspaceID),
|
||||
item.SkillID,
|
||||
boolToInt(item.IsEnabled),
|
||||
item.SortOrder,
|
||||
configJSON,
|
||||
item.Version,
|
||||
coalesceString(changedBy, item.UpdatedBy),
|
||||
item.CreatedAt,
|
||||
item.UpdatedAt,
|
||||
)
|
||||
return err
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Store) ListRoleSkillBindings(ctx context.Context, roleName string) ([]role.SkillBinding, error) {
|
||||
rows, err := s.db.QueryContext(ctx, `
|
||||
SELECT id, role_name, workspace_id, skill_id, is_enabled, sort_order, config_json, version, updated_by, created_at, updated_at
|
||||
FROM role_skill_bindings
|
||||
WHERE role_name = ?
|
||||
ORDER BY sort_order, skill_id, workspace_id
|
||||
`, roleName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("list role skill bindings: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var out []role.SkillBinding
|
||||
for rows.Next() {
|
||||
item, err := scanRoleSkillBinding(rows)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out = append(out, item)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, fmt.Errorf("iterate role skill bindings: %w", err)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func getRoleTx(ctx context.Context, tx *sql.Tx, name string) (role.Definition, error) {
|
||||
row := tx.QueryRowContext(ctx, `
|
||||
SELECT name, title, executor_kind, description, is_enabled, is_builtin, sort_order, created_at, updated_at
|
||||
FROM roles
|
||||
WHERE name = ?
|
||||
`, name)
|
||||
return scanRole(row)
|
||||
}
|
||||
|
||||
func getRolePromptTx(ctx context.Context, tx *sql.Tx, roleName, workspaceID string, kind role.PromptKind) (role.Prompt, error) {
|
||||
var row *sql.Row
|
||||
if workspaceID == "" {
|
||||
row = tx.QueryRowContext(ctx, `
|
||||
SELECT id, role_name, workspace_id, prompt_kind, content_markdown, version, updated_by, created_at, updated_at
|
||||
FROM role_prompts
|
||||
WHERE role_name = ? AND prompt_kind = ? AND workspace_id IS NULL
|
||||
`, roleName, string(kind))
|
||||
} else {
|
||||
row = tx.QueryRowContext(ctx, `
|
||||
SELECT id, role_name, workspace_id, prompt_kind, content_markdown, version, updated_by, created_at, updated_at
|
||||
FROM role_prompts
|
||||
WHERE role_name = ? AND prompt_kind = ? AND workspace_id = ?
|
||||
`, roleName, string(kind), workspaceID)
|
||||
}
|
||||
return scanRolePrompt(row)
|
||||
}
|
||||
|
||||
func getRoleConfigTx(ctx context.Context, tx *sql.Tx, roleName string) (role.Config, error) {
|
||||
row := tx.QueryRowContext(ctx, `
|
||||
SELECT name, config_toml, auth_json
|
||||
FROM roles
|
||||
WHERE name = ?
|
||||
`, roleName)
|
||||
return scanRoleConfig(row)
|
||||
}
|
||||
|
||||
func getRoleSkillBindingTx(ctx context.Context, tx *sql.Tx, roleName, workspaceID, skillID string) (role.SkillBinding, error) {
|
||||
var row *sql.Row
|
||||
if workspaceID == "" {
|
||||
row = tx.QueryRowContext(ctx, `
|
||||
SELECT id, role_name, workspace_id, skill_id, is_enabled, sort_order, config_json, version, updated_by, created_at, updated_at
|
||||
FROM role_skill_bindings
|
||||
WHERE role_name = ? AND skill_id = ? AND workspace_id IS NULL
|
||||
`, roleName, skillID)
|
||||
} else {
|
||||
row = tx.QueryRowContext(ctx, `
|
||||
SELECT id, role_name, workspace_id, skill_id, is_enabled, sort_order, config_json, version, updated_by, created_at, updated_at
|
||||
FROM role_skill_bindings
|
||||
WHERE role_name = ? AND skill_id = ? AND workspace_id = ?
|
||||
`, roleName, skillID, workspaceID)
|
||||
}
|
||||
return scanRoleSkillBinding(row)
|
||||
}
|
||||
|
||||
func scanRole(s scanner) (role.Definition, error) {
|
||||
var item role.Definition
|
||||
var executorKind string
|
||||
if err := s.Scan(&item.Name, &item.Title, &executorKind, &item.Description, &item.IsEnabled, &item.IsBuiltin, &item.SortOrder, &item.CreatedAt, &item.UpdatedAt); err != nil {
|
||||
return role.Definition{}, err
|
||||
}
|
||||
item.ExecutorKind = role.ExecutorKind(executorKind)
|
||||
item = role.NormalizeDefinition(item)
|
||||
return item, nil
|
||||
}
|
||||
|
||||
func scanRolePrompt(s scanner) (role.Prompt, error) {
|
||||
var item role.Prompt
|
||||
var workspaceID sql.NullString
|
||||
var kind string
|
||||
if err := s.Scan(&item.ID, &item.RoleName, &workspaceID, &kind, &item.ContentMarkdown, &item.Version, &item.UpdatedBy, &item.CreatedAt, &item.UpdatedAt); err != nil {
|
||||
return role.Prompt{}, err
|
||||
}
|
||||
if workspaceID.Valid {
|
||||
item.WorkspaceID = workspaceID.String
|
||||
}
|
||||
item.PromptKind = role.PromptKind(kind)
|
||||
return item, nil
|
||||
}
|
||||
|
||||
func scanRoleConfig(s scanner) (role.Config, error) {
|
||||
var item role.Config
|
||||
if err := s.Scan(&item.RoleName, &item.ConfigTOML, &item.AuthJSON); err != nil {
|
||||
return role.Config{}, err
|
||||
}
|
||||
return role.NormalizeConfig(item), nil
|
||||
}
|
||||
|
||||
func scanRoleSkillBinding(s scanner) (role.SkillBinding, error) {
|
||||
var item role.SkillBinding
|
||||
var workspaceID sql.NullString
|
||||
var configJSON string
|
||||
if err := s.Scan(&item.ID, &item.RoleName, &workspaceID, &item.SkillID, &item.IsEnabled, &item.SortOrder, &configJSON, &item.Version, &item.UpdatedBy, &item.CreatedAt, &item.UpdatedAt); err != nil {
|
||||
return role.SkillBinding{}, err
|
||||
}
|
||||
if workspaceID.Valid {
|
||||
item.WorkspaceID = workspaceID.String
|
||||
}
|
||||
if err := unmarshalJSON(configJSON, &item.Config); err != nil {
|
||||
return role.SkillBinding{}, fmt.Errorf("decode role skill binding config: %w", err)
|
||||
}
|
||||
return item, nil
|
||||
}
|
||||
Reference in New Issue
Block a user