Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BACK-2728] Tandem pump settings updates #680

Merged
merged 6 commits into from
Nov 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions data/types/settings/pump/bolus.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package pump

import (
"sort"

"github.com/tidepool-org/platform/data"
"github.com/tidepool-org/platform/structure"
structureValidator "github.com/tidepool-org/platform/structure/validator"
)

type Bolus struct {
Expand Down Expand Up @@ -53,3 +56,63 @@ func (b *Bolus) Normalize(normalizer data.Normalizer) {
b.Extended.Normalize(normalizer.WithReference("extended"))
}
}

type BolusMap map[string]*Bolus

func ParseBolusMap(parser structure.ObjectParser) *BolusMap {
if !parser.Exists() {
return nil
}
datum := NewBolusMap()
parser.Parse(datum)
return datum
}

func NewBolusMap() *BolusMap {
return &BolusMap{}
}

func (b *BolusMap) Parse(parser structure.ObjectParser) {
for _, reference := range parser.References() {
b.Set(reference, ParseBolus(parser.WithReferenceObjectParser(reference)))
}
}

func (b *BolusMap) Normalize(normalizer data.Normalizer) {
for _, name := range b.sortedNames() {
if datum := b.Get(name); datum != nil {
datum.Normalize(normalizer.WithReference(name))
}
}
}

func (b *BolusMap) Validate(validator structure.Validator) {
for _, name := range b.sortedNames() {
datumValidator := validator.WithReference(name)
if datum := b.Get(name); datum != nil {
datum.Validate(datumValidator)
} else {
datumValidator.ReportError(structureValidator.ErrorValueNotExists())
}
}
}

func (b *BolusMap) Get(name string) *Bolus {
if datumArray, exists := (*b)[name]; exists {
return datumArray
}
return nil
}

func (b *BolusMap) Set(name string, datum *Bolus) {
(*b)[name] = datum
}

func (b *BolusMap) sortedNames() []string {
names := []string{}
for name := range *b {
names = append(names, name)
}
sort.Strings(names)
return names
}
109 changes: 107 additions & 2 deletions data/types/settings/pump/bolus_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ var _ = Describe("Bolus", func() {
Context("Validate", func() {
DescribeTable("validates the datum",
func(mutator func(datum *pump.Bolus), expectedErrors ...error) {
datum := pumpTest.NewBolus()
datum := pumpTest.NewRandomBolus()
mutator(datum)
dataTypesTest.ValidateWithExpectedOrigins(datum, structure.Origins(), expectedErrors...)
},
Expand Down Expand Up @@ -75,7 +75,7 @@ var _ = Describe("Bolus", func() {
DescribeTable("normalizes the datum",
func(mutator func(datum *pump.Bolus)) {
for _, origin := range structure.Origins() {
datum := pumpTest.NewBolus()
datum := pumpTest.NewRandomBolus()
mutator(datum)
expectedDatum := pumpTest.CloneBolus(datum)
normalizer := dataNormalizer.New()
Expand All @@ -98,4 +98,109 @@ var _ = Describe("Bolus", func() {
)
})
})

Context("Boluses", func() {

Context("Validate", func() {
DescribeTable("validates the datum",
func(mutator func(datum *pump.BolusMap), expectedErrors ...error) {
datum := pump.NewBolusMap()
mutator(datum)
dataTypesTest.ValidateWithExpectedOrigins(datum, structure.Origins(), expectedErrors...)
},
Entry("succeeds",
func(datum *pump.BolusMap) {},
),
Entry("empty",
func(datum *pump.BolusMap) {
*datum = *pump.NewBolusMap()
},
),

Entry("single invalid",
func(datum *pump.BolusMap) {
invalid := pumpTest.NewRandomBolus()
invalid.AmountMaximum.Units = nil
datum.Set("one", invalid)
},
errorsTest.WithPointerSource(structureValidator.ErrorValueNotExists(), "/one/amountMaximum/units"),
),
Entry("single valid",
func(datum *pump.BolusMap) {
datum.Set("one", pumpTest.NewRandomBolus())
},
),
Entry("multiple valid",
func(datum *pump.BolusMap) {
datum.Set("one", pumpTest.NewRandomBolus())
datum.Set("two", pumpTest.NewRandomBolus())
datum.Set("three", pumpTest.NewRandomBolus())
},
),
Entry("multiple errors",
func(datum *pump.BolusMap) {
invalid := pumpTest.NewRandomBolus()
invalid.AmountMaximum.Units = nil

invalidThree := pumpTest.NewRandomBolus()
invalidThree.AmountMaximum.Value = nil

datum.Set("one", invalid)
datum.Set("two", pumpTest.NewRandomBolus())
datum.Set("three", invalidThree)
},
errorsTest.WithPointerSource(structureValidator.ErrorValueNotExists(), "/one/amountMaximum/units"),
errorsTest.WithPointerSource(structureValidator.ErrorValueNotExists(), "/three/amountMaximum/value"),
),
)
})
Context("Normalize", func() {
DescribeTable("normalizes the datum",
func(mutator func(datum *pump.BolusMap), expectator func(datum *pump.BolusMap, expectedDatum *pump.BolusMap)) {
for _, origin := range structure.Origins() {
datum := pumpTest.NewRandomBolusMap(1, 4)
mutator(datum)
expectedDatum := pumpTest.CloneBolusMap(datum)
normalizer := dataNormalizer.New()
Expect(normalizer).ToNot(BeNil())
datum.Normalize(normalizer.WithOrigin(origin))
Expect(normalizer.Error()).To(BeNil())
Expect(normalizer.Data()).To(BeEmpty())
if expectator != nil {
expectator(datum, expectedDatum)
}
Expect(datum).To(Equal(expectedDatum))
}
},
Entry("does not modify the datum",
func(datum *pump.BolusMap) {},
nil,
),
Entry("does not modify the datum; amountMaximum missing",
func(datum *pump.BolusMap) {
for name := range *datum {
(*(*datum)[name]).AmountMaximum = nil
}
},
nil,
),
Entry("does not modify the datum; calculator missing",
func(datum *pump.BolusMap) {
for name := range *datum {
(*(*datum)[name]).Calculator = nil
}
},
nil,
),
Entry("does not modify the datum; extended missing",
func(datum *pump.BolusMap) {
for name := range *datum {
(*(*datum)[name]).Extended = nil
}
},
nil,
),
)
})
})
})
12 changes: 12 additions & 0 deletions data/types/settings/pump/pump.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ type Pump struct {
BloodGlucoseTargetSchedule *BloodGlucoseTargetStartArray `json:"bgTarget,omitempty" bson:"bgTarget,omitempty"` // TODO: Move into BolusCalculator struct; rename bloodGlucoseTarget
BloodGlucoseTargetSchedules *BloodGlucoseTargetStartArrayMap `json:"bgTargets,omitempty" bson:"bgTargets,omitempty"` // TODO: Move into BolusCalculator struct; rename bloodGlucoseTargets
Bolus *Bolus `json:"bolus,omitempty" bson:"bolus,omitempty"`
Boluses *BolusMap `json:"boluses,omitempty" bson:"boluses,omitempty"`
CarbohydrateRatioSchedule *CarbohydrateRatioStartArray `json:"carbRatio,omitempty" bson:"carbRatio,omitempty"` // TODO: Move into BolusCalculator struct; rename carbohydrateRatio
CarbohydrateRatioSchedules *CarbohydrateRatioStartArrayMap `json:"carbRatios,omitempty" bson:"carbRatios,omitempty"` // TODO: Move into BolusCalculator struct; rename carbohydrateRatios
Display *Display `json:"display,omitempty" bson:"display,omitempty"`
Expand Down Expand Up @@ -85,6 +86,7 @@ func (p *Pump) Parse(parser structure.ObjectParser) {
p.BloodGlucoseTargetSchedule = ParseBloodGlucoseTargetStartArray(parser.WithReferenceArrayParser("bgTarget"))
p.BloodGlucoseTargetSchedules = ParseBloodGlucoseTargetStartArrayMap(parser.WithReferenceObjectParser("bgTargets"))
p.Bolus = ParseBolus(parser.WithReferenceObjectParser("bolus"))
p.Boluses = ParseBolusMap(parser.WithReferenceObjectParser("boluses"))
p.CarbohydrateRatioSchedule = ParseCarbohydrateRatioStartArray(parser.WithReferenceArrayParser("carbRatio"))
p.CarbohydrateRatioSchedules = ParseCarbohydrateRatioStartArrayMap(parser.WithReferenceObjectParser("carbRatios"))
p.Display = ParseDisplay(parser.WithReferenceObjectParser("display"))
Expand Down Expand Up @@ -147,9 +149,16 @@ func (p *Pump) Validate(validator structure.Validator) {
} else if p.BloodGlucoseTargetSchedules != nil {
p.BloodGlucoseTargetSchedules.Validate(validator.WithReference("bgTargets"), unitsBloodGlucose)
}

if p.Bolus != nil {
p.Bolus.Validate(validator.WithReference("bolus"))
if p.Boluses != nil {
validator.WithReference("boluses").ReportError(structureValidator.ErrorValueExists())
}
} else if p.Boluses != nil {
p.Boluses.Validate(validator.WithReference("boluses"))
}

if p.CarbohydrateRatioSchedule != nil {
p.CarbohydrateRatioSchedule.Validate(validator.WithReference("carbRatio"))
if p.CarbohydrateRatioSchedules != nil {
Expand Down Expand Up @@ -232,6 +241,9 @@ func (p *Pump) Normalize(normalizer data.Normalizer) {
if p.Bolus != nil {
p.Bolus.Normalize(normalizer.WithReference("bolus"))
}
if p.Boluses != nil {
p.Boluses.Normalize(normalizer.WithReference("boluses"))
}
if p.CarbohydrateRatioSchedule != nil {
p.CarbohydrateRatioSchedule.Normalize(normalizer.WithReference("carbRatio"))
}
Expand Down
46 changes: 41 additions & 5 deletions data/types/settings/pump/pump_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package pump_test

import (
"fmt"
"sort"

. "github.com/onsi/ginkgo/v2"
Expand Down Expand Up @@ -43,6 +44,7 @@ var _ = Describe("Pump", func() {
Expect(datum.BloodGlucoseTargetSchedule).To(BeNil())
Expect(datum.BloodGlucoseTargetSchedules).To(BeNil())
Expect(datum.Bolus).To(BeNil())
Expect(datum.Boluses).To(BeNil())
Expect(datum.CarbohydrateRatioSchedule).To(BeNil())
Expect(datum.CarbohydrateRatioSchedules).To(BeNil())
Expect(datum.Display).To(BeNil())
Expand Down Expand Up @@ -278,16 +280,49 @@ var _ = Describe("Pump", func() {
),
Entry("bolus missing",
pointer.FromString("mmol/L"),
func(datum *pump.Pump, unitsBloodGlucose *string) { datum.Bolus = nil },
func(datum *pump.Pump, unitsBloodGlucose *string) {
datum.Bolus = nil
},
),
Entry("bolus invalid",
pointer.FromString("mmol/L"),
func(datum *pump.Pump, unitsBloodGlucose *string) { datum.Bolus.Extended.Enabled = nil },
errorsTest.WithPointerSourceAndMeta(structureValidator.ErrorValueNotExists(), "/bolus/extended/enabled", pumpTest.NewMeta()),
func(datum *pump.Pump, unitsBloodGlucose *string) {
datum.Boluses = nil
datum.Bolus = pumpTest.NewRandomBolus()
datum.Bolus.Calculator.Enabled = nil
},
errorsTest.WithPointerSourceAndMeta(structureValidator.ErrorValueNotExists(), "/bolus/calculator/enabled", pumpTest.NewMeta()),
),
Entry("bolus valid",
pointer.FromString("mmol/L"),
func(datum *pump.Pump, unitsBloodGlucose *string) { datum.Bolus = pumpTest.NewBolus() },
func(datum *pump.Pump, unitsBloodGlucose *string) {
datum.Boluses = nil
datum.Bolus = pumpTest.NewRandomBolus()
},
),
Entry("boluses missing",
pointer.FromString("mmol/L"),
func(datum *pump.Pump, unitsBloodGlucose *string) { datum.Boluses = nil },
),
Entry("boluses invalid",
pointer.FromString("mmol/L"),
func(datum *pump.Pump, unitsBloodGlucose *string) {
datum.Bolus = nil
datum.Boluses = pumpTest.NewRandomBolusMap(2, 2)
(*datum.Boluses)[pumpTest.BolusName(1)].AmountMaximum.Units = nil
(*datum.Boluses)[pumpTest.BolusName(2)].Extended.Enabled = nil
(*datum.Boluses)[pumpTest.BolusName(1)].Calculator.Enabled = nil
},
errorsTest.WithPointerSourceAndMeta(structureValidator.ErrorValueNotExists(), fmt.Sprintf("/boluses/%s/amountMaximum/units", pumpTest.BolusName(1)), pumpTest.NewMeta()),
errorsTest.WithPointerSourceAndMeta(structureValidator.ErrorValueNotExists(), fmt.Sprintf("/boluses/%s/calculator/enabled", pumpTest.BolusName(1)), pumpTest.NewMeta()),
errorsTest.WithPointerSourceAndMeta(structureValidator.ErrorValueNotExists(), fmt.Sprintf("/boluses/%s/extended/enabled", pumpTest.BolusName(2)), pumpTest.NewMeta()),
),
Entry("boluses valid",
pointer.FromString("mmol/L"),
func(datum *pump.Pump, unitsBloodGlucose *string) {
datum.Bolus = nil
datum.Boluses = pumpTest.NewRandomBolusMap(1, 5)
},
),
Entry("carbohydrate ratio schedule and carbohydrate ratio schedules missing",
pointer.FromString("mmol/L"),
Expand Down Expand Up @@ -672,7 +707,8 @@ var _ = Describe("Pump", func() {
datum.BloodGlucoseTargetSchedules = nil
datum.BloodGlucoseTargetPhysicalActivity = dataBloodGlucose.NewTarget()
datum.BloodGlucoseTargetPreprandial = dataBloodGlucose.NewTarget()
datum.BloodGlucoseTargetSchedules = nil
datum.Boluses = nil
datum.Bolus = pumpTest.NewRandomBolus()
datum.Bolus.Extended.Enabled = nil
invalidCarbohydrateRatioSchedule := pumpTest.NewCarbohydrateRatioStartArray()
(*invalidCarbohydrateRatioSchedule)[0].Start = nil
Expand Down
34 changes: 32 additions & 2 deletions data/types/settings/pump/test/bolus.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
package test

import "github.com/tidepool-org/platform/data/types/settings/pump"
import (
"fmt"

func NewBolus() *pump.Bolus {
"github.com/tidepool-org/platform/data/types/settings/pump"
"github.com/tidepool-org/platform/test"
)

func NewRandomBolus() *pump.Bolus {
datum := pump.NewBolus()
datum.AmountMaximum = NewBolusAmountMaximum()
datum.Extended = NewBolusExtended()
datum.Calculator = NewBolusCalculator()
return datum
}

Expand All @@ -16,5 +22,29 @@ func CloneBolus(datum *pump.Bolus) *pump.Bolus {
clone := pump.NewBolus()
clone.AmountMaximum = CloneBolusAmountMaximum(datum.AmountMaximum)
clone.Extended = CloneBolusExtended(datum.Extended)
clone.Calculator = CloneBolusCalculator(datum.Calculator)
return clone
}

func BolusName(index int) string {
return fmt.Sprintf("bolus-%d", index)
}

func NewRandomBolusMap(minimumLength int, maximumLength int) *pump.BolusMap {
datum := pump.NewBolusMap()
for count := test.RandomIntFromRange(minimumLength, maximumLength); count > 0; count-- {
datum.Set(BolusName(count), NewRandomBolus())
}
return datum
}

func CloneBolusMap(datum *pump.BolusMap) *pump.BolusMap {
if datum == nil {
return nil
}
clone := pump.NewBolusMap()
for k, v := range *datum {
(*clone)[k] = CloneBolus(v)
}
return clone
}
3 changes: 2 additions & 1 deletion data/types/settings/pump/test/pump.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func NewPump(unitsBloodGlucose *string) *pump.Pump {
datum.BloodGlucoseTargetPreprandial = dataBloodGlucoseTest.RandomTarget(unitsBloodGlucose)
datum.BloodGlucoseTargetSchedules = pump.NewBloodGlucoseTargetStartArrayMap()
datum.BloodGlucoseTargetSchedules.Set(scheduleName, RandomBloodGlucoseTargetStartArray(unitsBloodGlucose))
datum.Bolus = NewBolus()
datum.Boluses = NewRandomBolusMap(2, 4)
datum.CarbohydrateRatioSchedules = pump.NewCarbohydrateRatioStartArrayMap()
datum.CarbohydrateRatioSchedules.Set(scheduleName, NewCarbohydrateRatioStartArray())
datum.Display = NewDisplay()
Expand Down Expand Up @@ -86,6 +86,7 @@ func ClonePump(datum *pump.Pump) *pump.Pump {
clone.BloodGlucoseTargetSchedule = CloneBloodGlucoseTargetStartArray(datum.BloodGlucoseTargetSchedule)
clone.BloodGlucoseTargetSchedules = CloneBloodGlucoseTargetStartArrayMap(datum.BloodGlucoseTargetSchedules)
clone.Bolus = CloneBolus(datum.Bolus)
clone.Boluses = CloneBolusMap(datum.Boluses)
clone.CarbohydrateRatioSchedule = CloneCarbohydrateRatioStartArray(datum.CarbohydrateRatioSchedule)
clone.CarbohydrateRatioSchedules = CloneCarbohydrateRatioStartArrayMap(datum.CarbohydrateRatioSchedules)
clone.Display = CloneDisplay(datum.Display)
Expand Down