5.1 KiB
5.1 KiB
Indexable Usage Guide
Generic Implementation for Any Indexable Struct
The implementation is now generic and supports any struct that embeds model.Indexable!
- Interface:
api/pkg/db/indexable.go- defines the contract - Implementation:
api/pkg/db/internal/mongo/indexable/- generic implementation - Factory:
api/pkg/db/project_indexable.go- convenient factory for projects
Usage
1. Using the Generic Implementation Directly
import "github.com/tech/sendico/pkg/db/internal/mongo/indexable"
// For any type that embeds model.Indexable, define helper functions:
createEmpty := func() *YourType {
return &YourType{}
}
getIndexable := func(obj *YourType) *model.Indexable {
return &obj.Indexable
}
// Create generic IndexableDB
indexableDB := indexable.NewIndexableDB(repo, logger, createEmpty, getIndexable)
// Use with single filter parameter
err := indexableDB.Reorder(ctx, objectID, newIndex, filter)
2. Using the Project Factory (Recommended for Projects)
import "github.com/tech/sendico/pkg/db"
// Create project indexable DB (automatically applies org filter)
projectDB := db.NewProjectIndexableDB(repo, logger, organizationRef)
// Reorder project (org filter applied automatically)
err := projectDB.Reorder(ctx, projectID, newIndex, repository.Query())
// Reorder with additional filters (combined with org filter)
additionalFilter := repository.Query().Comparison(repository.Field("state"), builder.Eq, "active")
err := projectDB.Reorder(ctx, projectID, newIndex, additionalFilter)
Examples for Different Types
Project IndexableDB
createEmpty := func() *model.Project {
return &model.Project{}
}
getIndexable := func(p *model.Project) *model.Indexable {
return &p.Indexable
}
projectDB := indexable.NewIndexableDB(repo, logger, createEmpty, getIndexable)
orgFilter := repository.OrgFilter(organizationRef)
projectDB.Reorder(ctx, projectID, 2, orgFilter)
Status IndexableDB
createEmpty := func() *model.Status {
return &model.Status{}
}
getIndexable := func(s *model.Status) *model.Indexable {
return &s.Indexable
}
statusDB := indexable.NewIndexableDB(repo, logger, createEmpty, getIndexable)
projectFilter := repository.Query().Comparison(repository.Field("projectRef"), builder.Eq, projectRef)
statusDB.Reorder(ctx, statusID, 1, projectFilter)
Task IndexableDB
createEmpty := func() *model.Task {
return &model.Task{}
}
getIndexable := func(t *model.Task) *model.Indexable {
return &t.Indexable
}
taskDB := indexable.NewIndexableDB(repo, logger, createEmpty, getIndexable)
statusFilter := repository.Query().Comparison(repository.Field("statusRef"), builder.Eq, statusRef)
taskDB.Reorder(ctx, taskID, 3, statusFilter)
Priority IndexableDB
createEmpty := func() *model.Priority {
return &model.Priority{}
}
getIndexable := func(p *model.Priority) *model.Indexable {
return &p.Indexable
}
priorityDB := indexable.NewIndexableDB(repo, logger, createEmpty, getIndexable)
orgFilter := repository.OrgFilter(organizationRef)
priorityDB.Reorder(ctx, priorityID, 0, orgFilter)
Global Reordering (No Filter)
createEmpty := func() *model.Project {
return &model.Project{}
}
getIndexable := func(p *model.Project) *model.Indexable {
return &p.Indexable
}
globalDB := indexable.NewIndexableDB(repo, logger, createEmpty, getIndexable)
// Reorders all items globally (empty filter)
globalDB.Reorder(ctx, objectID, 5, repository.Query())
Key Features
✅ Generic Support
- Works with any struct that embeds
model.Indexable - Type-safe with compile-time checking
- No hardcoded types
✅ Single Filter Parameter
- Simple: Single
builder.Queryparameter instead of variadicinterface{} - Flexible: Can incorporate any combination of filters
- Type-safe: No runtime type assertions needed
✅ Clean Architecture
- Interface separated from implementation
- Generic implementation in internal package
- Easy-to-use factories for common types
How It Works
Generic Algorithm
- Get current index using type-specific helper function
- If no change needed → return early
- Apply filter to scope affected items
- Shift affected items using
PatchManywith$inc - Update target object using
Patchwith$set
Type-Safe Implementation
type IndexableDB[T storable.Storable] struct {
repo repository.Repository
logger mlogger.Logger
createEmpty func() T
getIndexable func(T) *model.Indexable
}
// Single filter parameter - clean and simple
func (db *IndexableDB[T]) Reorder(ctx context.Context, objectRef primitive.ObjectID, newIndex int, filter builder.Query) error
Benefits
✅ Generic - Works with any Indexable struct
✅ Type Safe - Compile-time type checking
✅ Simple - Single filter parameter instead of variadic interface{}
✅ Efficient - Uses patches, not full updates
✅ Clean - Interface separated from implementation
That's it! Generic, type-safe, and simple reordering for any Indexable struct with a single filter parameter.