Skip to content

Commit

Permalink
Merge pull request #1407 from CMS-Enterprise/task/MINT-3157_data_exch…
Browse files Browse the repository at this point in the history
…ange_data_loader

[MINT-3157] Plan Data Exchange Data Loader
  • Loading branch information
StevenWadeOddball authored Oct 11, 2024
2 parents 3a0ad1f + cb9cf1d commit 57538b1
Show file tree
Hide file tree
Showing 9 changed files with 212 additions and 9 deletions.
2 changes: 1 addition & 1 deletion pkg/graph/resolvers/activity.resolvers.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 1 addition & 3 deletions pkg/graph/resolvers/model_plan.resolvers.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions pkg/graph/resolvers/plan_data_exchange_approach.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package resolvers

import (
"context"
"fmt"
"time"

"github.com/google/uuid"
"go.uber.org/zap"

"github.com/cms-enterprise/mint-app/pkg/authentication"
"github.com/cms-enterprise/mint-app/pkg/storage/loaders"

"github.com/cms-enterprise/mint-app/pkg/models"
"github.com/cms-enterprise/mint-app/pkg/storage"
Expand Down Expand Up @@ -77,3 +79,8 @@ func PlanDataExchangeApproachUpdate(
retDataExchangeApproach, err := storage.PlanDataExchangeApproachUpdate(store, logger, existing)
return retDataExchangeApproach, err
}

// PlanDataExchangeApproachGetByModelPlanIDLoader calls a data loader to batch fetching a a plan data exchange object that corresponds to a model plan
func PlanDataExchangeApproachGetByModelPlanIDLoader(ctx context.Context, modelPlanID uuid.UUID) (*models.PlanDataExchangeApproach, error) {
return loaders.PlanDataExchangeApproach.ByModelPlanID.Load(ctx, modelPlanID)
}
41 changes: 40 additions & 1 deletion pkg/graph/resolvers/plan_data_exchange_approach_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,45 @@
package resolvers

import "github.com/cms-enterprise/mint-app/pkg/models"
import (
"github.com/google/uuid"

"github.com/cms-enterprise/mint-app/pkg/models"
"github.com/cms-enterprise/mint-app/pkg/storage/loaders"
)

func (suite *ResolverSuite) TestPlanDataExchangeApproachGetByModelPlanIDLoader() {

plan1 := suite.createModelPlan("model plan 1")
approach1, err := PlanDataExchangeApproachGetByModelPlanIDLoader(suite.testConfigs.Context, plan1.ID)
suite.NoError(err)
suite.EqualValues(plan1.ID, approach1.ModelPlanID)
plan2 := suite.createModelPlan("model plan 2")

approach2, err := PlanDataExchangeApproachGetByModelPlanIDLoader(suite.testConfigs.Context, plan2.ID)
suite.NoError(err)
suite.EqualValues(plan2.ID, approach2.ModelPlanID)
plan3 := suite.createModelPlan("model plan 3")
approach3, err := PlanDataExchangeApproachGetByModelPlanIDLoader(suite.testConfigs.Context, plan3.ID)
suite.NoError(err)
suite.EqualValues(plan3.ID, approach3.ModelPlanID)
expectedResults := []loaders.KeyAndExpected[uuid.UUID, uuid.UUID]{
{Key: plan1.ID, Expected: approach1.ID},
{Key: plan2.ID, Expected: approach2.ID},
{Key: plan3.ID, Expected: approach3.ID},
}

verifyFunc := func(data *models.PlanDataExchangeApproach, expected uuid.UUID) bool {
if suite.NotNil(data) {
return suite.EqualValues(expected, data.ID)
}
return false

}

loaders.VerifyLoaders[uuid.UUID, *models.PlanDataExchangeApproach, uuid.UUID](suite.testConfigs.Context, &suite.Suite, loaders.PlanDataExchangeApproach.ByModelPlanID,
expectedResults, verifyFunc)

}

func (suite *ResolverSuite) TestPlanDataExchangeApproachGetByID() {
plan1 := suite.createModelPlan("model plan 1")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
WITH QUERIED_IDS AS (
/*Translate the input to a table */
SELECT UNNEST(CAST(:model_plan_ids AS UUID[])) AS model_plan_id
)

SELECT
approach.id,
approach.model_plan_id,
approach.data_to_collect_from_participants,
approach.data_to_collect_from_participants_reports_details,
approach.data_to_collect_from_participants_other,
approach.data_will_not_be_collected_from_participants,
approach.data_to_collect_from_participants_note,
approach.data_to_send_to_participants,
approach.data_to_send_to_participants_note,
approach.does_need_to_make_multi_payer_data_available,
approach.anticipated_multi_payer_data_availability_use_case,
approach.does_need_to_make_multi_payer_data_available_note,
approach.does_need_to_collect_and_aggregate_multi_source_data,
approach.multi_source_data_to_collect,
approach.multi_source_data_to_collect_other,
approach.does_need_to_collect_and_aggregate_multi_source_data_note,
approach.will_implement_new_data_exchange_methods,
approach.new_data_exchange_methods_description,
approach.new_data_exchange_methods_note,
approach.additional_data_exchange_considerations_description,
approach.created_by,
approach.created_dts,
approach.modified_by,
approach.modified_dts,
approach.marked_complete_by,
approach.marked_complete_dts,
approach.status
FROM plan_data_exchange_approach AS approach
INNER JOIN QUERIED_IDS ON approach.model_plan_id = QUERIED_IDS.model_plan_id
14 changes: 10 additions & 4 deletions pkg/sqlqueries/plan_data_exchange_approach.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,23 @@ var planDataExchangeApproachGetByIDSQL string
//go:embed SQL/plan_data_exchange_approach/get_by_model_plan_id.sql
var planDataExchangeApproachGetByModelPlanIDSQL string

//go:embed SQL/plan_data_exchange_approach/get_by_model_plan_id_LOADER.sql
var planDataExchangeApproachGetByModelPlanIDLoaderSQL string

type planDataExchangeApproachScripts struct {
Create string
Update string
GetByID string
GetByModelPlanID string
//Uses a list of model_plan_ids to return a corresponding list of data exchange approach objects
GetByModelPlanIDLoader string
}

// PlanDataExchangeApproach houses all the SQL scripts for the plan_data_exchange_approach table
var PlanDataExchangeApproach = planDataExchangeApproachScripts{
Create: planDataExchangeApproachCreateSQL,
Update: planDataExchangeApproachUpdateSQL,
GetByID: planDataExchangeApproachGetByIDSQL,
GetByModelPlanID: planDataExchangeApproachGetByModelPlanIDSQL,
Create: planDataExchangeApproachCreateSQL,
Update: planDataExchangeApproachUpdateSQL,
GetByID: planDataExchangeApproachGetByIDSQL,
GetByModelPlanID: planDataExchangeApproachGetByModelPlanIDSQL,
GetByModelPlanIDLoader: planDataExchangeApproachGetByModelPlanIDLoaderSQL,
}
60 changes: 60 additions & 0 deletions pkg/storage/loaders/loader_wrapper_test_utilities.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package loaders

import (
"context"
"fmt"

"github.com/stretchr/testify/suite"
"golang.org/x/sync/errgroup"
)

type KeyAndExpected[K comparable, Expected any] struct {
Key K
Expected Expected
}

// verifyLoader is meant to be called by VerifyLoaders to validate a result set of data, and the returned results
func verifyLoader[K comparable, V any, Expected any](ctx context.Context, suite *suite.Suite, loaderWrapper LoaderWrapper[K, V], key K, expected Expected, validateResult func(V, Expected) bool) bool {
res, err := loaderWrapper.Load(ctx, key)
suite.NoError(err)
return validateResult(res, expected)
}

// VerifyLoaders validates a data loader. It takes a loaderWrapper and a list of expected results and loads the data loader asynchronously. This ensures that the dataloader is returning the results as expected
/*
example
expectedResults := []loaders.KeyAndExpected[uuid.UUID, uuid.UUID]{
{Key: model_plan1.ID, Expected: approach1.ID},
{Key: model_plan2.ID, Expected: approach2.ID},
{Key: model_plan3.ID, Expected: approach3.ID},
}
verifyFunc := func(data *models.PlanDataExchangeApproach, expected uuid.UUID) bool {
if suite.NotNil(data) {
return suite.EqualValues(expected, data.ID)
}
return false
}
loaders.VerifyLoaders[uuid.UUID, *models.PlanDataExchangeApproach, uuid.UUID](suite.testConfigs.Context, &suite.Suite, loaders.PlanDataExchangeApproach.ByModelPlanID,
expectedResults, verifyFunc)
This example takes the model_plan_id keys, and specifies the expected values.
*/
func VerifyLoaders[K comparable, V any, Expected any](ctx context.Context, suite *suite.Suite, loaderWrapper LoaderWrapper[K, V], expectedResults []KeyAndExpected[K, Expected], validateResult func(V, Expected) bool) {
g, ctx := errgroup.WithContext(ctx)
for _, expected := range expectedResults {
g.Go(func() error {
passed := verifyLoader[K, V, Expected](ctx, suite, loaderWrapper, expected.Key, expected.Expected, validateResult)
if !passed {
return fmt.Errorf("dataloader verification function failed")
}
return nil
})
}
err := g.Wait()
suite.NoError(err)
}
41 changes: 41 additions & 0 deletions pkg/storage/loaders/plan_data_exchange_approach_loader.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package loaders

import (
"context"

"github.com/google/uuid"

"github.com/cms-enterprise/mint-app/pkg/appcontext"
"github.com/cms-enterprise/mint-app/pkg/models"
"github.com/cms-enterprise/mint-app/pkg/storage"

"github.com/graph-gophers/dataloader/v7"
)

// planDataExchangeApproachLoaders is a struct that holds LoaderWrappers related to Plan Data Exchange Approach
type planDataExchangeApproachLoaders struct {
// ByModelPlanID Gets a plan data exchange approach record associated with a model plan by the supplied model plan id
ByModelPlanID LoaderWrapper[uuid.UUID, *models.PlanDataExchangeApproach]
}

var PlanDataExchangeApproach = &planDataExchangeApproachLoaders{
ByModelPlanID: NewLoaderWrapper(batchPlanDataExchangeApproachByModelPlanID),
}

func batchPlanDataExchangeApproachByModelPlanID(ctx context.Context, modelPlanIDs []uuid.UUID) []*dataloader.Result[*models.PlanDataExchangeApproach] {
logger := appcontext.ZLogger(ctx)
loaders, err := Loaders(ctx)
if err != nil {
return errorPerEachKey[uuid.UUID, *models.PlanDataExchangeApproach](modelPlanIDs, err)
}

data, err := storage.PlanDataExchangeApproachGetByModelPlanIDLoader(loaders.DataReader.Store, logger, modelPlanIDs)
if err != nil {
return errorPerEachKey[uuid.UUID, *models.PlanDataExchangeApproach](modelPlanIDs, err)
}
getKeyFunc := func(data *models.PlanDataExchangeApproach) uuid.UUID {
return data.ModelPlanID
}
return oneToOneDataLoaderFunc(modelPlanIDs, data, getKeyFunc)

}
17 changes: 17 additions & 0 deletions pkg/storage/plan_data_exchange_approachStore.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
_ "embed"
"fmt"

"github.com/lib/pq"

"github.com/cms-enterprise/mint-app/pkg/sqlqueries"

"github.com/google/uuid"
Expand Down Expand Up @@ -56,3 +58,18 @@ func PlanDataExchangeApproachGetByModelPlanID(np sqlutils.NamedPreparer, _ *zap.
return sqlutils.GetProcedure[models.PlanDataExchangeApproach](np, sqlqueries.PlanDataExchangeApproach.GetByModelPlanID, utilitysql.CreateModelPlanIDQueryMap(modelPlanID))

}

// PlanDataExchangeApproachGetByModelPlanIDLoader returns the plan basics for a slice of model plan ids
func PlanDataExchangeApproachGetByModelPlanIDLoader(np sqlutils.NamedPreparer, _ *zap.Logger, modelPlanIDs []uuid.UUID) ([]*models.PlanDataExchangeApproach, error) {

args := map[string]interface{}{
"model_plan_ids": pq.Array(modelPlanIDs),
}

res, err := sqlutils.SelectProcedure[models.PlanDataExchangeApproach](np, sqlqueries.PlanDataExchangeApproach.GetByModelPlanIDLoader, args)
if err != nil {
return nil, err
}
return res, nil

}

0 comments on commit 57538b1

Please sign in to comment.