3
0

upd(crm): service tests and logic

This commit is contained in:
Tit Petric
2018-11-27 13:26:49 +01:00
parent 390409ed6a
commit 7e87f00c42
19 changed files with 248 additions and 160 deletions

View File

@@ -90,7 +90,7 @@ test.events: $(GOTEST)
$(GO) tool cover -func=.cover.out | grep --color "^\|[^0-9]0.0%"
test.crm: $(GOTEST)
$(GOTEST) -covermode count -coverprofile .cover.out -v ./crm/repository/...
$(GOTEST) -covermode count -coverprofile .cover.out -v ./crm/service/...
$(GO) tool cover -func=.cover.out | grep --color "^\|[^0-9]0.0%"
test.crm.db: $(GOTEST)

View File

@@ -12,7 +12,6 @@ import (
"github.com/titpetric/factory"
"github.com/crusttech/crust/crm/types"
systemRepository "github.com/crusttech/crust/system/repository"
)
type (
@@ -64,7 +63,7 @@ func (r *content) FindByID(id uint64) (*types.Content, error) {
if err := r.db().Get(mod, "SELECT * FROM crm_content WHERE id=? and deleted_at IS NULL", id); err != nil {
return nil, err
}
return mod, r.prepare(mod, "page", "user", "fields")
return mod, nil
}
func (r *content) Find(moduleID uint64, query string, page int, perPage int) (*FindResponse, error) {
@@ -116,10 +115,6 @@ func (r *content) Find(moduleID uint64, query string, page int, perPage int) (*F
}
}
if err := r.prepareAll(response.Contents, "user", "fields"); err != nil {
return nil, err
}
return response, nil
}
@@ -154,14 +149,10 @@ func (r *content) Create(mod *types.Content) (*types.Content, error) {
if err := r.db().Insert("crm_content", mod); err != nil {
return nil, err
}
return mod, r.prepare(mod, "user", "fields")
return mod, nil
}
func (r *content) Update(mod *types.Content) (*types.Content, error) {
if mod.ID == 0 {
return nil, errors.New("Error when savig content, invalid ID")
}
now := time.Now()
mod.UpdatedAt = &now
@@ -222,44 +213,3 @@ func (r *content) Fields(content *types.Content) ([]*types.ContentColumn, error)
}
return result, r.db().Select(&result, "select * FROM crm_content_column where content_id=? order by "+order, args...)
}
func (r *content) prepareAll(contents []*types.Content, fields ...string) error {
for _, content := range contents {
if err := r.prepare(content, fields...); err != nil {
return err
}
}
return nil
}
func (r *content) prepare(content *types.Content, fields ...string) (err error) {
api := Page(r.Context(), r.db())
usersAPI := systemRepository.User(r.Context(), r.db())
for _, field := range fields {
switch field {
case "fields":
fields, err := r.Fields(content)
if err != nil {
return err
}
json, err := json.Marshal(fields)
if err != nil {
return err
}
if err := (&content.Fields).Scan(json); err != nil {
return err
}
case "page":
if content.Page, err = api.FindByModuleID(content.ModuleID); err != nil {
return
}
case "user":
if content.UserID > 0 {
if content.User, err = usersAPI.FindByID(content.UserID); err != nil {
return
}
}
}
}
return
}

View File

@@ -50,9 +50,6 @@ func (r *module) FindByID(id uint64) (*types.Module, error) {
if err := r.db().Get(mod, "SELECT * FROM crm_module WHERE id=?", id); err != nil {
return nil, err
}
if err := r.fillPage(mod); err != nil {
return nil, err
}
return mod, nil
}
@@ -122,9 +119,3 @@ func (r *module) FieldNames(mod *types.Module) ([]string, error) {
return result, nil
}
}
func (r *module) fillPage(mod *types.Module) (err error) {
api := Page(r.Context(), r.db())
mod.Page, err = api.FindByModuleID(mod.ID)
return
}

View File

@@ -3,7 +3,6 @@ package repository
import (
"context"
"github.com/pkg/errors"
"github.com/titpetric/factory"
"github.com/crusttech/crust/crm/types"
@@ -45,9 +44,6 @@ func (r *page) FindByID(id uint64) (*types.Page, error) {
if err := r.db().Get(page, "SELECT * FROM crm_page WHERE id=?", id); err != nil {
return page, err
}
if err := r.fillModule(page); err != nil {
return page, err
}
return page, nil
}
@@ -64,11 +60,6 @@ func (r *page) FindBySelfID(selfID uint64) (types.PageSet, error) {
if err := r.db().Select(&pages, "SELECT * FROM crm_page WHERE self_id = ? ORDER BY weight ASC", selfID); err != nil {
return pages, err
}
for _, page := range pages {
if err := r.fillModule(page); err != nil {
return pages, err
}
}
return pages, nil
}
@@ -118,9 +109,6 @@ func (r *page) Create(item *types.Page) (*types.Page, error) {
}
func (r *page) Update(page *types.Page) (*types.Page, error) {
if page.ID == 0 {
return nil, errors.New("Error when savig page, invalid ID")
}
return page, r.db().Replace("crm_page", page)
}
@@ -128,13 +116,3 @@ func (r *page) DeleteByID(id uint64) error {
_, err := r.db().Exec("DELETE FROM crm_page WHERE id=?", id)
return err
}
func (r *page) fillModule(page *types.Page) error {
if page.ModuleID > 0 {
api := Module(r.Context(), r.db())
module, err := api.FindByID(page.ModuleID)
page.Module = module
return err
}
return nil
}

View File

@@ -22,7 +22,7 @@ func (Page) New(pageSvc service.PageService) *Page {
}
func (ctrl *Page) List(ctx context.Context, r *request.PageList) (interface{}, error) {
return ctrl.page.With(ctx).Find(r.SelfID)
return ctrl.page.With(ctx).FindBySelfID(r.SelfID)
}
func (ctrl *Page) Tree(ctx context.Context, r *request.PageTree) (interface{}, error) {

View File

@@ -1,14 +1,14 @@
package repository
package service
import (
"context"
"testing"
"context"
"github.com/crusttech/crust/crm/rest/request"
)
func TestModuleGraph(t *testing.T) {
repository := Module(context.TODO(), nil).With(context.Background(), nil)
repository := Module().With(context.Background())
params := &request.ModuleChart{
Kind: "line",

View File

@@ -3,17 +3,24 @@ package service
import (
"context"
"github.com/pkg/errors"
"github.com/titpetric/factory"
"github.com/crusttech/crust/crm/repository"
"github.com/crusttech/crust/crm/types"
systemService "github.com/crusttech/crust/system/service"
)
type (
content struct {
db *factory.DB
ctx context.Context
db *factory.DB
ctx context.Context
repository repository.ContentRepository
pageRepo repository.PageRepository
userSvc systemService.UserService
}
ContentService interface {
@@ -26,11 +33,15 @@ type (
Create(content *types.Content) (*types.Content, error)
Update(content *types.Content) (*types.Content, error)
DeleteByID(contentID uint64) error
Fields(mod *types.Content) ([]*types.ContentColumn, error)
}
)
func Content() ContentService {
return (&content{}).With(context.Background())
return (&content{
userSvc: systemService.DefaultUser,
}).With(context.Background())
}
func (s *content) With(ctx context.Context) ContentService {
@@ -39,25 +50,49 @@ func (s *content) With(ctx context.Context) ContentService {
db: db,
ctx: ctx,
repository: repository.Content(ctx, db),
pageRepo: repository.Page(ctx, db),
userSvc: s.userSvc.With(ctx),
}
}
func (s *content) FindByID(id uint64) (*types.Content, error) {
return s.repository.FindByID(id)
response, err := s.repository.FindByID(id)
if err != nil {
return nil, err
}
return response, s.preload(response, "page", "user", "fields")
}
func (s *content) Find(moduleID uint64, query string, page int, perPage int) (*repository.FindResponse, error) {
return s.repository.Find(moduleID, query, page, perPage)
response, err := s.repository.Find(moduleID, query, page, perPage)
if err != nil {
return nil, err
}
if err := s.preloadAll(response.Contents, "user", "fields"); err != nil {
return nil, err
}
return response, nil
}
func (s *content) Create(mod *types.Content) (*types.Content, error) {
return s.repository.Create(mod)
response, err := s.repository.Create(mod)
if err != nil {
return nil, err
}
return response, s.preload(response, "user", "fields")
}
func (s *content) Update(mod *types.Content) (*types.Content, error) {
if mod.ID == 0 {
return nil, errors.New("Error when savig content, invalid ID")
}
return s.repository.Update(mod)
}
func (s *content) Fields(mod *types.Content) ([]*types.ContentColumn, error) {
return s.repository.Fields(mod)
}
func (s *content) DeleteByID(id uint64) error {
return s.repository.DeleteByID(id)
}

View File

@@ -1,4 +1,4 @@
package repository
package service
import (
"context"
@@ -30,7 +30,7 @@ func TestContent(t *testing.T) {
}
ctx := auth.SetIdentityToContext(context.Background(), auth.NewIdentity(user.Identity()))
repository := Content(context.TODO(), nil).With(ctx, nil)
repository := Content().With(ctx)
fields, err := json.Marshal([]types.Field{
types.Field{
@@ -55,7 +55,7 @@ func TestContent(t *testing.T) {
// set up a module
{
_, err := Module(context.TODO(), nil).With(context.Background(), nil).Create(module)
_, err := Module().With(context.Background()).Create(module)
assert(t, err == nil, "Error when creating module: %+v", err)
assert(t, module.ID > 0, "Expected auto generated ID")
}

View File

@@ -0,0 +1,46 @@
package service
import (
"encoding/json"
"github.com/crusttech/crust/crm/types"
)
func (r *content) preloadAll(contents []*types.Content, fields ...string) error {
for _, content := range contents {
if err := r.preload(content, fields...); err != nil {
return err
}
}
return nil
}
func (r *content) preload(content *types.Content, fields ...string) (err error) {
for _, field := range fields {
switch field {
case "fields":
fields, err := r.Fields(content)
if err != nil {
return err
}
json, err := json.Marshal(fields)
if err != nil {
return err
}
if err := (&content.Fields).Scan(json); err != nil {
return err
}
case "page":
if content.Page, err = r.pageRepo.FindByModuleID(content.ModuleID); err != nil {
return
}
case "user":
if content.UserID > 0 {
if content.User, err = r.userSvc.FindByID(content.UserID); err != nil {
return
}
}
}
}
return
}

View File

@@ -11,8 +11,9 @@ import (
type (
field struct {
db *factory.DB
ctx context.Context
db *factory.DB
ctx context.Context
repository repository.FieldRepository
}

View File

@@ -1,4 +1,4 @@
package repository
package service
import (
"context"
@@ -6,7 +6,7 @@ import (
)
func TestField(t *testing.T) {
repository := Field(context.TODO(), nil).With(context.Background(), nil)
repository := Field().With(context.Background())
{
// fetch all fields

View File

@@ -1,4 +1,4 @@
package repository
package service
import (
"log"
@@ -11,6 +11,7 @@ import (
crmMigrate "github.com/crusttech/crust/crm/db"
systemMigrate "github.com/crusttech/crust/system/db"
systemService "github.com/crusttech/crust/system/service"
)
func TestMain(m *testing.M) {
@@ -57,6 +58,8 @@ func TestMain(m *testing.M) {
}
}
systemService.Init()
os.Exit(m.Run())
}

View File

@@ -12,9 +12,11 @@ import (
type (
module struct {
db *factory.DB
ctx context.Context
repository repository.ModuleRepository
db *factory.DB
ctx context.Context
moduleRepo repository.ModuleRepository
pageRepo repository.PageRepository
}
ModuleService interface {
@@ -40,30 +42,38 @@ func (s *module) With(ctx context.Context) ModuleService {
return &module{
db: db,
ctx: ctx,
repository: repository.Module(ctx, db),
moduleRepo: repository.Module(ctx, db),
pageRepo: repository.Page(ctx, db),
}
}
func (s *module) FindByID(id uint64) (*types.Module, error) {
return s.repository.FindByID(id)
mod, err := s.moduleRepo.FindByID(id)
if err != nil {
return nil, err
}
if err := s.preload(mod); err != nil {
return nil, err
}
return mod, err
}
func (s *module) Find() ([]*types.Module, error) {
return s.repository.Find()
return s.moduleRepo.Find()
}
func (s *module) Chart(r *request.ModuleChart) (interface{}, error) {
return s.repository.Chart(r)
return s.moduleRepo.Chart(r)
}
func (s *module) Create(mod *types.Module) (*types.Module, error) {
return s.repository.Create(mod)
return s.moduleRepo.Create(mod)
}
func (s *module) Update(mod *types.Module) (*types.Module, error) {
return s.repository.Update(mod)
return s.moduleRepo.Update(mod)
}
func (s *module) DeleteByID(id uint64) error {
return s.repository.DeleteByID(id)
return s.moduleRepo.DeleteByID(id)
}

View File

@@ -1,4 +1,4 @@
package repository
package service
import (
"context"
@@ -7,7 +7,7 @@ import (
)
func TestModule(t *testing.T) {
repository := Module(context.TODO(), nil).With(context.Background(), nil)
repository := Module().With(context.Background())
// the module object we're working with
module := &types.Module{

View File

@@ -0,0 +1,10 @@
package service
import (
"github.com/crusttech/crust/crm/types"
)
func (r *module) preload(mod *types.Module) (err error) {
mod.Page, err = r.pageRepo.FindByModuleID(mod.ID)
return
}

View File

@@ -4,7 +4,6 @@ import (
"context"
"errors"
"github.com/davecgh/go-spew/spew"
"github.com/titpetric/factory"
"github.com/crusttech/crust/crm/repository"
@@ -13,9 +12,10 @@ import (
type (
page struct {
db *factory.DB
ctx context.Context
repository repository.PageRepository
db *factory.DB
ctx context.Context
pageRepo repository.PageRepository
moduleRepo repository.ModuleRepository
}
@@ -23,7 +23,8 @@ type (
With(ctx context.Context) PageService
FindByID(pageID uint64) (*types.Page, error)
Find(selfID uint64) (pages types.PageSet, err error)
FindByModuleID(moduleID uint64) (*types.Page, error)
FindBySelfID(selfID uint64) (pages types.PageSet, err error)
Tree() (pages types.PageSet, err error)
Create(page *types.Page) (*types.Page, error)
@@ -41,24 +42,42 @@ func Page() PageService {
func (s *page) With(ctx context.Context) PageService {
db := repository.DB(ctx)
return &page{
db: db,
ctx: ctx,
repository: repository.Page(ctx, db),
db: db,
ctx: ctx,
pageRepo: repository.Page(ctx, db),
moduleRepo: repository.Module(ctx, db),
}
}
func (s *page) FindByID(id uint64) (*types.Page, error) {
return s.repository.FindByID(id)
page, err := s.pageRepo.FindByID(id)
if err != nil {
return nil, err
}
if err := s.preload(page); err != nil {
return nil, err
}
return page, err
}
func (s *page) Find(selfID uint64) (pages types.PageSet, err error) {
func (s *page) FindByModuleID(moduleID uint64) (*types.Page, error) {
page, err := s.pageRepo.FindByModuleID(moduleID)
if err != nil {
return nil, err
}
if err := s.preload(page); err != nil {
return nil, err
}
return page, err
}
func (s *page) FindBySelfID(selfID uint64) (pages types.PageSet, err error) {
return pages, s.db.Transaction(func() (err error) {
if pages, err = s.repository.FindBySelfID(selfID); err != nil {
if pages, err = s.pageRepo.FindBySelfID(selfID); err != nil {
return
}
if err = s.preload(pages); err != nil {
if err = s.preloadAll(pages); err != nil {
return
}
@@ -70,11 +89,11 @@ func (s *page) Tree() (pages types.PageSet, err error) {
var tree types.PageSet
return tree, s.db.Transaction(func() (err error) {
if pages, err = s.repository.FindAll(); err != nil {
if pages, err = s.pageRepo.FindAll(); err != nil {
return
}
if err = s.preload(pages); err != nil {
if err = s.preloadAll(pages); err != nil {
return
}
@@ -99,56 +118,54 @@ func (s *page) Tree() (pages types.PageSet, err error) {
}
func (s *page) Reorder(selfID uint64, pageIDs []uint64) error {
return s.repository.Reorder(selfID, pageIDs)
return s.pageRepo.Reorder(selfID, pageIDs)
}
func (s *page) Create(mod *types.Page) (p *types.Page, err error) {
return p, s.db.Transaction(func() (err error) {
if mod.ModuleID > 0 {
func (s *page) Create(page *types.Page) (p *types.Page, err error) {
validate := func() error {
if page.ModuleID > 0 {
// @todo check if module exists!
if p, err = s.repository.FindByModuleID(mod.ModuleID); err != nil {
if p, err = s.pageRepo.FindByModuleID(page.ModuleID); err != nil {
return err
} else if p.ID > 0 {
return errors.New("Page for module already exists")
}
}
p, err = s.repository.Create(mod)
return nil
}
if err := validate(); err != nil {
return nil, err
}
return p, s.db.Transaction(func() (err error) {
p, err = s.pageRepo.Create(page)
return
})
}
func (s *page) Update(mod *types.Page) (p *types.Page, err error) {
return p, s.db.Transaction(func() (err error) {
if mod.ModuleID > 0 {
func (s *page) Update(page *types.Page) (p *types.Page, err error) {
validate := func() error {
if page.ID == 0 {
return errors.New("Error when savig page, invalid ID")
}
if page.ModuleID > 0 {
// @todo check if module exists!
if p, err = s.repository.FindByModuleID(mod.ModuleID); err != nil {
if p, err = s.pageRepo.FindByModuleID(page.ModuleID); err != nil {
return err
} else if p.ID > 0 && mod.ID != p.ID {
spew.Dump(mod, p)
} else if p.ID > 0 && page.ID != p.ID {
return errors.New("Page for module already exists")
}
}
p, err = s.repository.Update(mod)
return nil
}
if err := validate(); err != nil {
return nil, err
}
return p, s.db.Transaction(func() (err error) {
p, err = s.pageRepo.Update(page)
return
})
}
func (s *page) DeleteByID(id uint64) error {
return s.repository.DeleteByID(id)
}
// Preloads modules for all pages
func (s *page) preload(pages types.PageSet) error {
if modules, err := s.moduleRepo.Find(); err != nil {
return err
} else {
_ = pages.Walk(func(page *types.Page) error {
page.Module = modules.FindByID(page.ModuleID)
return nil
})
}
return nil
return s.pageRepo.DeleteByID(id)
}

View File

@@ -1,4 +1,4 @@
package repository
package service
import (
"context"
@@ -11,7 +11,7 @@ import (
)
func TestPage(t *testing.T) {
repository := Page(context.TODO(), nil).With(context.Background(), nil)
repository := Page().With(context.Background())
// the page object we're working with
page := &types.Page{

25
crm/service/page_util.go Normal file
View File

@@ -0,0 +1,25 @@
package service
import (
"github.com/crusttech/crust/crm/types"
)
func (s *page) preloadAll(pages types.PageSet) (err error) {
var modules types.ModuleSet
modules, err = s.moduleRepo.Find()
if err != nil {
return err
}
return pages.Walk(func(page *types.Page) error {
page.Module = modules.FindByID(page.ModuleID)
return nil
})
}
func (s *page) preload(page *types.Page) (err error) {
if page.ModuleID > 0 {
page.Module, err = s.moduleRepo.FindByID(page.ModuleID)
return
}
return
}

22
crm/service/service.go Normal file
View File

@@ -0,0 +1,22 @@
package service
import (
"sync"
)
var (
o sync.Once
DefaultContent ContentService
DefaultField FieldService
DefaultModule ModuleService
DefaultPage PageService
)
func Init() {
o.Do(func() {
DefaultContent = Content()
DefaultField = Field()
DefaultModule = Module()
DefaultPage = Page()
})
}