Skip to content

Commit

Permalink
feat: implement retrieve one facility by id
Browse files Browse the repository at this point in the history
Signed-off-by: maxwellgithinji <maxwellgithinji@gmail.com>
  • Loading branch information
maxwellgithinji committed Oct 12, 2021
1 parent 9201b24 commit 971321e
Show file tree
Hide file tree
Showing 15 changed files with 774 additions and 22 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ require (
github.com/savannahghi/profileutils v0.0.17
github.com/savannahghi/scalarutils v0.0.4
github.com/savannahghi/serverutils v0.0.6
github.com/segmentio/ksuid v1.0.4
github.com/sirupsen/logrus v1.8.1
github.com/tj/assert v0.0.3
github.com/vektah/gqlparser/v2 v2.1.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import (
//
// This mock struct should be separate from our own internal methods.
type GormMock struct {
CreateFacilityFn func(ctx context.Context, facility *gorm.Facility) (*gorm.Facility, error)
RetrieveFn func(id *int64) (*gorm.Facility, error)
GetFacilitiesFn func(ctx context.Context) ([]gorm.Facility, error)
CreateFacilityFn func(ctx context.Context, facility *gorm.Facility) (*gorm.Facility, error)
RetrieveFacilityFn func(ctx context.Context, id *int64) (*gorm.Facility, error)
GetFacilitiesFn func(ctx context.Context) ([]gorm.Facility, error)
}

// NewGormMock initializes a new instance of `GormMock` then mocking the case of success.
Expand All @@ -34,7 +34,7 @@ func NewGormMock() *GormMock {
}, nil
},

RetrieveFn: func(id *int64) (*gorm.Facility, error) {
RetrieveFacilityFn: func(ctx context.Context, id *int64) (*gorm.Facility, error) {
facilityID := int64(1)
name := "Kanairo One"
code := "KN001"
Expand Down Expand Up @@ -74,9 +74,9 @@ func (gm *GormMock) CreateFacility(ctx context.Context, facility *gorm.Facility)
return gm.CreateFacilityFn(ctx, facility)
}

// Retrieve mocks the implementation of `gorm's` Retrieve method.
func (gm *GormMock) Retrieve(id *int64) (*gorm.Facility, error) {
return gm.RetrieveFn(id)
// RetrieveFacility mocks the implementation of `gorm's` RetrieveFacility method.
func (gm *GormMock) RetrieveFacility(ctx context.Context, id *int64) (*gorm.Facility, error) {
return gm.RetrieveFacilityFn(ctx, id)
}

// GetFacilities mocks the implementation of `gorm's` GetFacilities method.
Expand Down
6 changes: 3 additions & 3 deletions pkg/onboarding/infrastructure/database/postgres/gorm/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ import (

// Query contains all the db query methods
type Query interface {
Retrieve(id *int64) (*Facility, error)
RetrieveFacility(ctx context.Context, id *int64) (*Facility, error)
GetFacilities(ctx context.Context) ([]Facility, error)
}

// Retrieve fetches a single facility
func (db *PGInstance) Retrieve(id *int64) (*Facility, error) {
// RetrieveFacility fetches a single facility
func (db *PGInstance) RetrieveFacility(ctx context.Context, id *int64) (*Facility, error) {
var facility Facility
if err := db.DB.Where(&Facility{FacilityID: id}).First(&facility).Error; err != nil {
return nil, fmt.Errorf("failed to get facility by ID %v: %v", id, err)
Expand Down
25 changes: 23 additions & 2 deletions pkg/onboarding/infrastructure/database/postgres/mock/pg_mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ import (

// PostgresMock struct implements mocks of `postgres's` internal methods.
type PostgresMock struct {
CreateFacilityFn func(ctx context.Context, facility *dto.FacilityInput) (*domain.Facility, error)
GetFacilitiesFn func(ctx context.Context) ([]*domain.Facility, error)
CreateFacilityFn func(ctx context.Context, facility *dto.FacilityInput) (*domain.Facility, error)
GetFacilitiesFn func(ctx context.Context) ([]*domain.Facility, error)
RetrieveFacilityFn func(ctx context.Context, id *int64) (*domain.Facility, error)
}

// NewPostgresMock initializes a new instance of `GormMock` then mocking the case of success.
Expand Down Expand Up @@ -48,10 +49,30 @@ func NewPostgresMock() *PostgresMock {
},
}, nil
},
RetrieveFacilityFn: func(ctx context.Context, id *int64) (*domain.Facility, error) {
facilityID := int64(1)
name := "test-facility"
code := "t-100"
county := "test-county"
description := "test description"
return &domain.Facility{
ID: facilityID,
Name: name,
Code: code,
Active: true,
County: county,
Description: description,
}, nil
},
}
}

// CreateFacility mocks the implementation of `gorm's` CreateFacility method.
func (gm *PostgresMock) CreateFacility(ctx context.Context, facility *dto.FacilityInput) (*domain.Facility, error) {
return gm.CreateFacilityFn(ctx, facility)
}

// RetrieveFacility mocks the implementation of `gorm's` CreateFacility method.
func (gm *PostgresMock) RetrieveFacility(ctx context.Context, id *int64) (*domain.Facility, error) {
return gm.RetrieveFacilityFn(ctx, id)
}
13 changes: 13 additions & 0 deletions pkg/onboarding/infrastructure/database/postgres/pg_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,16 @@ func (d *OnboardingDb) GetFacilities(ctx context.Context) ([]*domain.Facility, e

return facility, nil
}

// RetrieveFacility gets a facility by ID from the database
func (d *OnboardingDb) RetrieveFacility(ctx context.Context, id *int64) (*domain.Facility, error) {
if id == nil {
return nil, fmt.Errorf("facility ID should be defined")
}
facilitySession, err := d.query.RetrieveFacility(ctx, id)
if err != nil {
return nil, fmt.Errorf("failed query and retrieve one facility: %s", err)
}

return d.mapFacilityObjectToDomain(facilitySession), nil
}
116 changes: 116 additions & 0 deletions pkg/onboarding/infrastructure/database/postgres/pg_retrieve_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package postgres

import (
"context"
"fmt"
"testing"

"github.com/savannahghi/onboarding-service/pkg/onboarding/application/dto"
"github.com/savannahghi/onboarding-service/pkg/onboarding/domain"
"github.com/savannahghi/onboarding-service/pkg/onboarding/infrastructure/database/postgres/gorm"
gormMock "github.com/savannahghi/onboarding-service/pkg/onboarding/infrastructure/database/postgres/gorm/mock"
)

func TestOnboardingDb_RetrieveFacility(t *testing.T) {
ctx := context.Background()

var fakeGorm = gormMock.NewGormMock()
d := NewOnboardingDb(fakeGorm, fakeGorm)

facilityInput := &dto.FacilityInput{
Name: "Kanairo One",
Code: "KN001",
County: "Kanairo",
Description: "This is just for mocking",
}

// Setup, create a facility
facility, err := d.CreateFacility(ctx, facilityInput)
if err != nil {
t.Errorf("failed to create new facility: %v", err)
}

id := facility.ID

invalidID := int64(-100)

type args struct {
ctx context.Context
id *int64
}
tests := []struct {
name string
args args
want *domain.Facility
wantErr bool
}{
{
name: "happy case - valid ID passed",
args: args{
ctx: ctx,
id: &id,
},
wantErr: false,
},
{
name: "sad case - no ID passed",
args: args{
ctx: ctx,
},
wantErr: true,
},
{
name: "sad case - invalid ID",
args: args{
ctx: ctx,
id: &invalidID,
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {

got, err := d.RetrieveFacility(ctx, tt.args.id)

if tt.name == "happy case - valid ID passed" {
fakeGorm.RetrieveFacilityFn = func(ctx context.Context, id *int64) (*gorm.Facility, error) {
return &gorm.Facility{
FacilityID: &facility.ID,
Name: facility.Name,
Code: facility.Code,
Active: facility.Active,
County: facility.County,
Description: facility.Description,
}, nil
}
}

if tt.name == "sad case - no ID passed" {
fakeGorm.RetrieveFacilityFn = func(ctx context.Context, id *int64) (*gorm.Facility, error) {
return nil, fmt.Errorf("failed to create facility")
}
}

if tt.name == "sad case - invalid ID" {
fakeGorm.RetrieveFacilityFn = func(ctx context.Context, id *int64) (*gorm.Facility, error) {
return nil, fmt.Errorf("failed to create facility")
}
}

if (err != nil) != tt.wantErr {
t.Errorf("OnboardingDb.RetrieveFacility() error = %v, wantErr %v", err, tt.wantErr)
return
}
if tt.wantErr && got != nil {
t.Errorf("expected facility to be nil for %v", tt.name)
return
}

if !tt.wantErr && got == nil {
t.Errorf("expected facility not to be nil for %v", tt.name)
return
}
})
}
}
16 changes: 10 additions & 6 deletions pkg/onboarding/infrastructure/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,25 +32,29 @@ func (f ServiceCreateImpl) CreateFacility(ctx context.Context, facility dto.Faci
return f.onboarding.CreateFacility(ctx, &facility)
}

// Query represents a contract that contains all `get` ops to the database
//
// All the contracts for get operations are assembled here
// Query contains all query methods
type Query interface {
RetrieveFacility(ctx context.Context, id *int64) (*domain.Facility, error)
GetFacilities(ctx context.Context) ([]*domain.Facility, error)
}

// ServiceQueryImpl represents create contract implementation object
// ServiceQueryImpl contains implementation for the Query interface
type ServiceQueryImpl struct {
onboarding pg.OnboardingDb
}

// NewServiceQueryImpl returns new instance of ServiceQueryImpl
func NewServiceQueryImpl(on pg.OnboardingDb) Query {
// NewServiceQueryImpl is the initializer for Service query
func NewServiceQueryImpl(on pg.OnboardingDb) *ServiceQueryImpl {
return &ServiceQueryImpl{
onboarding: on,
}
}

// RetrieveFacility is a repository implementation method for RetrieveFacility
func (q ServiceQueryImpl) RetrieveFacility(ctx context.Context, id *int64) (*domain.Facility, error) {
return q.onboarding.RetrieveFacility(ctx, id)
}

//GetFacilities is responsible for returning a slice of healthcare facilities in the platform.
func (q ServiceQueryImpl) GetFacilities(ctx context.Context) ([]*domain.Facility, error) {
return q.onboarding.GetFacilities(ctx)
Expand Down
1 change: 1 addition & 0 deletions pkg/onboarding/presentation/graph/facility.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ extend type Mutation {

extend type Query {
fetchFacilities: [Facility]
RetrieveFacility(id: Int!): Facility!
}
5 changes: 5 additions & 0 deletions pkg/onboarding/presentation/graph/facility.resolvers.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ func (r *queryResolver) FetchFacilities(ctx context.Context) ([]*domain.Facility
return r.interactor.FacilityUsecase.FetchFacilities(ctx)
}

func (r *queryResolver) RetrieveFacility(ctx context.Context, id int) (*domain.Facility, error) {
intID := int64(id)
return r.interactor.FacilityUsecase.RetrieveFacility(ctx, &intID)
}

// Mutation returns generated.MutationResolver implementation.
func (r *Resolver) Mutation() generated.MutationResolver { return &mutationResolver{r} }

Expand Down
Loading

0 comments on commit 971321e

Please sign in to comment.