mirror of
https://github.com/kevin-DL/services.git
synced 2026-01-11 19:04:35 +00:00
176 lines
3.4 KiB
Go
176 lines
3.4 KiB
Go
// package model helps with data modelling on top of the store
|
|
package model
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
|
|
"github.com/micro/micro/v3/service/store"
|
|
)
|
|
|
|
var (
|
|
ErrNotFound = errors.New("not found")
|
|
ErrAlreadyExists = errors.New("already exists")
|
|
)
|
|
|
|
type Entity interface {
|
|
// The primary key
|
|
Key(ctx context.Context) string
|
|
// The index for the entity
|
|
Index(ctx context.Context) string
|
|
// The raw value of the entity
|
|
Value() interface{}
|
|
}
|
|
|
|
type Query struct {
|
|
Limit uint
|
|
Offset uint
|
|
Order string
|
|
}
|
|
|
|
func Create(ctx context.Context, e Entity) error {
|
|
key := e.Key(ctx)
|
|
val := e.Value()
|
|
idx := e.Index(ctx)
|
|
|
|
// read the existing record
|
|
recs, err := store.Read(key, store.ReadLimit(1))
|
|
if err != nil && err != store.ErrNotFound {
|
|
return err
|
|
}
|
|
|
|
if len(recs) > 0 {
|
|
return ErrAlreadyExists
|
|
}
|
|
|
|
// write the record
|
|
if err := store.Write(store.NewRecord(key, val)); err != nil {
|
|
return err
|
|
}
|
|
|
|
// only write the index if it exists
|
|
if len(idx) == 0 {
|
|
return nil
|
|
}
|
|
|
|
// write the index
|
|
return store.Write(store.NewRecord(idx, val))
|
|
}
|
|
|
|
func ReadIndex(ctx context.Context, e Entity) error {
|
|
recs, err := store.Read(e.Index(ctx), store.ReadLimit(1))
|
|
if err == store.ErrNotFound {
|
|
return ErrNotFound
|
|
} else if err != nil {
|
|
return err
|
|
}
|
|
if len(recs) == 0 {
|
|
return ErrNotFound
|
|
}
|
|
return recs[0].Decode(e)
|
|
}
|
|
|
|
func Read(ctx context.Context, e Entity) error {
|
|
recs, err := store.Read(e.Key(ctx), store.ReadLimit(1))
|
|
if err == store.ErrNotFound {
|
|
return ErrNotFound
|
|
} else if err != nil {
|
|
return err
|
|
}
|
|
if len(recs) == 0 {
|
|
return ErrNotFound
|
|
}
|
|
return recs[0].Decode(e)
|
|
}
|
|
|
|
func Update(ctx context.Context, e Entity) error {
|
|
key := e.Key(ctx)
|
|
val := e.Value()
|
|
idx := e.Index(ctx)
|
|
|
|
// write the record
|
|
if err := store.Write(store.NewRecord(key, val)); err != nil {
|
|
return err
|
|
}
|
|
|
|
// only write the index if it exists
|
|
if len(idx) == 0 {
|
|
return nil
|
|
}
|
|
|
|
// write the index
|
|
return store.Write(store.NewRecord(idx, val))
|
|
}
|
|
|
|
func List(ctx context.Context, e Entity, rsp interface{}, q Query) error {
|
|
opts := []store.ReadOption{
|
|
store.ReadPrefix(),
|
|
}
|
|
|
|
if q.Limit > 0 {
|
|
opts = append(opts, store.ReadLimit(q.Limit))
|
|
}
|
|
if q.Offset > 0 {
|
|
opts = append(opts, store.ReadOffset(q.Offset))
|
|
}
|
|
if len(q.Order) > 0 {
|
|
if q.Order == "desc" {
|
|
opts = append(opts, store.ReadOrder(store.OrderDesc))
|
|
} else {
|
|
opts = append(opts, store.ReadOrder(store.OrderAsc))
|
|
}
|
|
}
|
|
|
|
recs, err := store.Read(e.Index(ctx), opts...)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsBuffer := []byte("[")
|
|
|
|
for i, rec := range recs {
|
|
jsBuffer = append(jsBuffer, rec.Value...)
|
|
if i < len(recs)-1 {
|
|
jsBuffer = append(jsBuffer, []byte(",")...)
|
|
}
|
|
}
|
|
|
|
jsBuffer = append(jsBuffer, []byte("]")...)
|
|
return json.Unmarshal(jsBuffer, rsp)
|
|
}
|
|
|
|
func Delete(ctx context.Context, e Entity) error {
|
|
key := e.Key(ctx)
|
|
idx := e.Index(ctx)
|
|
|
|
if len(key) > 0 {
|
|
if err := store.Delete(key); err != nil && err != store.ErrNotFound {
|
|
return err
|
|
}
|
|
}
|
|
|
|
recs, err := store.Read(idx, store.ReadPrefix())
|
|
if err != nil && err != store.ErrNotFound {
|
|
return err
|
|
}
|
|
|
|
// delete every record by index
|
|
for _, rec := range recs {
|
|
var val interface{}
|
|
if err := rec.Decode(val); err != nil || val == nil {
|
|
continue
|
|
}
|
|
// convert to an entity
|
|
e, ok := val.(Entity)
|
|
if !ok {
|
|
continue
|
|
}
|
|
if err := store.Delete(e.Key(ctx)); err != store.ErrNotFound {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|