123 lines
4.0 KiB
Go
123 lines
4.0 KiB
Go
package indexable
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/tech/sendico/pkg/db/repository"
|
|
"github.com/tech/sendico/pkg/db/repository/builder"
|
|
"github.com/tech/sendico/pkg/db/storable"
|
|
"github.com/tech/sendico/pkg/mlogger"
|
|
"github.com/tech/sendico/pkg/model"
|
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
// IndexableDB implements db.IndexableDB interface with generic support
|
|
type IndexableDB[T storable.Storable] struct {
|
|
repo repository.Repository
|
|
logger mlogger.Logger
|
|
createEmpty func() T
|
|
getIndexable func(T) *model.Indexable
|
|
}
|
|
|
|
// NewIndexableDB creates a new IndexableDB instance
|
|
func NewIndexableDB[T storable.Storable](
|
|
repo repository.Repository,
|
|
logger mlogger.Logger,
|
|
createEmpty func() T,
|
|
getIndexable func(T) *model.Indexable,
|
|
) *IndexableDB[T] {
|
|
return &IndexableDB[T]{
|
|
repo: repo,
|
|
logger: logger,
|
|
createEmpty: createEmpty,
|
|
getIndexable: getIndexable,
|
|
}
|
|
}
|
|
|
|
// Reorder implements the db.IndexableDB interface with single filter parameter
|
|
func (db *IndexableDB[T]) Reorder(ctx context.Context, objectRef primitive.ObjectID, newIndex int, filter builder.Query) error {
|
|
// Get current object to find its index
|
|
obj := db.createEmpty()
|
|
err := db.repo.Get(ctx, objectRef, obj)
|
|
if err != nil {
|
|
db.logger.Error("Failed to get object for reordering",
|
|
zap.Error(err),
|
|
zap.String("object_ref", objectRef.Hex()),
|
|
zap.Int("new_index", newIndex))
|
|
return err
|
|
}
|
|
|
|
// Extract index from the object
|
|
indexable := db.getIndexable(obj)
|
|
currentIndex := indexable.Index
|
|
if currentIndex == newIndex {
|
|
db.logger.Debug("No reordering needed - same index",
|
|
zap.String("object_ref", objectRef.Hex()),
|
|
zap.Int("current_index", currentIndex),
|
|
zap.Int("new_index", newIndex))
|
|
return nil // No change needed
|
|
}
|
|
|
|
// Simple reordering logic
|
|
if currentIndex < newIndex {
|
|
// Moving down: shift items between currentIndex+1 and newIndex up by -1
|
|
patch := repository.Patch().Inc(repository.IndexField(), -1)
|
|
reorderFilter := filter.
|
|
And(repository.IndexOpFilter(currentIndex+1, builder.Gte)).
|
|
And(repository.IndexOpFilter(newIndex, builder.Lte))
|
|
|
|
updatedCount, err := db.repo.PatchMany(ctx, reorderFilter, patch)
|
|
if err != nil {
|
|
db.logger.Error("Failed to shift objects during reordering (moving down)",
|
|
zap.Error(err),
|
|
zap.String("object_ref", objectRef.Hex()),
|
|
zap.Int("current_index", currentIndex),
|
|
zap.Int("new_index", newIndex),
|
|
zap.Int("updated_count", updatedCount))
|
|
return err
|
|
}
|
|
db.logger.Debug("Successfully shifted objects (moving down)",
|
|
zap.String("object_ref", objectRef.Hex()),
|
|
zap.Int("updated_count", updatedCount))
|
|
} else {
|
|
// Moving up: shift items between newIndex and currentIndex-1 down by +1
|
|
patch := repository.Patch().Inc(repository.IndexField(), 1)
|
|
reorderFilter := filter.
|
|
And(repository.IndexOpFilter(newIndex, builder.Gte)).
|
|
And(repository.IndexOpFilter(currentIndex-1, builder.Lte))
|
|
|
|
updatedCount, err := db.repo.PatchMany(ctx, reorderFilter, patch)
|
|
if err != nil {
|
|
db.logger.Error("Failed to shift objects during reordering (moving up)",
|
|
zap.Error(err),
|
|
zap.String("object_ref", objectRef.Hex()),
|
|
zap.Int("current_index", currentIndex),
|
|
zap.Int("new_index", newIndex),
|
|
zap.Int("updated_count", updatedCount))
|
|
return err
|
|
}
|
|
db.logger.Debug("Successfully shifted objects (moving up)",
|
|
zap.String("object_ref", objectRef.Hex()),
|
|
zap.Int("updated_count", updatedCount))
|
|
}
|
|
|
|
// Update the target object to new index
|
|
patch := repository.Patch().Set(repository.IndexField(), newIndex)
|
|
err = db.repo.Patch(ctx, objectRef, patch)
|
|
if err != nil {
|
|
db.logger.Error("Failed to update target object index",
|
|
zap.Error(err),
|
|
zap.String("object_ref", objectRef.Hex()),
|
|
zap.Int("current_index", currentIndex),
|
|
zap.Int("new_index", newIndex))
|
|
return err
|
|
}
|
|
|
|
db.logger.Info("Successfully reordered object",
|
|
zap.String("object_ref", objectRef.Hex()),
|
|
zap.Int("old_index", currentIndex),
|
|
zap.Int("new_index", newIndex))
|
|
return nil
|
|
}
|