diff --git a/model/model.go b/model/model.go index 57b17b1e..391d28b1 100644 --- a/model/model.go +++ b/model/model.go @@ -34,8 +34,6 @@ type Entity interface { Value() interface{} // Attributes of the entity Attributes() map[string]interface{} - // Read a value as a concrete type - Read(v interface{}) error } type Options struct { diff --git a/model/sql/entity.go b/model/sql/entity.go new file mode 100644 index 00000000..a683e507 --- /dev/null +++ b/model/sql/entity.go @@ -0,0 +1,41 @@ +package sql + +import ( + "github.com/google/uuid" + "github.com/micro/go-micro/v3/codec" + "github.com/micro/go-micro/v3/model" +) + +type sqlEntity struct { + id string + name string + value interface{} + codec codec.Marshaler + attributes map[string]interface{} +} + +func (m *sqlEntity) Attributes() map[string]interface{} { + return m.attributes +} + +func (m *sqlEntity) Id() string { + return m.id +} + +func (m *sqlEntity) Name() string { + return m.name +} + +func (m *sqlEntity) Value() interface{} { + return m.value +} + +func newEntity(name string, value interface{}, codec codec.Marshaler) model.Entity { + return &sqlEntity{ + id: uuid.New().String(), + name: name, + value: value, + codec: codec, + attributes: make(map[string]interface{}), + } +} diff --git a/model/sql/sql.go b/model/sql/sql.go new file mode 100644 index 00000000..af224d1f --- /dev/null +++ b/model/sql/sql.go @@ -0,0 +1,104 @@ +// Package sql is the micro data model implementation +package sql + +import ( + "github.com/micro/go-micro/v3/codec/json" + "github.com/micro/go-micro/v3/model" + "github.com/micro/go-micro/v3/store" + "github.com/micro/go-micro/v3/store/memory" + memsync "github.com/micro/go-micro/v3/sync/memory" +) + +type sqlModel struct { + options model.Options +} + +func (m *sqlModel) Init(opts ...model.Option) error { + for _, o := range opts { + o(&m.options) + } + return nil +} + +func (m *sqlModel) NewEntity(name string, value interface{}) model.Entity { + // TODO: potentially pluralise name for tables + return newEntity(name, value, m.options.Codec) +} + +func (m *sqlModel) 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 *sqlModel) 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 *sqlModel) 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 *sqlModel) 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 *sqlModel) String() string { + return "sql" +} + +func NewModel(opts ...model.Option) model.Model { + options := model.Options{ + Codec: new(json.Marshaler), + Sync: memsync.NewSync(), + Store: memory.NewStore(), + } + + return &sqlModel{ + options: options, + } +}