Add versioning, update tool, and soft-delete
Schema: public_id + version columns with UNIQUE constraint, delete_timestamp for soft-delete. Tools: store_flashcard accepts optional public_id, update_flashcard creates a new version preserving history, delete_flashcard inserts a tombstone row and removes the Qdrant point. Qdrant: point ID is public_id (only latest version indexed).
This commit is contained in:
1 parent
726ab62c62
commit
e700a81c25
10 files changed
+352
-72
No files matched your search
@@ -8,17 +8,20 @@ import (
|
||||
"github.com/qdrant/go-client/qdrant"
|
||||
)
|
||||
|
||||
const collectionName = "knowledge"
|
||||
const collectionName = "flashcard"
|
||||
|
||||
type entry struct {
|
||||
ID int64 `json:"id"`
|
||||
Note string `json:"note"`
|
||||
Repos []string `json:"repos,omitempty"`
|
||||
Host string `json:"host,omitempty"`
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
User string `json:"user,omitempty"`
|
||||
Context string `json:"context,omitempty"`
|
||||
Created string `json:"created"`
|
||||
ID int64 `json:"_id"`
|
||||
PublicID int64 `json:"public_id"`
|
||||
Version int `json:"version"`
|
||||
Note string `json:"note"`
|
||||
Repos []string `json:"repos,omitempty"`
|
||||
Host string `json:"host,omitempty"`
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
User string `json:"user,omitempty"`
|
||||
Context string `json:"context,omitempty"`
|
||||
DeleteTimestamp string `json:"delete_timestamp,omitempty"`
|
||||
Created string `json:"created"`
|
||||
}
|
||||
|
||||
type searchResult struct {
|
||||
@@ -58,22 +61,24 @@ func (s *qdrantStore) ensureCollection(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *qdrantStore) index(ctx context.Context, id int64, note string) error {
|
||||
func (s *qdrantStore) index(ctx context.Context, id, publicID int64, version int, note string) error {
|
||||
vec, err := s.embedder.embedText(ctx, note)
|
||||
if err != nil {
|
||||
return fmt.Errorf("embed text: %w", err)
|
||||
}
|
||||
|
||||
payload := map[string]*qdrant.Value{
|
||||
"id": qdrant.NewValueString(strconv.FormatInt(id, 10)),
|
||||
"content": qdrant.NewValueString(note),
|
||||
"_id": qdrant.NewValueString(strconv.FormatInt(id, 10)),
|
||||
"public_id": qdrant.NewValueString(strconv.FormatInt(publicID, 10)),
|
||||
"version": qdrant.NewValueInt(int64(version)),
|
||||
"content": qdrant.NewValueString(note),
|
||||
}
|
||||
|
||||
_, err = s.client.Upsert(ctx, &qdrant.UpsertPoints{
|
||||
CollectionName: collectionName,
|
||||
Points: []*qdrant.PointStruct{
|
||||
{
|
||||
Id: qdrant.NewIDNum(uint64(id)),
|
||||
Id: qdrant.NewIDNum(uint64(publicID)),
|
||||
Vectors: qdrant.NewVectors(vec...),
|
||||
Payload: payload,
|
||||
},
|
||||
@@ -86,6 +91,21 @@ func (s *qdrantStore) index(ctx context.Context, id int64, note string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *qdrantStore) delete(ctx context.Context, publicID int64) error {
|
||||
wait := true
|
||||
_, err := s.client.Delete(ctx, &qdrant.DeletePoints{
|
||||
CollectionName: collectionName,
|
||||
Wait: &wait,
|
||||
Points: qdrant.NewPointsSelector(
|
||||
qdrant.NewIDNum(uint64(publicID)),
|
||||
),
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("delete point: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *qdrantStore) search(ctx context.Context, query string, limit uint64) ([]searchResult, error) {
|
||||
vec, err := s.embedder.embedText(ctx, query)
|
||||
if err != nil {
|
||||
@@ -113,7 +133,7 @@ func (s *qdrantStore) search(ctx context.Context, query string, limit uint64) ([
|
||||
}
|
||||
|
||||
if payload := pt.GetPayload(); payload != nil {
|
||||
if v, ok := payload["id"]; ok {
|
||||
if v, ok := payload["_id"]; ok {
|
||||
if n, err := strconv.ParseInt(v.GetStringValue(), 10, 64); err == nil {
|
||||
r.Entry.ID = n
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user