service backend
This commit is contained in:
174
api/pkg/db/internal/mongo/indexable/USAGE.md
Normal file
174
api/pkg/db/internal/mongo/indexable/USAGE.md
Normal file
@@ -0,0 +1,174 @@
|
||||
# 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
|
||||
|
||||
```go
|
||||
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)
|
||||
|
||||
```go
|
||||
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
|
||||
```go
|
||||
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
|
||||
```go
|
||||
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
|
||||
```go
|
||||
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
|
||||
```go
|
||||
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)
|
||||
```go
|
||||
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.Query` parameter instead of variadic `interface{}`
|
||||
- **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
|
||||
1. **Get current index** using type-specific helper function
|
||||
2. **If no change needed** → return early
|
||||
3. **Apply filter** to scope affected items
|
||||
4. **Shift affected items** using `PatchMany` with `$inc`
|
||||
5. **Update target object** using `Patch` with `$set`
|
||||
|
||||
### Type-Safe Implementation
|
||||
```go
|
||||
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.
|
||||
Reference in New Issue
Block a user