212 lines
5.4 KiB
Go
212 lines
5.4 KiB
Go
package collection
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"codeberg.org/mapleopentech/monorepo/native/desktop/maplefile/pkg/storage"
|
|
"codeberg.org/mapleopentech/monorepo/native/desktop/maplefile/internal/domain/collection"
|
|
)
|
|
|
|
const (
|
|
collectionKeyPrefix = "collection:"
|
|
parentCollIndex = "parent_collection_index:"
|
|
rootCollIndex = "root_collection_index:"
|
|
)
|
|
|
|
type repository struct {
|
|
storage storage.Storage
|
|
}
|
|
|
|
// ProvideRepository creates a new collection repository for Wire
|
|
func ProvideRepository(storage storage.Storage) collection.Repository {
|
|
return &repository{storage: storage}
|
|
}
|
|
|
|
func (r *repository) Create(c *collection.Collection) error {
|
|
return r.save(c)
|
|
}
|
|
|
|
func (r *repository) Get(id string) (*collection.Collection, error) {
|
|
key := collectionKeyPrefix + id
|
|
data, err := r.storage.Get(key)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get collection: %w", err)
|
|
}
|
|
if data == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
var c collection.Collection
|
|
if err := json.Unmarshal(data, &c); err != nil {
|
|
return nil, fmt.Errorf("failed to unmarshal collection: %w", err)
|
|
}
|
|
|
|
return &c, nil
|
|
}
|
|
|
|
func (r *repository) Update(c *collection.Collection) error {
|
|
// Get existing collection to clean up old indexes if parent changed
|
|
existing, err := r.Get(c.ID)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get existing collection: %w", err)
|
|
}
|
|
if existing != nil && existing.ParentID != c.ParentID {
|
|
// Clean up old parent index
|
|
if existing.ParentID == "" {
|
|
oldRootKey := rootCollIndex + existing.ID
|
|
_ = r.storage.Delete(oldRootKey)
|
|
} else {
|
|
oldParentKey := parentCollIndex + existing.ParentID + ":" + existing.ID
|
|
_ = r.storage.Delete(oldParentKey)
|
|
}
|
|
}
|
|
|
|
return r.save(c)
|
|
}
|
|
|
|
func (r *repository) Delete(id string) error {
|
|
// Get collection first to remove indexes
|
|
c, err := r.Get(id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if c == nil {
|
|
return nil // Nothing to delete
|
|
}
|
|
|
|
// Delete parent index or root index
|
|
if c.ParentID == "" {
|
|
rootKey := rootCollIndex + id
|
|
if err := r.storage.Delete(rootKey); err != nil {
|
|
return fmt.Errorf("failed to delete root index: %w", err)
|
|
}
|
|
} else {
|
|
parentKey := parentCollIndex + c.ParentID + ":" + id
|
|
if err := r.storage.Delete(parentKey); err != nil {
|
|
return fmt.Errorf("failed to delete parent index: %w", err)
|
|
}
|
|
}
|
|
|
|
// Delete collection
|
|
collKey := collectionKeyPrefix + id
|
|
if err := r.storage.Delete(collKey); err != nil {
|
|
return fmt.Errorf("failed to delete collection: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (r *repository) List() ([]*collection.Collection, error) {
|
|
var collections []*collection.Collection
|
|
|
|
err := r.storage.Iterate(func(key, value []byte) error {
|
|
keyStr := string(key)
|
|
if strings.HasPrefix(keyStr, collectionKeyPrefix) {
|
|
var c collection.Collection
|
|
if err := json.Unmarshal(value, &c); err != nil {
|
|
return fmt.Errorf("failed to unmarshal collection: %w", err)
|
|
}
|
|
collections = append(collections, &c)
|
|
}
|
|
return nil
|
|
})
|
|
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to list collections: %w", err)
|
|
}
|
|
|
|
return collections, nil
|
|
}
|
|
|
|
func (r *repository) ListByParent(parentID string) ([]*collection.Collection, error) {
|
|
var collections []*collection.Collection
|
|
prefix := parentCollIndex + parentID + ":"
|
|
|
|
err := r.storage.Iterate(func(key, value []byte) error {
|
|
keyStr := string(key)
|
|
if strings.HasPrefix(keyStr, prefix) {
|
|
// Extract collection ID from index key
|
|
collID := strings.TrimPrefix(keyStr, prefix)
|
|
c, err := r.Get(collID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if c != nil {
|
|
collections = append(collections, c)
|
|
}
|
|
}
|
|
return nil
|
|
})
|
|
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to list collections by parent: %w", err)
|
|
}
|
|
|
|
return collections, nil
|
|
}
|
|
|
|
func (r *repository) ListRoot() ([]*collection.Collection, error) {
|
|
var collections []*collection.Collection
|
|
|
|
err := r.storage.Iterate(func(key, value []byte) error {
|
|
keyStr := string(key)
|
|
if strings.HasPrefix(keyStr, rootCollIndex) {
|
|
// Extract collection ID from index key
|
|
collID := strings.TrimPrefix(keyStr, rootCollIndex)
|
|
c, err := r.Get(collID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if c != nil {
|
|
collections = append(collections, c)
|
|
}
|
|
}
|
|
return nil
|
|
})
|
|
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to list root collections: %w", err)
|
|
}
|
|
|
|
return collections, nil
|
|
}
|
|
|
|
func (r *repository) Exists(id string) (bool, error) {
|
|
key := collectionKeyPrefix + id
|
|
data, err := r.storage.Get(key)
|
|
if err != nil {
|
|
return false, fmt.Errorf("failed to check collection existence: %w", err)
|
|
}
|
|
return data != nil, nil
|
|
}
|
|
|
|
// save persists the collection and maintains indexes
|
|
func (r *repository) save(c *collection.Collection) error {
|
|
data, err := json.Marshal(c)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to marshal collection: %w", err)
|
|
}
|
|
|
|
// Save collection by ID
|
|
collKey := collectionKeyPrefix + c.ID
|
|
if err := r.storage.Set(collKey, data); err != nil {
|
|
return fmt.Errorf("failed to save collection: %w", err)
|
|
}
|
|
|
|
// Create parent index (for ListByParent) or root index (for ListRoot)
|
|
if c.ParentID == "" {
|
|
rootKey := rootCollIndex + c.ID
|
|
if err := r.storage.Set(rootKey, []byte(c.ID)); err != nil {
|
|
return fmt.Errorf("failed to create root index: %w", err)
|
|
}
|
|
} else {
|
|
parentKey := parentCollIndex + c.ParentID + ":" + c.ID
|
|
if err := r.storage.Set(parentKey, []byte(c.ID)); err != nil {
|
|
return fmt.Errorf("failed to create parent index: %w", err)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|