refactor(store,tools): migrate IDs from UUID to bigserial int64
Some checks failed
CI / build-and-test (push) Failing after -31m12s
Some checks failed
CI / build-and-test (push) Failing after -31m12s
All internal entity lookups now use bigserial primary keys (int64) while GUIDs are retained for external/public identification. Updated store functions (TouchProject, UpdateThoughtMetadata, AddThoughtAttachment) to query by id instead of guid, added GetThoughtByID, changed semanticSearch and all tool helpers to use *int64 project IDs, and updated retry/backfill workers to use int64 thought IDs throughout.
This commit is contained in:
@@ -33,12 +33,12 @@ func (db *DB) InsertThought(ctx context.Context, thought thoughttypes.Thought, e
|
||||
row := tx.QueryRow(ctx, `
|
||||
insert into thoughts (content, metadata, project_id)
|
||||
values ($1, $2::jsonb, $3)
|
||||
returning guid, created_at, updated_at
|
||||
returning id, guid, created_at, updated_at
|
||||
`, thought.Content, metadata, thought.ProjectID)
|
||||
|
||||
created := thought
|
||||
created.Embedding = nil
|
||||
if err := row.Scan(&created.ID, &created.CreatedAt, &created.UpdatedAt); err != nil {
|
||||
if err := row.Scan(&created.ID, &created.GUID, &created.CreatedAt, &created.UpdatedAt); err != nil {
|
||||
return thoughttypes.Thought{}, fmt.Errorf("insert thought: %w", err)
|
||||
}
|
||||
|
||||
@@ -132,7 +132,7 @@ func (db *DB) ListThoughts(ctx context.Context, filter thoughttypes.ListFilter)
|
||||
}
|
||||
|
||||
query := `
|
||||
select guid, content, metadata, project_id, archived_at, created_at, updated_at
|
||||
select id, guid, content, metadata, project_id, archived_at, created_at, updated_at
|
||||
from thoughts
|
||||
`
|
||||
if len(conditions) > 0 {
|
||||
@@ -151,7 +151,7 @@ func (db *DB) ListThoughts(ctx context.Context, filter thoughttypes.ListFilter)
|
||||
thoughts := make([]thoughttypes.Thought, 0, filter.Limit)
|
||||
for rows.Next() {
|
||||
var model generatedmodels.ModelPublicThoughts
|
||||
if err := rows.Scan(&model.GUID, &model.Content, &model.Metadata, &model.ProjectID, &model.ArchivedAt, &model.CreatedAt, &model.UpdatedAt); err != nil {
|
||||
if err := rows.Scan(&model.ID, &model.GUID, &model.Content, &model.Metadata, &model.ProjectID, &model.ArchivedAt, &model.CreatedAt, &model.UpdatedAt); err != nil {
|
||||
return nil, fmt.Errorf("scan listed thought: %w", err)
|
||||
}
|
||||
thought, err := thoughtFromModel(model)
|
||||
@@ -218,13 +218,13 @@ func (db *DB) Stats(ctx context.Context) (thoughttypes.ThoughtStats, error) {
|
||||
|
||||
func (db *DB) GetThought(ctx context.Context, id uuid.UUID) (thoughttypes.Thought, error) {
|
||||
row := db.pool.QueryRow(ctx, `
|
||||
select guid, content, metadata, project_id, archived_at, created_at, updated_at
|
||||
select id, guid, content, metadata, project_id, archived_at, created_at, updated_at
|
||||
from thoughts
|
||||
where guid = $1
|
||||
`, id)
|
||||
|
||||
var model generatedmodels.ModelPublicThoughts
|
||||
if err := row.Scan(&model.GUID, &model.Content, &model.Metadata, &model.ProjectID, &model.ArchivedAt, &model.CreatedAt, &model.UpdatedAt); err != nil {
|
||||
if err := row.Scan(&model.ID, &model.GUID, &model.Content, &model.Metadata, &model.ProjectID, &model.ArchivedAt, &model.CreatedAt, &model.UpdatedAt); err != nil {
|
||||
if err == pgx.ErrNoRows {
|
||||
return thoughttypes.Thought{}, err
|
||||
}
|
||||
@@ -239,7 +239,30 @@ func (db *DB) GetThought(ctx context.Context, id uuid.UUID) (thoughttypes.Though
|
||||
return thought, nil
|
||||
}
|
||||
|
||||
func (db *DB) UpdateThought(ctx context.Context, id uuid.UUID, content string, embedding []float32, embeddingModel string, metadata thoughttypes.ThoughtMetadata, projectID *uuid.UUID) (thoughttypes.Thought, error) {
|
||||
func (db *DB) GetThoughtByID(ctx context.Context, id int64) (thoughttypes.Thought, error) {
|
||||
row := db.pool.QueryRow(ctx, `
|
||||
select id, guid, content, metadata, project_id, archived_at, created_at, updated_at
|
||||
from thoughts
|
||||
where id = $1
|
||||
`, id)
|
||||
|
||||
var model generatedmodels.ModelPublicThoughts
|
||||
if err := row.Scan(&model.ID, &model.GUID, &model.Content, &model.Metadata, &model.ProjectID, &model.ArchivedAt, &model.CreatedAt, &model.UpdatedAt); err != nil {
|
||||
if err == pgx.ErrNoRows {
|
||||
return thoughttypes.Thought{}, err
|
||||
}
|
||||
return thoughttypes.Thought{}, fmt.Errorf("get thought by id: %w", err)
|
||||
}
|
||||
|
||||
thought, err := thoughtFromModel(model)
|
||||
if err != nil {
|
||||
return thoughttypes.Thought{}, fmt.Errorf("map thought: %w", err)
|
||||
}
|
||||
|
||||
return thought, nil
|
||||
}
|
||||
|
||||
func (db *DB) UpdateThought(ctx context.Context, id uuid.UUID, content string, embedding []float32, embeddingModel string, metadata thoughttypes.ThoughtMetadata, projectID *int64) (thoughttypes.Thought, error) {
|
||||
metadataBytes, err := json.Marshal(metadata)
|
||||
if err != nil {
|
||||
return thoughttypes.Thought{}, fmt.Errorf("marshal updated metadata: %w", err)
|
||||
@@ -271,7 +294,7 @@ func (db *DB) UpdateThought(ctx context.Context, id uuid.UUID, content string, e
|
||||
if len(embedding) > 0 && embeddingModel != "" {
|
||||
if _, err := tx.Exec(ctx, `
|
||||
insert into embeddings (thought_id, model, dim, embedding)
|
||||
values ($1, $2, $3, $4)
|
||||
select id, $2, $3, $4 from thoughts where guid = $1
|
||||
on conflict (thought_id, model) do update
|
||||
set embedding = excluded.embedding,
|
||||
dim = excluded.dim,
|
||||
@@ -288,7 +311,7 @@ func (db *DB) UpdateThought(ctx context.Context, id uuid.UUID, content string, e
|
||||
return db.GetThought(ctx, id)
|
||||
}
|
||||
|
||||
func (db *DB) UpdateThoughtMetadata(ctx context.Context, id uuid.UUID, metadata thoughttypes.ThoughtMetadata) (thoughttypes.Thought, error) {
|
||||
func (db *DB) UpdateThoughtMetadata(ctx context.Context, id int64, metadata thoughttypes.ThoughtMetadata) (thoughttypes.Thought, error) {
|
||||
metadataBytes, err := json.Marshal(metadata)
|
||||
if err != nil {
|
||||
return thoughttypes.Thought{}, fmt.Errorf("marshal updated metadata: %w", err)
|
||||
@@ -298,7 +321,7 @@ func (db *DB) UpdateThoughtMetadata(ctx context.Context, id uuid.UUID, metadata
|
||||
update thoughts
|
||||
set metadata = $2::jsonb,
|
||||
updated_at = now()
|
||||
where guid = $1
|
||||
where id = $1
|
||||
`, id, metadataBytes)
|
||||
if err != nil {
|
||||
return thoughttypes.Thought{}, fmt.Errorf("update thought metadata: %w", err)
|
||||
@@ -307,7 +330,7 @@ func (db *DB) UpdateThoughtMetadata(ctx context.Context, id uuid.UUID, metadata
|
||||
return thoughttypes.Thought{}, pgx.ErrNoRows
|
||||
}
|
||||
|
||||
return db.GetThought(ctx, id)
|
||||
return db.GetThoughtByID(ctx, id)
|
||||
}
|
||||
|
||||
func (db *DB) DeleteThought(ctx context.Context, id uuid.UUID) error {
|
||||
@@ -332,7 +355,7 @@ func (db *DB) ArchiveThought(ctx context.Context, id uuid.UUID) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *DB) RecentThoughts(ctx context.Context, projectID *uuid.UUID, limit int, days int) ([]thoughttypes.Thought, error) {
|
||||
func (db *DB) RecentThoughts(ctx context.Context, projectID *int64, limit int, days int) ([]thoughttypes.Thought, error) {
|
||||
filter := thoughttypes.ListFilter{
|
||||
Limit: limit,
|
||||
ProjectID: projectID,
|
||||
@@ -342,7 +365,7 @@ func (db *DB) RecentThoughts(ctx context.Context, projectID *uuid.UUID, limit in
|
||||
return db.ListThoughts(ctx, filter)
|
||||
}
|
||||
|
||||
func (db *DB) ListThoughtsPendingMetadataRetry(ctx context.Context, limit int, projectID *uuid.UUID, includeArchived bool, olderThanDays int) ([]thoughttypes.Thought, error) {
|
||||
func (db *DB) ListThoughtsPendingMetadataRetry(ctx context.Context, limit int, projectID *int64, includeArchived bool, olderThanDays int) ([]thoughttypes.Thought, error) {
|
||||
args := make([]any, 0, 4)
|
||||
conditions := []string{
|
||||
"(metadata->>'metadata_status' = 'pending' or metadata->>'metadata_status' = 'failed')",
|
||||
@@ -361,7 +384,7 @@ func (db *DB) ListThoughtsPendingMetadataRetry(ctx context.Context, limit int, p
|
||||
}
|
||||
|
||||
query := `
|
||||
select guid, content, metadata, project_id, archived_at, created_at, updated_at
|
||||
select id, guid, content, metadata, project_id, archived_at, created_at, updated_at
|
||||
from thoughts
|
||||
where ` + strings.Join(conditions, " and ")
|
||||
|
||||
@@ -376,12 +399,12 @@ func (db *DB) ListThoughtsPendingMetadataRetry(ctx context.Context, limit int, p
|
||||
|
||||
thoughts := make([]thoughttypes.Thought, 0, limit)
|
||||
for rows.Next() {
|
||||
var thought thoughttypes.Thought
|
||||
var metadataBytes []byte
|
||||
if err := rows.Scan(&thought.ID, &thought.Content, &metadataBytes, &thought.ProjectID, &thought.ArchivedAt, &thought.CreatedAt, &thought.UpdatedAt); err != nil {
|
||||
var model generatedmodels.ModelPublicThoughts
|
||||
if err := rows.Scan(&model.ID, &model.GUID, &model.Content, &model.Metadata, &model.ProjectID, &model.ArchivedAt, &model.CreatedAt, &model.UpdatedAt); err != nil {
|
||||
return nil, fmt.Errorf("scan pending metadata retry thought: %w", err)
|
||||
}
|
||||
if err := json.Unmarshal(metadataBytes, &thought.Metadata); err != nil {
|
||||
thought, err := thoughtFromModel(model)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("decode pending metadata retry thought: %w", err)
|
||||
}
|
||||
thoughts = append(thoughts, thought)
|
||||
@@ -394,7 +417,7 @@ func (db *DB) ListThoughtsPendingMetadataRetry(ctx context.Context, limit int, p
|
||||
return thoughts, nil
|
||||
}
|
||||
|
||||
func (db *DB) SearchSimilarThoughts(ctx context.Context, embedding []float32, embeddingModel string, threshold float64, limit int, projectID *uuid.UUID, excludeID *uuid.UUID) ([]thoughttypes.SearchResult, error) {
|
||||
func (db *DB) SearchSimilarThoughts(ctx context.Context, embedding []float32, embeddingModel string, threshold float64, limit int, projectID *int64, excludeID *uuid.UUID) ([]thoughttypes.SearchResult, error) {
|
||||
args := []any{pgvector.NewVector(embedding), threshold, embeddingModel}
|
||||
conditions := []string{
|
||||
"t.archived_at is null",
|
||||
@@ -412,9 +435,9 @@ func (db *DB) SearchSimilarThoughts(ctx context.Context, embedding []float32, em
|
||||
args = append(args, limit)
|
||||
|
||||
query := `
|
||||
select t.guid, t.content, t.metadata, 1 - (e.embedding <=> $1) as similarity, t.created_at
|
||||
select t.id, t.content, t.metadata, 1 - (e.embedding <=> $1) as similarity, t.created_at
|
||||
from thoughts t
|
||||
join embeddings e on e.thought_id = t.guid
|
||||
join embeddings e on e.thought_id = t.id
|
||||
where ` + strings.Join(conditions, " and ") + fmt.Sprintf(`
|
||||
order by e.embedding <=> $1
|
||||
limit $%d`, len(args))
|
||||
@@ -443,7 +466,7 @@ func (db *DB) SearchSimilarThoughts(ctx context.Context, embedding []float32, em
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func (db *DB) HasEmbeddingsForModel(ctx context.Context, model string, projectID *uuid.UUID) (bool, error) {
|
||||
func (db *DB) HasEmbeddingsForModel(ctx context.Context, model string, projectID *int64) (bool, error) {
|
||||
args := []any{model}
|
||||
conditions := []string{
|
||||
"e.model = $1",
|
||||
@@ -454,7 +477,7 @@ func (db *DB) HasEmbeddingsForModel(ctx context.Context, model string, projectID
|
||||
conditions = append(conditions, fmt.Sprintf("t.project_id = $%d", len(args)))
|
||||
}
|
||||
|
||||
query := `select exists(select 1 from embeddings e join thoughts t on t.guid = e.thought_id where ` +
|
||||
query := `select exists(select 1 from embeddings e join thoughts t on t.id = e.thought_id where ` +
|
||||
strings.Join(conditions, " and ") + `)`
|
||||
|
||||
var exists bool
|
||||
@@ -464,7 +487,7 @@ func (db *DB) HasEmbeddingsForModel(ctx context.Context, model string, projectID
|
||||
return exists, nil
|
||||
}
|
||||
|
||||
func (db *DB) ListThoughtsMissingEmbedding(ctx context.Context, model string, limit int, projectID *uuid.UUID, includeArchived bool, olderThanDays int) ([]thoughttypes.Thought, error) {
|
||||
func (db *DB) ListThoughtsMissingEmbedding(ctx context.Context, model string, limit int, projectID *int64, includeArchived bool, olderThanDays int) ([]thoughttypes.Thought, error) {
|
||||
args := []any{model}
|
||||
conditions := []string{"e.id is null"}
|
||||
|
||||
@@ -482,9 +505,9 @@ func (db *DB) ListThoughtsMissingEmbedding(ctx context.Context, model string, li
|
||||
args = append(args, limit)
|
||||
|
||||
query := `
|
||||
select t.guid, t.content, t.metadata, t.project_id, t.archived_at, t.created_at, t.updated_at
|
||||
select t.id, t.guid, t.content, t.metadata, t.project_id, t.archived_at, t.created_at, t.updated_at
|
||||
from thoughts t
|
||||
left join embeddings e on e.thought_id = t.guid and e.model = $1
|
||||
left join embeddings e on e.thought_id = t.id and e.model = $1
|
||||
where ` + strings.Join(conditions, " and ") + `
|
||||
order by t.created_at asc
|
||||
limit $` + fmt.Sprintf("%d", len(args))
|
||||
@@ -497,12 +520,12 @@ func (db *DB) ListThoughtsMissingEmbedding(ctx context.Context, model string, li
|
||||
|
||||
thoughts := make([]thoughttypes.Thought, 0, limit)
|
||||
for rows.Next() {
|
||||
var thought thoughttypes.Thought
|
||||
var metadataBytes []byte
|
||||
if err := rows.Scan(&thought.ID, &thought.Content, &metadataBytes, &thought.ProjectID, &thought.ArchivedAt, &thought.CreatedAt, &thought.UpdatedAt); err != nil {
|
||||
var model generatedmodels.ModelPublicThoughts
|
||||
if err := rows.Scan(&model.ID, &model.GUID, &model.Content, &model.Metadata, &model.ProjectID, &model.ArchivedAt, &model.CreatedAt, &model.UpdatedAt); err != nil {
|
||||
return nil, fmt.Errorf("scan missing-embedding thought: %w", err)
|
||||
}
|
||||
if err := json.Unmarshal(metadataBytes, &thought.Metadata); err != nil {
|
||||
thought, err := thoughtFromModel(model)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("decode missing-embedding metadata: %w", err)
|
||||
}
|
||||
thoughts = append(thoughts, thought)
|
||||
@@ -513,7 +536,7 @@ func (db *DB) ListThoughtsMissingEmbedding(ctx context.Context, model string, li
|
||||
return thoughts, nil
|
||||
}
|
||||
|
||||
func (db *DB) ListThoughtsForMetadataReparse(ctx context.Context, limit int, projectID *uuid.UUID, includeArchived bool, olderThanDays int) ([]thoughttypes.Thought, error) {
|
||||
func (db *DB) ListThoughtsForMetadataReparse(ctx context.Context, limit int, projectID *int64, includeArchived bool, olderThanDays int) ([]thoughttypes.Thought, error) {
|
||||
args := make([]any, 0, 3)
|
||||
conditions := make([]string, 0, 4)
|
||||
|
||||
@@ -531,7 +554,7 @@ func (db *DB) ListThoughtsForMetadataReparse(ctx context.Context, limit int, pro
|
||||
args = append(args, limit)
|
||||
|
||||
query := `
|
||||
select guid, content, metadata, project_id, archived_at, created_at, updated_at
|
||||
select id, guid, content, metadata, project_id, archived_at, created_at, updated_at
|
||||
from thoughts
|
||||
`
|
||||
if len(conditions) > 0 {
|
||||
@@ -547,12 +570,12 @@ func (db *DB) ListThoughtsForMetadataReparse(ctx context.Context, limit int, pro
|
||||
|
||||
thoughts := make([]thoughttypes.Thought, 0, limit)
|
||||
for rows.Next() {
|
||||
var thought thoughttypes.Thought
|
||||
var metadataBytes []byte
|
||||
if err := rows.Scan(&thought.ID, &thought.Content, &metadataBytes, &thought.ProjectID, &thought.ArchivedAt, &thought.CreatedAt, &thought.UpdatedAt); err != nil {
|
||||
var model generatedmodels.ModelPublicThoughts
|
||||
if err := rows.Scan(&model.ID, &model.GUID, &model.Content, &model.Metadata, &model.ProjectID, &model.ArchivedAt, &model.CreatedAt, &model.UpdatedAt); err != nil {
|
||||
return nil, fmt.Errorf("scan metadata-reparse thought: %w", err)
|
||||
}
|
||||
if err := json.Unmarshal(metadataBytes, &thought.Metadata); err != nil {
|
||||
thought, err := thoughtFromModel(model)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("decode metadata-reparse thought metadata: %w", err)
|
||||
}
|
||||
thoughts = append(thoughts, thought)
|
||||
@@ -564,7 +587,7 @@ func (db *DB) ListThoughtsForMetadataReparse(ctx context.Context, limit int, pro
|
||||
return thoughts, nil
|
||||
}
|
||||
|
||||
func (db *DB) UpsertEmbedding(ctx context.Context, thoughtID uuid.UUID, model string, embedding []float32) error {
|
||||
func (db *DB) UpsertEmbedding(ctx context.Context, thoughtID int64, model string, embedding []float32) error {
|
||||
_, err := db.pool.Exec(ctx, `
|
||||
insert into embeddings (thought_id, model, dim, embedding)
|
||||
values ($1, $2, $3, $4)
|
||||
@@ -579,7 +602,7 @@ func (db *DB) UpsertEmbedding(ctx context.Context, thoughtID uuid.UUID, model st
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *DB) SearchThoughtsText(ctx context.Context, query string, limit int, projectID *uuid.UUID, excludeID *uuid.UUID) ([]thoughttypes.SearchResult, error) {
|
||||
func (db *DB) SearchThoughtsText(ctx context.Context, query string, limit int, projectID *int64, excludeID *uuid.UUID) ([]thoughttypes.SearchResult, error) {
|
||||
args := []any{query}
|
||||
conditions := []string{
|
||||
"t.archived_at is null",
|
||||
@@ -596,11 +619,11 @@ func (db *DB) SearchThoughtsText(ctx context.Context, query string, limit int, p
|
||||
args = append(args, limit)
|
||||
|
||||
q := `
|
||||
select t.guid, t.content, t.metadata,
|
||||
select t.id, t.content, t.metadata,
|
||||
ts_rank_cd(to_tsvector('simple', t.content) || to_tsvector('simple', coalesce(p.name, '')), websearch_to_tsquery('simple', $1)) as similarity,
|
||||
t.created_at
|
||||
from thoughts t
|
||||
left join projects p on t.project_id = p.guid
|
||||
left join projects p on t.project_id = p.id
|
||||
where ` + strings.Join(conditions, " and ") + `
|
||||
order by similarity desc
|
||||
limit $` + fmt.Sprintf("%d", len(args))
|
||||
|
||||
Reference in New Issue
Block a user