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

Allow legacy deduplication #741

Open
wants to merge 430 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
430 commits
Select commit Hold shift + click to select a range
235c05c
fix type
jh-bate Feb 1, 2024
fc353cb
BACK 2746
jh-bate Feb 7, 2024
0e6783e
tests moves to migration utils
jh-bate Feb 7, 2024
2d2ecb5
basic update tests
jh-bate Feb 7, 2024
bef257e
payload test
jh-bate Feb 7, 2024
8dcb33a
test for payload and annotations
jh-bate Feb 7, 2024
1b52af2
remove calc wizard from audit
jh-bate Feb 7, 2024
649bcf5
build mongo query form difference
jh-bate Feb 11, 2024
c70e95d
don't build diff on internal properties
jh-bate Feb 12, 2024
7011293
import order
jh-bate Feb 12, 2024
9a0548c
remove payload
jh-bate Feb 12, 2024
c27671a
check if cap set or not
jh-bate Feb 12, 2024
c46998b
set last update ID for select
jh-bate Feb 12, 2024
4f6c7cf
set id even when item not updated
jh-bate Feb 12, 2024
9115b92
don't write the updates yet
jh-bate Feb 12, 2024
9c87b14
switch to audit or update process
jh-bate Feb 12, 2024
329af8c
filter out inner payload changes
jh-bate Feb 13, 2024
4915b2e
errors per type
jh-bate Feb 13, 2024
b41fbdf
type specific validator changes
jh-bate Feb 13, 2024
f7334c5
fix payload type
jh-bate Feb 13, 2024
4a0fe93
parse for specific types
jh-bate Feb 13, 2024
56816a7
move percent so it is deleted in update
jh-bate Feb 13, 2024
8912a52
try to remove empty payload
jh-bate Feb 13, 2024
204ff7e
remove payload
jh-bate Feb 13, 2024
ace6538
type specific updates
jh-bate Feb 13, 2024
203427e
allow updates
jh-bate Feb 13, 2024
87a97df
log if auditing
jh-bate Feb 13, 2024
da9bbe9
remove needless logging
jh-bate Feb 13, 2024
5941ddc
tests and updates
jh-bate Feb 13, 2024
fb540b9
trying to sort empty payload
jh-bate Feb 13, 2024
222cc52
generic object also
jh-bate Feb 13, 2024
7094887
moar debugging for cbg
jh-bate Feb 13, 2024
d0c9e35
empty payload removed
jh-bate Feb 13, 2024
7e54587
fix reservoirchange status
jh-bate Feb 13, 2024
85b1514
test BuildPlatformDatum
jh-bate Feb 14, 2024
94eafcb
fix for cgmSettings precision
jh-bate Feb 14, 2024
5456c14
parse previousOverride allow string alarm status
jh-bate Feb 14, 2024
b075de8
hold off writing errors until the end
jh-bate Feb 14, 2024
3f97d79
all errors to JSON at once
jh-bate Feb 14, 2024
d44dd31
errors as we write updates smaller files
jh-bate Feb 14, 2024
f02369d
cleaner error logs and grouping
jh-bate Feb 14, 2024
9d7a0e5
limit per group
jh-bate Feb 14, 2024
8661d31
write errors as pretty JSON
jh-bate Feb 15, 2024
fa9d7b9
json formatting for errors
jh-bate Feb 15, 2024
86087d5
generate ans set hash
jh-bate Feb 15, 2024
ca18a36
new line after each
jh-bate Feb 15, 2024
db165bd
all tests
jh-bate Feb 20, 2024
03aaf80
output diff in batches also
jh-bate Feb 20, 2024
314f53b
group updates by type for diff
jh-bate Feb 21, 2024
57b99b0
flush diffs at end
jh-bate Feb 21, 2024
bba5b9f
remove audit, set _deduplicator correctly on updates
jh-bate Feb 21, 2024
6474069
filter out empty updates
jh-bate Feb 21, 2024
fb10961
reset after written
jh-bate Feb 21, 2024
1ede9ee
debug status changes
jh-bate Feb 21, 2024
b858997
status ID checks
jh-bate Feb 21, 2024
e4ff330
debug for bolusID on wizard
jh-bate Feb 21, 2024
88eeba9
changes for wizard datum with bolus string
jh-bate Feb 22, 2024
53f0321
fixes for pathing
jh-bate Feb 22, 2024
b35d332
update has both an apply and revert
jh-bate Feb 27, 2024
f8a5fb3
fix log paths
jh-bate Feb 27, 2024
189441f
write line by line
jh-bate Feb 27, 2024
5cb3cba
set revert for logging
jh-bate Feb 28, 2024
4249efb
attempt to get vaild bg updates
jh-bate Feb 28, 2024
cc5c310
update targetObj setting
jh-bate Feb 28, 2024
81dd29d
fix for wizard target types
jh-bate Feb 28, 2024
015a574
logging
jh-bate Feb 28, 2024
03b7482
fix when units are invalid
jh-bate Feb 28, 2024
3fbb935
write revert data for each datum
jh-bate Feb 28, 2024
c5b5ddc
fix empty payload issue
jh-bate Feb 29, 2024
06b4f6d
test pumpSettings with bolus
jh-bate Feb 29, 2024
e4b3806
fix so wizard bolus is validated
jh-bate Feb 29, 2024
8e8c99a
updates and tests for payload and annotations
jh-bate Mar 4, 2024
130f4b2
update for deviceEvent with status
jh-bate Mar 4, 2024
a993085
test debug
jh-bate Mar 4, 2024
ad5bb24
status deviceEvent test
jh-bate Mar 5, 2024
bc7fff8
start of SleepSchedule test
jh-bate Mar 5, 2024
c23f149
tests for annotations and sleepSchedules
jh-bate Mar 5, 2024
9b6e227
only write audit log if a dry run
jh-bate Mar 5, 2024
beecdc5
update logging
jh-bate Mar 5, 2024
5b0b505
migration updates
jh-bate Mar 6, 2024
821637c
allow for start of revert changes
jh-bate Mar 6, 2024
69af971
error filtering
jh-bate Mar 6, 2024
f067e66
show percent processed
jh-bate Mar 7, 2024
2fe84d9
show percent process
jh-bate Mar 7, 2024
eb44639
cleanup error checking
jh-bate Mar 7, 2024
659bc2d
query updates for filtering
jh-bate Mar 11, 2024
1fffd0a
revert of changes
jh-bate Mar 11, 2024
8855e7e
general writeLastProcessed for audit, process and revert
jh-bate Mar 12, 2024
0d0ea1d
updates for apply rollback
jh-bate Mar 12, 2024
b8f45f5
rollback cmds
jh-bate Mar 12, 2024
57ba478
log only if commands are found
jh-bate Mar 12, 2024
4db4699
update logging details
jh-bate Mar 12, 2024
40a2ce2
Merge branch 'master' into jf_migration_tests
jh-bate Mar 12, 2024
5ab390b
naming updates for consistency
jh-bate Mar 12, 2024
eab3f8d
rework for testing
jh-bate Mar 14, 2024
c107334
migration tests
jh-bate Mar 20, 2024
1729d97
Merge branch 'master' into jf_migration_tests
jh-bate Mar 20, 2024
eef58bd
tests compare original vs rolledback item
jh-bate Mar 20, 2024
e85a447
move out mongo instance checker for easier testing
jh-bate Mar 21, 2024
0cc6b64
make internal
jh-bate Mar 21, 2024
af0214d
not nil or empty
jh-bate Mar 26, 2024
54d6e16
ensure all config is set
jh-bate Mar 26, 2024
52226ec
reset data if not writing to disk
jh-bate Mar 26, 2024
329a62c
write as we go
jh-bate Mar 26, 2024
8b4bcd8
don't persist raw data
jh-bate Mar 26, 2024
0bafed4
cleanup
jh-bate Mar 26, 2024
5e72371
allow to build error summary
jh-bate Apr 1, 2024
5a4a210
fixes to generate log summary
jh-bate Apr 1, 2024
d43e44c
roll log file every 6 hours
jh-bate Apr 1, 2024
582b55f
format dateContainer for logs
jh-bate Apr 1, 2024
8ebb807
fix err check
jh-bate Apr 1, 2024
5dcb098
report run details
jh-bate Apr 2, 2024
b34056d
show query and config
jh-bate Apr 2, 2024
cbf581a
cleanup settings
jh-bate Apr 2, 2024
f6770c0
linting
jh-bate Apr 3, 2024
cbc0f1e
optional splitting of the logs
jh-bate Apr 3, 2024
45b4a57
remove log splitting - will just ensure disk space
jh-bate Apr 3, 2024
b34ec12
cleanup cbg parsing of unused fields
jh-bate Apr 9, 2024
e1c1e65
updates for drilling into specific details
jh-bate Apr 10, 2024
1f5a00f
Merge branch 'master' into jf_migration_tests
jh-bate Apr 15, 2024
be287f9
fix and test for cgmSettings
jh-bate Apr 16, 2024
31d4d6b
move comment
jh-bate Apr 16, 2024
ee8050b
Jf migration history (#712)
jh-bate Apr 25, 2024
b7d579e
LegacyIdentityFields for hash
jh-bate May 29, 2024
176ba64
cleanup creation and tests for legacy id fields
jh-bate May 29, 2024
0ba107e
cleanup for getting of legacy fields
jh-bate May 30, 2024
a50175b
Merge branch 'master' into jf_deduplication
jh-bate Jun 3, 2024
fb425d0
changes for migration of jellyfish upload records
jh-bate Jun 4, 2024
1597c04
Merge branch 'master' into jf_deduplication
jh-bate Jun 18, 2024
b5ff5d0
update devices
jh-bate Jun 20, 2024
59e50d3
cleanup
jh-bate Jun 25, 2024
3c8d3e6
fix field types
jh-bate Jun 25, 2024
4db0383
Merge branch 'master' into jf_deduplication
jh-bate Jun 25, 2024
1f63fc7
updates from previous review
jh-bate Jun 25, 2024
8d15dc8
review updates
jh-bate Jun 25, 2024
0f7dda1
review updates
jh-bate Jun 26, 2024
acd4869
fix nil check
jh-bate Jun 26, 2024
ba2b664
simple dataset comparison tool
jh-bate Jun 27, 2024
5b4d580
fix flag name
jh-bate Jun 27, 2024
23f946b
debug logging
jh-bate Jun 27, 2024
2bbde7c
error checking
jh-bate Jun 27, 2024
2ccdb24
logging for diffs
jh-bate Jun 27, 2024
b6c4ea1
dont clean datasets for compare
jh-bate Jun 27, 2024
2929216
differ updates
jh-bate Jun 27, 2024
aaf274b
trying other options
jh-bate Jun 27, 2024
5151712
limit
jh-bate Jun 27, 2024
03778dd
remove cruft from compare datasets
jh-bate Jun 27, 2024
7a625c4
remove fields not required for comparison
jh-bate Jul 1, 2024
412154a
run diff for a dataset in batches
jh-bate Jul 1, 2024
3b93bb6
cleanup reporting
jh-bate Jul 1, 2024
ae89fca
Merge branch 'master' into jf_deduplication
jh-bate Jul 1, 2024
7a16063
allow finding of blobs
jh-bate Jul 2, 2024
1991df4
update sort
jh-bate Jul 2, 2024
0886a7c
group data by type
jh-bate Jul 2, 2024
5d75629
report type
jh-bate Jul 2, 2024
72521ae
allow to pass datatype of upload to compare
jh-bate Jul 2, 2024
54583a0
clean out revision form compare
jh-bate Jul 2, 2024
6a74788
look at 4 smaller batches to compare
jh-bate Jul 2, 2024
14d9ee8
depending on amount of data process a subset or all data points
jh-bate Jul 2, 2024
46a84dc
batch diffs
jh-bate Jul 2, 2024
ae8d571
fix for fetching blob ids
jh-bate Jul 2, 2024
75c5cab
include deviceId with blob details
jh-bate Jul 2, 2024
dd87ea2
rename blobId
jh-bate Jul 2, 2024
1ed373e
include bolus deliveryContext
jh-bate Jul 2, 2024
d4e573c
add field keys
jh-bate Jul 2, 2024
c3725de
allow day of week to be case insensitive
jh-bate Jul 3, 2024
0ab37ed
test for day of week validation
jh-bate Jul 3, 2024
361b697
updates for dataset verification tool
jh-bate Jul 3, 2024
6cb3072
seperate file name and path
jh-bate Jul 3, 2024
36ca339
also group by subtype if present
jh-bate Jul 4, 2024
e354180
simplify compare sets
jh-bate Jul 4, 2024
6b74c8e
diff row by row
jh-bate Jul 4, 2024
033e3a0
diff datum by datum
jh-bate Jul 4, 2024
092dead
find missing datum if there are any
jh-bate Jul 4, 2024
9206307
allow basal suspend to have no upper bound
jh-bate Jul 8, 2024
2828e2f
cleanup LegacyIDFields setup
jh-bate Jul 10, 2024
8a63758
expand device list
jh-bate Jul 10, 2024
4218656
have generic raw object for units and value (#749)
jh-bate Jul 11, 2024
5b63d5e
Merge branch 'master' into jf_deduplication
jh-bate Jul 11, 2024
c6ac9ad
requirement updates
jh-bate Jul 11, 2024
16fdcb8
updates for deps
jh-bate Jul 11, 2024
387299a
pull blob user also
jh-bate Jul 12, 2024
452362e
device blob path, check which is largest for finding missing records
jh-bate Jul 12, 2024
f2307df
use ConvertCompatibleTypes so non-existent diffs not reported
jh-bate Jul 16, 2024
f5a2190
ability to filter out expected differences
jh-bate Jul 16, 2024
cfbaffd
update tests and filtering
jh-bate Jul 16, 2024
7aaced7
write blob data to file
jh-bate Jul 16, 2024
db52ff6
format blob data and include helper script
jh-bate Jul 17, 2024
eb023c1
find missing datum
jh-bate Jul 19, 2024
aadfec3
tests for finding missing vals
jh-bate Jul 21, 2024
b32d1b9
CompareDatasets and CompareDatasetDatums updates
jh-bate Jul 23, 2024
ef7c733
cleanup CompareDatasets
jh-bate Jul 24, 2024
db10afe
fix for duplicates CompareDatasets
jh-bate Jul 24, 2024
8fcba34
updates to find missing datums from platform records
jh-bate Jul 24, 2024
6d0cd04
combine all verification code and scripts
jh-bate Jul 29, 2024
755103a
keep uploadId and _active
jh-bate Jul 30, 2024
8205240
cleanup and allow query of datasets for deduping
jh-bate Jul 30, 2024
f7960eb
fix tandem model
jh-bate Jul 30, 2024
f1e15a6
Legacy Field Updates
jh-bate Jul 30, 2024
4ac6f5c
expand type LegacyIdentityFields tests
jh-bate Jul 31, 2024
f67d41c
fix test
jh-bate Jul 31, 2024
8872788
updates for DeviceDeactivateHashName with different versions
jh-bate Aug 1, 2024
275cf7a
refine setting of DeviceDeactivateHashVersion
jh-bate Aug 1, 2024
5f6398c
no-op on base LegacyIdentityFields
jh-bate Aug 2, 2024
ed43af9
fix test
jh-bate Aug 2, 2024
0a5c1cc
LegacyIdentityFields returns base fields
jh-bate Aug 2, 2024
fe8a85a
sorting out LegacyIdentityFields error
jh-bate Aug 4, 2024
5ddf7ec
set base LegacyIdentityFields as type, deviceId and time
jh-bate Aug 4, 2024
8a20208
modify time format
jh-bate Aug 5, 2024
e6dce6c
fix format to keep trailing zeros
jh-bate Aug 5, 2024
4541d0d
fix test formatting
jh-bate Aug 5, 2024
5279675
version naming and debug
jh-bate Aug 6, 2024
d51f3ca
start using _groupId for legacy hash
jh-bate Aug 7, 2024
74290b3
try to find last upload if a legacy device
jh-bate Aug 7, 2024
c9ed224
more error details
jh-bate Aug 7, 2024
7588edf
debug
jh-bate Aug 7, 2024
1412b4c
fix error check
jh-bate Aug 7, 2024
079b214
allow checking based on _deduplicator
jh-bate Aug 8, 2024
6a71e3d
extend insulin range to 250 for consistency
jh-bate Aug 8, 2024
3a32367
expand device model list
jh-bate Aug 9, 2024
4ede27e
helper script updates
jh-bate Aug 12, 2024
4876b11
Merge branch 'master' into jf_deduplication
jh-bate Aug 14, 2024
390fce1
naming
jh-bate Aug 20, 2024
8d2c0ff
script updates from testing
jh-bate Aug 20, 2024
135f3e9
Merge branch 'master' into jf_deduplication
jh-bate Aug 20, 2024
f75d16c
testing updates
jh-bate Sep 2, 2024
5eb1d3b
Merge branch 'master' into jf_deduplication
jh-bate Sep 2, 2024
e6c765d
fix hash tests
jh-bate Sep 2, 2024
7f84ab8
include userID in device data query
jh-bate Sep 5, 2024
5c6b8fd
set raw data from CBG, fix issue with missing id for SMBG
jh-bate Sep 10, 2024
04aac95
Merge branch 'master' into jf_deduplication
jh-bate Sep 11, 2024
5007049
Merge branch 'master' into jf_deduplication
jh-bate Sep 17, 2024
cabab88
updates to helper files
jh-bate Sep 23, 2024
5ddf372
Merge branch 'master' into jf_deduplication
jh-bate Sep 23, 2024
5dbfcab
increase carb ratio based on findings from prod data testing (#767)
jh-bate Sep 24, 2024
d52e9d6
remove correlation with expectedExtended and expectedDuration (#778)
jh-bate Oct 3, 2024
e4d88ab
Merge branch 'master' into jf_deduplication
jh-bate Oct 8, 2024
5d39959
review updates
jh-bate Oct 21, 2024
8328218
update to use IdentityFields(version string) ([]string, error)
jh-bate Oct 21, 2024
f87f048
review updates
jh-bate Oct 22, 2024
086b4fd
cleanup
jh-bate Oct 22, 2024
7492d22
cleanup identityFields creation
jh-bate Oct 22, 2024
1c6731f
review updates
jh-bate Oct 22, 2024
f0cc214
Merge branch 'master' into jf_deduplication
jh-bate Oct 22, 2024
0209295
Merge branch 'master' into jf_deduplication
jh-bate Oct 30, 2024
6d84df2
updates from merge
jh-bate Oct 30, 2024
adbd24f
review updates
jh-bate Nov 11, 2024
77ffcca
Merge branch 'master' into jf_deduplication
jh-bate Nov 11, 2024
1a090b0
update import for consistency
jh-bate Nov 11, 2024
f715153
test updates
jh-bate Nov 11, 2024
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
8 changes: 4 additions & 4 deletions data/blood/glucose/test/glucose.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ func RandomUnits() string {
func ExpectRaw(raw *metadata.Metadata, expectedRaw *metadata.Metadata) {
if expectedRaw != nil {
gomega.Expect(raw).ToNot(gomega.BeNil())
if expectedRaw.Get("units") == nil {
if units := expectedRaw.Get("units"); units == nil {
gomega.Expect(raw.Get("units")).To(gomega.BeNil())
} else {
gomega.Expect(raw.Get("units")).To(gomega.Equal(expectedRaw.Get("units")))
gomega.Expect(raw.Get("units")).To(gomega.Equal(units))
}
if expectedRaw.Get("value") == nil {
if value := expectedRaw.Get("value"); value == nil {
gomega.Expect(raw.Get("value")).To(gomega.BeNil())
} else {
gomega.Expect(raw.Get("value")).To(gomega.Equal(expectedRaw.Get("value")))
gomega.Expect(raw.Get("value")).To(gomega.Equal(value))
}
} else {
gomega.Expect(raw).To(gomega.BeNil())
Expand Down
2 changes: 1 addition & 1 deletion data/data_set.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ func (d *DataSetClient) Validate(validator structure.Validator) {

type DataSetFilter struct {
ClientName *string
IsLegacy *bool
LegacyOnly *bool
Deleted *bool
DeviceID *string
}
Expand Down
3 changes: 1 addition & 2 deletions data/datum.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ type Datum interface {
Validate(validator structure.Validator)
Normalize(normalizer Normalizer)

IdentityFields() ([]string, error)
LegacyIdentityFields() ([]string, error)
IdentityFields(version string) ([]string, error)

GetOrigin() *origin.Origin
GetPayload() *metadata.Metadata
Expand Down
2 changes: 0 additions & 2 deletions data/deduplicator/deduplicator/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ func NewBase(name string, version string) (*Base, error) {
}
if version == "" {
return nil, errors.New("version is missing")
} else if !net.IsValidSemanticVersion(version) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why removed?

return nil, errors.New("version is invalid")
}

return &Base{
Expand Down
12 changes: 4 additions & 8 deletions data/deduplicator/deduplicator/base_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@ var _ = Describe("Base", func() {

BeforeEach(func() {
name = netTest.RandomReverseDomain()
version = netTest.RandomSemanticVersion()
version = test.RandomStringFromArray([]string{
dataDeduplicatorDeduplicator.DeviceDeactivateHashVersionCurrent,
dataDeduplicatorDeduplicator.DeviceDeactivateHashVersionLegacy,
})
})

Context("NewBase", func() {
Expand All @@ -50,13 +53,6 @@ var _ = Describe("Base", func() {
Expect(deduplicator).To(BeNil())
})

It("returns an error when version is invalid", func() {
version = "invalid"
deduplicator, err := dataDeduplicatorDeduplicator.NewBase(name, version)
Expect(err).To(MatchError("version is invalid"))
Expect(deduplicator).To(BeNil())
})

It("returns successfully", func() {
Expect(dataDeduplicatorDeduplicator.NewBase(name, version)).ToNot(BeNil())
})
Expand Down
40 changes: 20 additions & 20 deletions data/deduplicator/deduplicator/device_deactivate_hash.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,17 @@ import (

"github.com/tidepool-org/platform/data"
dataStore "github.com/tidepool-org/platform/data/store"
"github.com/tidepool-org/platform/data/types"
dataTypesUpload "github.com/tidepool-org/platform/data/types/upload"
"github.com/tidepool-org/platform/errors"
"github.com/tidepool-org/platform/page"
"github.com/tidepool-org/platform/pointer"
)

type DeviceDeactivateHashVersion string

const (
DeviceDeactivateHashVersionUnkown DeviceDeactivateHashVersion = ""
DeviceDeactivateHashVersionCurrent DeviceDeactivateHashVersion = "1.1.0"
DeviceDeactivateHashVersionLegacy DeviceDeactivateHashVersion = "0.0.0"
DeviceDeactivateHashVersionUnknown = "unknown-hash"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I think we have a disconnect. I may not have explained myself very well. These version strings need to remain the same.

There need to be two separate version groups.

First, the version of the DeviceDeactivationHash deduplicator. That would be "0.0.0" (for Jellyfish) and "1.1.0" (for current Platform).

Second, the version of the identity fields, that would be, for simplicity, "0" (for legacy) and "1" (for current). This is what is passed into the datum.IdentityFields function.

The hash function and HashOptions, since it is not specific to the DeviceDeactivateHash deduplicator, should use the identity fields version.

Or, for complete separation of concerns, you could add a third version, the hash version, either "0" or "1".

So, then the code maps from deduplicator version to hash version to identity fields version.

The DeviceDeactivateHash code looks at its version, maps its version to a hash version and creates the HashOptions with that version. Then, the hash code looks at its version, maps its version to an identity field versions and calls IdentityFields with that identity field version.

Then, you've completely isolated the DeviceDeactivationHash deduplicator from the hash functionality from the identity fields functionality. In practice, we definitely have to do the first step (deduplicator version to hash version) because there will be another duplicator for continuous data sets that is not based off the device id, but the data set id, and doesn't deactivate, but deletes.

Technically, we don't actually need the hash version and could just use the identity fields version for both hash function and IdentityFields function.

Does that make sense? Let's chat about this tomorrow.

DeviceDeactivateHashVersionLegacy = "legacy-hash"
DeviceDeactivateHashVersionCurrent = "current-hash"
)

const DeviceDeactivateHashName = "org.tidepool.deduplicator.device.deactivate.hash"
Expand Down Expand Up @@ -46,7 +45,7 @@ type DeviceDeactivateHash struct {
}

func NewDeviceDeactivateLegacyHash() (*DeviceDeactivateHash, error) {
base, err := NewBase(DeviceDeactivateHashName, string(DeviceDeactivateHashVersionLegacy))
base, err := NewBase(DeviceDeactivateHashName, DeviceDeactivateHashVersionLegacy)
if err != nil {
return nil, err
}
Expand All @@ -57,7 +56,7 @@ func NewDeviceDeactivateLegacyHash() (*DeviceDeactivateHash, error) {
}

func NewDeviceDeactivateHash() (*DeviceDeactivateHash, error) {
base, err := NewBase(DeviceDeactivateHashName, string(DeviceDeactivateHashVersionCurrent))
base, err := NewBase(DeviceDeactivateHashName, DeviceDeactivateHashVersionCurrent)
if err != nil {
return nil, err
}
Expand All @@ -67,13 +66,13 @@ func NewDeviceDeactivateHash() (*DeviceDeactivateHash, error) {
}, nil
}

func getDeviceDeactivateHashVersion(dataSet *dataTypesUpload.Upload) DeviceDeactivateHashVersion {
func getDeduplicatorVersion(dataSet *dataTypesUpload.Upload) string {
if dataSet.Deduplicator != nil {
if dataSet.Deduplicator.Name != nil && dataSet.Deduplicator.Version != nil {
if *dataSet.Deduplicator.Name == DeviceDeactivateHashName {
if *dataSet.Deduplicator.Version == string(DeviceDeactivateHashVersionLegacy) {
if types.LegacyIdentityFieldsVersion == *dataSet.Deduplicator.Version {
return DeviceDeactivateHashVersionLegacy
} else if *dataSet.Deduplicator.Version == string(DeviceDeactivateHashVersionCurrent) {
} else if types.IdentityFieldsVersion == *dataSet.Deduplicator.Version {
return DeviceDeactivateHashVersionCurrent
}
}
Expand All @@ -99,10 +98,10 @@ func getDeviceDeactivateHashVersion(dataSet *dataTypesUpload.Upload) DeviceDeact
}
}
}
return DeviceDeactivateHashVersionUnkown
return DeviceDeactivateHashVersionUnknown
}

func (d *DeviceDeactivateHash) New(dataSet *dataTypesUpload.Upload) (bool, error) {
func (d *DeviceDeactivateHash) New(ctx context.Context, dataSet *dataTypesUpload.Upload) (bool, error) {
if dataSet == nil {
return false, errors.New("data set is missing")
}
Expand All @@ -115,20 +114,20 @@ func (d *DeviceDeactivateHash) New(dataSet *dataTypesUpload.Upload) (bool, error
if dataSet.HasDeduplicatorName() {
return d.Get(ctx, dataSet)
}
return getDeviceDeactivateHashVersion(dataSet) != DeviceDeactivateHashVersionUnkown, nil
return getDeduplicatorVersion(dataSet) != DeviceDeactivateHashVersionUnknown, nil
}

func (d *DeviceDeactivateHash) Get(dataSet *dataTypesUpload.Upload) (bool, error) {
func (d *DeviceDeactivateHash) Get(ctx context.Context, dataSet *dataTypesUpload.Upload) (bool, error) {
// NOTE: check legacy first then fallback to other matches
if dataSet == nil {
return false, errors.New("data set is missing")
}

if getDeviceDeactivateHashVersion(dataSet) == DeviceDeactivateHashVersionLegacy {
if getDeduplicatorVersion(dataSet) == DeviceDeactivateHashVersionLegacy {
return true, nil
}

if found, err := d.Base.Get(dataSet); err != nil || found {
if found, err := d.Base.Get(ctx, dataSet); err != nil || found {
return found, err
}
return dataSet.HasDeduplicatorNameMatch("org.tidepool.hash-deactivate-old"), nil // TODO: DEPRECATED
Expand All @@ -150,18 +149,19 @@ func (d *DeviceDeactivateHash) AddData(ctx context.Context, repository dataStore

options := NewDefaultDeviceDeactivateHashOptions()

if getDeviceDeactivateHashVersion(dataSet) == DeviceDeactivateHashVersionLegacy {
filter := &data.DataSetFilter{IsLegacy: pointer.FromBool(true), DeviceID: dataSet.DeviceID}
if getDeduplicatorVersion(dataSet) == DeviceDeactivateHashVersionLegacy {
filter := &data.DataSetFilter{LegacyOnly: pointer.FromBool(true), DeviceID: dataSet.DeviceID}
pagination := &page.Pagination{Page: 1, Size: 1}

uploads, err := repository.ListUserDataSets(ctx, *dataSet.UserID, filter, pagination)
if err != nil {
return errors.Wrap(err, "error getting datasets for user")
}
if len(uploads) != 0 {
if uploads[0].LegacyGroupID != nil {
options = NewLegacyDeviceDeactivateHashOptions(*uploads[0].LegacyGroupID)
if uploads[0].LegacyGroupID == nil {
return errors.New("missing required legacy groupId for the device deactive hash legacy version")
}
options = NewLegacyHashOptions(*uploads[0].LegacyGroupID)
}
}

Expand Down
20 changes: 16 additions & 4 deletions data/deduplicator/deduplicator/device_deactivate_hash_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,18 @@ var _ = Describe("DeviceDeactivateHash", func() {
Expect(dataDeduplicatorDeduplicator.DeviceDeactivateHashName).To(Equal("org.tidepool.deduplicator.device.deactivate.hash"))
})

It("DeviceDeactivateHashVersionCurrent is current-hash", func() {
Expect(dataDeduplicatorDeduplicator.DeviceDeactivateHashVersionCurrent).To(Equal("current-hash"))
})

It("DeviceDeactivateHashVersionLegacy is legacy-hash", func() {
Expect(dataDeduplicatorDeduplicator.DeviceDeactivateHashVersionLegacy).To(Equal("legacy-hash"))
})

It("DeviceDeactivateHashVersionUnknown is unkown-hash", func() {
Expect(dataDeduplicatorDeduplicator.DeviceDeactivateHashVersionUnknown).To(Equal("unknown-hash"))
})

Context("NewDeviceDeactivateHash", func() {
It("returns succesfully", func() {
Expect(dataDeduplicatorDeduplicator.NewDeviceDeactivateHash()).ToNot(BeNil())
Expand Down Expand Up @@ -66,14 +78,14 @@ var _ = Describe("DeviceDeactivateHash", func() {

It("returns false when the deduplicator name does not match", func() {
dataSet.Deduplicator.Name = pointer.FromString(netTest.RandomReverseDomain())
Expect(deduplicator.New(dataSet)).To(BeFalse())
Expect(deduplicator.New(context.Background(), dataSet)).To(BeFalse())
})

DescribeTable("returns true when",
func(deviceManufacturer string, deviceModel string) {
dataSet.DeviceManufacturers = pointer.FromStringArray([]string{deviceManufacturer})
dataSet.DeviceModel = pointer.FromString(deviceModel)
Expect(deduplicator.New(dataSet)).To(BeTrue())
Expect(deduplicator.New(context.Background(), dataSet)).To(BeTrue())
},
Entry("is Abbott FreeStyle Libre", "Abbott", "FreeStyle Libre"),
Entry("is LifeScan OneTouch Ultra 2", "LifeScan", "OneTouch Ultra 2"),
Expand Down Expand Up @@ -264,7 +276,7 @@ var _ = Describe("DeviceDeactivateHash", func() {
dataSet.Deduplicator.Name = pointer.FromString(dataDeduplicatorDeduplicator.DeviceDeactivateHashName)
dataSet.DeviceManufacturers = pointer.FromStringArray([]string{"Tandem"})
dataSet.DeviceModel = pointer.FromString("1002717")
Expect(deduplicator.Get(dataSet)).To(BeTrue())
Expect(deduplicator.Get(context.Background(), dataSet)).To(BeTrue())
})
})

Expand Down Expand Up @@ -308,7 +320,7 @@ var _ = Describe("DeviceDeactivateHash", func() {
update.Active = pointer.FromBool(false)
update.Deduplicator = &data.DeduplicatorDescriptor{
Name: pointer.FromString("org.tidepool.deduplicator.device.deactivate.hash"),
Version: pointer.FromString("1.1.0"),
Version: pointer.FromString(dataDeduplicatorDeduplicator.DeviceDeactivateHashVersionCurrent),
}
})

Expand Down
59 changes: 32 additions & 27 deletions data/deduplicator/deduplicator/hash.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,58 +13,63 @@ import (
"github.com/tidepool-org/platform/pointer"
)

type deviceDeactivateHashOptions struct {
version DeviceDeactivateHashVersion
legacyGroupID *string
type HashOptions struct {
Version string
LegacyGroupID *string
}

func NewLegacyDeviceDeactivateHashOptions(legacyGroupID string) deviceDeactivateHashOptions {
return deviceDeactivateHashOptions{
version: DeviceDeactivateHashVersionLegacy,
legacyGroupID: &legacyGroupID,
func NewLegacyHashOptions(legacyGroupID string) HashOptions {
return HashOptions{
Version: DeviceDeactivateHashVersionLegacy,
LegacyGroupID: &legacyGroupID,
}
}

func NewDefaultDeviceDeactivateHashOptions() deviceDeactivateHashOptions {
return deviceDeactivateHashOptions{
version: DeviceDeactivateHashVersionCurrent,
func NewDefaultDeviceDeactivateHashOptions() HashOptions {
return HashOptions{
Version: DeviceDeactivateHashVersionCurrent,
}
}

func (d deviceDeactivateHashOptions) ValidateLegacy() error {
if d.version == DeviceDeactivateHashVersionLegacy {
if d.legacyGroupID == nil || *d.legacyGroupID == "" {
func (d HashOptions) Validate() error {

switch d.Version {
case DeviceDeactivateHashVersionLegacy:
if d.LegacyGroupID == nil || *d.LegacyGroupID == "" {
return errors.New("missing required legacy groupId for the device deactive hash legacy version")
}
case DeviceDeactivateHashVersionCurrent:
if d.LegacyGroupID != nil {
return errors.New("groupId is not required for the device deactive hash current version")
}
default:
return errors.Newf("missing valid version %s", d.Version)
}
return nil
}

func AssignDataSetDataIdentityHashes(dataSetData data.Data, options deviceDeactivateHashOptions) error {
func AssignDataSetDataIdentityHashes(dataSetData data.Data, options HashOptions) error {
if err := options.Validate(); err != nil {
return err
}
for _, dataSetDatum := range dataSetData {
var hash string
if options.version == DeviceDeactivateHashVersionLegacy {
if err := options.ValidateLegacy(); err != nil {
return err
}
fields, err := dataSetDatum.LegacyIdentityFields()
if err != nil {
return errors.Wrapf(err, "unable to gather legacy identity fields for datum %T", dataSetDatum)
}

fields, err := dataSetDatum.IdentityFields(options.Version)
if err != nil {
return errors.Wrap(err, "unable to gather identity fields for datum")
}

if options.Version == DeviceDeactivateHashVersionLegacy {
hash, err = GenerateLegacyIdentityHash(fields)
if err != nil {
return errors.Wrapf(err, "unable to generate legacy identity hash for datum %T", dataSetDatum)
}
hash, err = GenerateLegacyIdentityHash([]string{hash, *options.legacyGroupID})
hash, err = GenerateLegacyIdentityHash([]string{hash, *options.LegacyGroupID})
if err != nil {
return errors.Wrapf(err, "unable to generate legacy identity hash with legacy groupID for datum %T", dataSetDatum)
}
} else {
fields, err := dataSetDatum.IdentityFields()
if err != nil {
return errors.Wrap(err, "unable to gather identity fields for datum")
}
hash, err = GenerateIdentityHash(fields)
if err != nil {
return errors.Wrap(err, "unable to generate identity hash for datum")
Expand Down
Loading