upd(crm): refactor crm service layer

This commit is contained in:
Tit Petric
2018-08-15 16:29:06 +02:00
parent 0489373ca8
commit 3ba1eb9a22
9 changed files with 200 additions and 116 deletions
+7
View File
@@ -0,0 +1,7 @@
package repository
const (
// @todo root should be configurable
// @todo move this to db or stack it inside the binary or container
fieldPath = "crm/data/%s.json"
)
+34 -21
View File
@@ -10,27 +10,40 @@ import (
"path/filepath"
)
const (
// @todo root should be configurable
// @todo move this to db or stack it inside the binary or container
fieldPath = "crm/data/%s.json"
)
type (
field struct{}
Field interface {
With(ctx context.Context) Field
FindByName(name string) (*types.Field, error)
Find() ([]*types.Field, error)
}
field struct {
*repository
}
)
func Field() field {
return field{}
func NewField(ctx context.Context) Field {
return &field{
repository: &repository{
ctx: ctx,
},
}
}
func (r *field) With(ctx context.Context) Field {
return &field{
repository: r.repository.With(ctx),
}
}
// Finds field by it's name and returns it
func (repo field) FindByName(ctx context.Context, name string) (*types.Field, error) {
return repo.decode(fmt.Sprintf(fieldPath, name))
func (f *field) FindByName(name string) (*types.Field, error) {
return f.fieldDecode(fmt.Sprintf(fieldPath, name))
}
// Returns all known fields
func (repo field) Find(ctx context.Context) ([]*types.Field, error) {
func (f *field) Find() ([]*types.Field, error) {
matches, err := filepath.Glob(fmt.Sprintf(fieldPath, "*"))
if err != nil {
return nil, err
@@ -38,14 +51,14 @@ func (repo field) Find(ctx context.Context) ([]*types.Field, error) {
res := make([]*types.Field, len(matches))
for i, match := range matches {
if res[i], err = repo.decode(match); err != nil {
if res[i], err = f.fieldDecode(match); err != nil {
return nil, err
}
}
return res, nil
}
func (repo field) decode(filepath string) (*types.Field, error) {
func (f *field) fieldDecode(filepath string) (*types.Field, error) {
file, err := os.Open(filepath)
if err != nil {
// @todo wrap error
@@ -54,9 +67,15 @@ func (repo field) decode(filepath string) (*types.Field, error) {
defer file.Close()
// Removes path and extension from full filename
fieldTypeFromPath := func(filepath string) string {
t := path.Base(filepath)
return t[:len(t)-5]
}
// Preset field's type with name of the file (sans .json)
// if type is explicitly set within the file, it will be overwritten
field := &types.Field{Type: repo.typeFromPath(filepath)}
field := &types.Field{Type: fieldTypeFromPath(filepath)}
if err := json.NewDecoder(file).Decode(&field); err != nil {
// @todo wrap error
return nil, err
@@ -64,9 +83,3 @@ func (repo field) decode(filepath string) (*types.Field, error) {
return field, nil
}
// Removes path and extension from full filename
func (repo field) typeFromPath(filepath string) string {
t := path.Base(filepath)
return t[:len(t)-5]
}
+40 -20
View File
@@ -7,17 +7,39 @@ import (
)
type (
module struct{}
Module interface {
With(ctx context.Context) Module
FindByID(id uint64) (*types.Module, error)
Find() ([]*types.Module, error)
Create(mod *types.Module) (*types.Module, error)
Update(mod *types.Module) (*types.Module, error)
DeleteByID(id uint64) error
}
module struct {
*repository
}
)
func Module() module {
return module{}
func NewModule(ctx context.Context) Module {
return &module{
repository: &repository{
ctx: ctx,
},
}
}
func (r module) FindByID(ctx context.Context, id uint64) (*types.Module, error) {
db := factory.Database.MustGet()
func (r *module) With(ctx context.Context) Module {
return &module{
repository: r.repository.With(ctx),
}
}
func (r *module) FindByID(id uint64) (*types.Module, error) {
mod := &types.Module{}
if err := db.Get(mod, "SELECT * FROM crm_module WHERE id = ?", id); err != nil {
if err := r.db().Get(mod, "SELECT * FROM crm_module WHERE id = ?", id); err != nil {
println(err.Error())
return nil, ErrDatabaseError
} else {
@@ -25,10 +47,9 @@ func (r module) FindByID(ctx context.Context, id uint64) (*types.Module, error)
}
}
func (r module) Find(ctx context.Context) ([]*types.Module, error) {
db := factory.Database.MustGet()
func (r *module) Find() ([]*types.Module, error) {
mod := make([]*types.Module, 0)
if err := db.With(ctx).Select(&mod, "SELECT * FROM crm_module ORDER BY name ASC"); err != nil {
if err := r.db().Select(&mod, "SELECT * FROM crm_module ORDER BY name ASC"); err != nil {
println(err.Error())
return nil, ErrDatabaseError
} else {
@@ -36,26 +57,25 @@ func (r module) Find(ctx context.Context) ([]*types.Module, error) {
}
}
func (r module) Create(ctx context.Context, mod *types.Module) (*types.Module, error) {
func (r *module) Create(mod *types.Module) (*types.Module, error) {
mod.ID = factory.Sonyflake.NextID()
return mod, factory.Database.MustGet().With(ctx).Insert("crm_module", mod)
return mod, r.db().Insert("crm_module", mod)
}
func (r module) Update(ctx context.Context, mod *types.Module) (*types.Module, error) {
return mod, factory.Database.MustGet().With(ctx).Replace("crm_module", mod)
func (r *module) Update(mod *types.Module) (*types.Module, error) {
return mod, r.db().Replace("crm_module", mod)
}
func (r module) DeleteByID(ctx context.Context, id uint64) error {
db := factory.Database.MustGet()
if _, err := db.Exec("DELETE FROM crm_module WHERE ID = ?", id); err != nil {
func (r *module) DeleteByID(id uint64) error {
if _, err := r.db().Exec("DELETE FROM crm_module WHERE ID = ?", id); err != nil {
return ErrDatabaseError
} else {
return nil
}
}
//func (r module) Edit(r *moduleEditRequest) (interface{}, error) {
//func (r *module) Edit(r *moduleEditRequest) (interface{}, error) {
// db := factory.Database.MustGet()
// m := module{}.New()
// m.SetID(r.id).SetName(r.name)
@@ -66,7 +86,7 @@ func (r module) DeleteByID(ctx context.Context, id uint64) error {
// return m, db.With(ctx).Insert("crm_module", m)
//}
//
//func (r module) ContentList(r *moduleContentListRequest) (interface{}, error) {
//func (r *module) ContentList(r *moduleContentListRequest) (interface{}, error) {
// db := factory.Database.MustGet()
// if r.id > 0 {
// m := ModuleContentRow{}.New()
@@ -78,10 +98,10 @@ func (r module) DeleteByID(ctx context.Context, id uint64) error {
// return res, err
//}
//
//func (r module) ContentEdit(r *moduleContentEditRequest) (interface{}, error) {
//func (r *module) ContentEdit(r *moduleContentEditRequest) (interface{}, error) {
// return nil, errors.New("Not implemented: module.content/edit")
//}
//
//func (r module) ContentDelete(r *moduleContentDeleteRequest) (interface{}, error) {
//func (r *module) ContentDelete(r *moduleContentDeleteRequest) (interface{}, error) {
// return nil, errors.New("Not implemented: module.content/delete")
//}
+43
View File
@@ -0,0 +1,43 @@
package repository
import (
"context"
"github.com/pkg/errors"
"github.com/titpetric/factory"
)
type (
repository struct {
ctx context.Context
// Current transaction
tx *factory.DB
}
)
// With updates repository and database contexts
func (r *repository) With(ctx context.Context) *repository {
return &repository{
ctx: ctx,
tx: r.db().With(r.ctx),
}
}
func (r *repository) Begin() error {
return r.db().Begin()
}
func (r *repository) Commit() error {
return errors.Wrap(r.db().Commit(), "Can not commit changes")
}
func (r *repository) Rollback() error {
return errors.Wrap(r.db().Rollback(), "Can not rollback changes")
}
func (r *repository) db() *factory.DB {
if r.tx == nil {
r.tx = factory.Database.MustGet().With(r.ctx)
}
return r.tx
}
+11 -10
View File
@@ -6,31 +6,32 @@ import (
"context"
"github.com/crusttech/crust/crm/rest/server"
"github.com/crusttech/crust/crm/types"
"github.com/crusttech/crust/crm/service"
)
var _ = errors.Wrap
type (
Field struct {
svc fieldService
field service.FieldService
}
fieldService interface {
FieldService interface {
FindByName(ctx context.Context, name string) (*types.Field, error)
Find(ctx context.Context) ([]*types.Field, error)
}
)
func (Field) New(fieldSvc fieldService) *Field {
var ctrl = &Field{}
ctrl.svc = fieldSvc
return ctrl
func (Field) New() server.FieldAPI {
return &Field{
field: service.Field(),
}
}
func (self *Field) List(ctx context.Context, _ *server.FieldListRequest) (interface{}, error) {
return self.svc.Find(ctx)
func (s *Field) List(ctx context.Context, _ *server.FieldListRequest) (interface{}, error) {
return s.field.With(ctx).Find()
}
func (self *Field) Type(ctx context.Context, r *server.FieldTypeRequest) (interface{}, error) {
return self.svc.FindByName(ctx, r.ID)
func (s *Field) Type(ctx context.Context, r *server.FieldTypeRequest) (interface{}, error) {
return s.field.With(ctx).FindByName(r.ID)
}
+16 -24
View File
@@ -8,51 +8,43 @@ import (
"context"
"github.com/crusttech/crust/crm/rest/server"
"github.com/crusttech/crust/crm/types"
"github.com/crusttech/crust/crm/service"
)
var _ = errors.Wrap
type (
Module struct {
svc moduleService
}
moduleService interface {
FindByID(ctx context.Context, moduleID uint64) (*types.Module, error)
Find(ctx context.Context) ([]*types.Module, error)
Create(ctx context.Context, module *types.Module) (*types.Module, error)
Update(ctx context.Context, module *types.Module) (*types.Module, error)
DeleteByID(ctx context.Context, moduleID uint64) error
module service.ModuleService
}
)
func (Module) New(moduleSvc moduleService) *Module {
var ctrl = &Module{}
ctrl.svc = moduleSvc
return ctrl
func (Module) New() server.ModuleAPI {
return &Module{
module: service.Module(),
}
}
func (c *Module) List(ctx context.Context, r *server.ModuleListRequest) (interface{}, error) {
return c.svc.Find(ctx)
func (s *Module) List(ctx context.Context, r *server.ModuleListRequest) (interface{}, error) {
return s.module.With(ctx).Find()
}
func (c *Module) Read(ctx context.Context, r *server.ModuleReadRequest) (interface{}, error) {
return c.svc.FindByID(ctx, r.ID)
func (s *Module) Read(ctx context.Context, r *server.ModuleReadRequest) (interface{}, error) {
return s.module.With(ctx).FindByID(r.ID)
}
func (c *Module) Delete(ctx context.Context, r *server.ModuleDeleteRequest) (interface{}, error) {
return resputil.OK(), c.svc.DeleteByID(ctx, r.ID)
func (s *Module) Delete(ctx context.Context, r *server.ModuleDeleteRequest) (interface{}, error) {
return resputil.OK(), s.module.With(ctx).DeleteByID(r.ID)
}
func (c *Module) Create(ctx context.Context, r *server.ModuleCreateRequest) (interface{}, error) {
func (s *Module) Create(ctx context.Context, r *server.ModuleCreateRequest) (interface{}, error) {
m := &types.Module{Name: r.Name}
return c.svc.Create(ctx, m)
return s.module.With(ctx).Create(m)
}
func (c *Module) Edit(ctx context.Context, r *server.ModuleEditRequest) (interface{}, error) {
func (s *Module) Edit(ctx context.Context, r *server.ModuleEditRequest) (interface{}, error) {
m := &types.Module{ID: r.ID, Name: r.Name}
return c.svc.Update(ctx, m)
return s.module.With(ctx).Update(m)
}
func (*Module) ContentList(ctx context.Context, r *server.ModuleContentListRequest) (interface{}, error) {
+2 -9
View File
@@ -3,7 +3,6 @@ package rest
import (
"github.com/crusttech/crust/auth"
"github.com/crusttech/crust/crm/rest/server"
"github.com/crusttech/crust/crm/service"
"github.com/go-chi/chi"
)
@@ -14,12 +13,6 @@ type (
)
func MountRoutes(jwtAuth authTokenEncoder) func(chi.Router) {
// Initialize services
var (
fieldSvc = service.Field()
moduleSvc = service.Module()
)
// @todo pass jwtAuth to auth handlers (signUp) for JWT generation
// Initialize handers & controllers.
@@ -27,11 +20,11 @@ func MountRoutes(jwtAuth authTokenEncoder) func(chi.Router) {
r.Use(auth.AuthenticationMiddlewareValidOnly)
(&server.FieldHandlers{
Field: (&Field{}).New(fieldSvc),
Field: Field{}.New(),
}).MountRoutes(r)
(&server.ModuleHandlers{
Module: (&Module{}).New(moduleSvc),
Module: Module{}.New(),
}).MountRoutes(r)
}
}
+19 -12
View File
@@ -7,26 +7,33 @@ import (
)
type (
fieldType struct {
repository fieldTypeRepository
field struct {
repository repository.Field
}
fieldTypeRepository interface {
FindByName(ctx context.Context, name string) (*types.Field, error)
Find(ctx context.Context) ([]*types.Field, error)
FieldService interface {
With(ctx context.Context) FieldService
FindByName(name string) (*types.Field, error)
Find() ([]*types.Field, error)
}
)
func Field() fieldType {
return fieldType{
repository: repository.Field(),
func Field() FieldService {
return &field{
repository: repository.NewField(context.Background()),
}
}
func (svc fieldType) FindByName(ctx context.Context, name string) (*types.Field, error) {
return svc.repository.FindByName(ctx, name)
func (s *field) With(ctx context.Context) FieldService {
return &field{
repository: s.repository.With(ctx),
}
}
func (svc fieldType) Find(ctx context.Context) ([]*types.Field, error) {
return svc.repository.Find(ctx)
func (s *field) FindByName(name string) (*types.Field, error) {
return s.repository.FindByName(name)
}
func (s *field) Find() ([]*types.Field, error) {
return s.repository.Find()
}
+28 -20
View File
@@ -8,41 +8,49 @@ import (
type (
module struct {
repository moduleRepository
repository repository.Module
}
moduleRepository interface {
FindByID(ctx context.Context, moduleID uint64) (*types.Module, error)
Find(ctx context.Context) ([]*types.Module, error)
ModuleService interface {
With(ctx context.Context) ModuleService
Create(ctx context.Context, module *types.Module) (*types.Module, error)
Update(ctx context.Context, module *types.Module) (*types.Module, error)
DeleteByID(ctx context.Context, moduleID uint64) error
FindByID(moduleID uint64) (*types.Module, error)
Find() ([]*types.Module, error)
Create(module *types.Module) (*types.Module, error)
Update(module *types.Module) (*types.Module, error)
DeleteByID(moduleID uint64) error
}
)
func Module() module {
return module{
repository: repository.Module(),
func Module() ModuleService {
return &module{
repository: repository.NewModule(context.Background()),
}
}
func (svc module) FindByID(ctx context.Context, id uint64) (*types.Module, error) {
return svc.repository.FindByID(ctx, id)
func (s *module) With(ctx context.Context) ModuleService {
return &module{
repository: s.repository.With(ctx),
}
}
func (svc module) Find(ctx context.Context) ([]*types.Module, error) {
return svc.repository.Find(ctx)
func (s *module) FindByID(id uint64) (*types.Module, error) {
return s.repository.FindByID(id)
}
func (svc module) Create(ctx context.Context, mod *types.Module) (*types.Module, error) {
return svc.repository.Create(ctx, mod)
func (s *module) Find() ([]*types.Module, error) {
return s.repository.Find()
}
func (svc module) Update(ctx context.Context, mod *types.Module) (*types.Module, error) {
return svc.repository.Update(ctx, mod)
func (s *module) Create(mod *types.Module) (*types.Module, error) {
return s.repository.Create(mod)
}
func (svc module) DeleteByID(ctx context.Context, id uint64) error {
return svc.repository.DeleteByID(ctx, id)
func (s *module) Update(mod *types.Module) (*types.Module, error) {
return s.repository.Update(mod)
}
func (s *module) DeleteByID(id uint64) error {
return s.repository.DeleteByID(id)
}