diff --git a/model/model.go b/model/model.go index 05c3de02..ea5d7f28 100644 --- a/model/model.go +++ b/model/model.go @@ -39,6 +39,8 @@ type Entity interface { } type Options struct { + // Database to write to + Database string // for serialising Codec codec.Marshaler // for locking diff --git a/model/mud/entity.go b/model/mud/entity.go new file mode 100644 index 00000000..03936598 --- /dev/null +++ b/model/mud/entity.go @@ -0,0 +1,52 @@ +package mud + +import ( + "github.com/google/uuid" + "github.com/micro/go-micro/v2/codec" + "github.com/micro/go-micro/v2/model" +) + +type mudEntity struct { + id string + name string + value interface{} + codec codec.Marshaler + attributes map[string]interface{} +} + +func (m *mudEntity) Attributes() map[string]interface{} { + return m.attributes +} + +func (m *mudEntity) Id() string { + return m.id +} + +func (m *mudEntity) Name() string { + return m.name +} + +func (m *mudEntity) Value() interface{} { + return m.value +} + +func (m *mudEntity) Read(v interface{}) error { + switch m.value.(type) { + case []byte: + b := m.value.([]byte) + return m.codec.Unmarshal(b, v) + default: + v = m.value + } + return nil +} + +func newEntity(name string, value interface{}, codec codec.Marshaler) model.Entity { + return &mudEntity{ + id: uuid.New().String(), + name: name, + value: value, + codec: codec, + attributes: make(map[string]interface{}), + } +} diff --git a/model/mud/mud.go b/model/mud/mud.go new file mode 100644 index 00000000..a01bc882 --- /dev/null +++ b/model/mud/mud.go @@ -0,0 +1,104 @@ +// Package mud is the micro data model implementation +package mud + +import ( + "github.com/micro/go-micro/v2/codec/json" + "github.com/micro/go-micro/v2/model" + "github.com/micro/go-micro/v2/store" + "github.com/micro/go-micro/v2/store/memory" + memsync "github.com/micro/go-micro/v2/sync/memory" +) + +type mudModel struct { + options model.Options +} + +func (m *mudModel) Init(opts ...model.Option) error { + for _, o := range opts { + o(&m.options) + } + return nil +} + +func (m *mudModel) NewEntity(name string, value interface{}) model.Entity { + // TODO: potentially pluralise name for tables + return newEntity(name, value, m.options.Codec) +} + +func (m *mudModel) Create(e model.Entity) error { + // lock on the name of entity + if err := m.options.Sync.Lock(e.Name()); err != nil { + return err + } + // TODO: deal with the error + defer m.options.Sync.Unlock(e.Name()) + + // TODO: potentially add encode to entity? + v, err := m.options.Codec.Marshal(e.Value()) + if err != nil { + return err + } + + // TODO: include metadata and set database + return m.options.Store.Write(&store.Record{ + Key: e.Id(), + Value: v, + }, store.WriteTo(m.options.Database, e.Name())) +} + +func (m *mudModel) Read(opts ...model.ReadOption) ([]model.Entity, error) { + var options model.ReadOptions + for _, o := range opts { + o(&options) + } + // TODO: implement the options that allow querying + return nil, nil +} + +func (m *mudModel) Update(e model.Entity) error { + // TODO: read out the record first, update the fields and store + + // lock on the name of entity + if err := m.options.Sync.Lock(e.Name()); err != nil { + return err + } + // TODO: deal with the error + defer m.options.Sync.Unlock(e.Name()) + + // TODO: potentially add encode to entity? + v, err := m.options.Codec.Marshal(e.Value()) + if err != nil { + return err + } + + // TODO: include metadata and set database + return m.options.Store.Write(&store.Record{ + Key: e.Id(), + Value: v, + }, store.WriteTo(m.options.Database, e.Name())) +} + +func (m *mudModel) Delete(opts ...model.DeleteOption) error { + var options model.DeleteOptions + for _, o := range opts { + o(&options) + } + // TODO: implement the options that allow deleting + return nil +} + +func (m *mudModel) String() string { + return "mud" +} + +func NewModel(opts ...model.Option) model.Model { + options := model.Options{ + Codec: new(json.Marshaler), + Sync: memsync.NewSync(), + Store: memory.NewStore(), + } + + return &mudModel{ + options: options, + } +}