-
-
Notifications
You must be signed in to change notification settings - Fork 2
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-2870] [BACK-3176] EHR Patient Tags #72
base: main
Are you sure you want to change the base?
Conversation
toddkazakov
commented
Sep 26, 2024
•
edited
Loading
edited
- Allow creating and associating patient tags with Redox create account orders
- Allow creating accounts and enabling reports with a single order
aad3d51
to
71771fd
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, just a few suggestions/questions. Nothing blocking.
I noticed that very few error paths are covered by tests. When the return path is return err
, this doesn't bother me much, but many of them involve sending messages or other non-trivial logic. It's probably worth trying to cover a few more of them.
if err != nil { | ||
return nil, err | ||
} | ||
if resp.StatusCode() != http.StatusOK { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know these clients are automatically generated, but I really hate how they leak HTTP like a sieve. Sure, I don't see us using anything other than HTTP for this, but that's only a small part of why we abstract away those details. Oh well. (Not a comment on your code, just lamenting the leakiness of the client's abstraction.)
return nil | ||
} | ||
|
||
patient := (*match.Patients)[0] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update: this probably isn't necessary, feel free to ignore.
patient := (*match.Patients)[0] | |
if len(match.Patients) < 1 { | |
return fmt.Errorf("no patient in match") | |
} | |
patient := (*match.Patients)[0] |
Just to prevent a possible panic in prod.
TargetDevices: patient.TargetDevices, | ||
Tags: tagIds, | ||
} | ||
resp, err := o.clinics.UpdatePatientWithResponse(ctx, *match.Clinic.Id, *patient.Id, update) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update: this probably isn't necessary, feel free to ignore.
resp, err := o.clinics.UpdatePatientWithResponse(ctx, *match.Clinic.Id, *patient.Id, update) | |
if match.Clinic == nil { | |
return fmt.Errorf("no clinic found in match") | |
} | |
resp, err := o.clinics.UpdatePatientWithResponse(ctx, *match.Clinic.Id, *patient.Id, update) |
Again, just to prevent possible panics in prod.
func (o *newOrderProcessor) getPatientTagCodes(match clinics.EHRMatchResponse) map[string]struct{} { | ||
result := make(map[string]struct{}) | ||
if match.Settings.Tags.Codes != nil { | ||
for _, code := range *match.Settings.Tags.Codes { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here, like previous comments, is an unchecked pointer (Codes
). This could panic. While highly unlikely, consider if it's worth a check to prevent.
...or is this all behind a HTTP request anyway that will recover from the panic I guess? Maybe my previous comments aren't really necessary either then, as I assume this being nil (at least when you expect it not to be nil) is quite rare. I don't love that, but it's probably the best solution.
I've updated my previous comments for these kinds of things under the assumption that in the rare event these were to panic, there is a recover()
somewhere that would prevent the service from terminating due to nil pointer dereference.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Line 358 is if match.Settings.Tags.Codes != nil {
so we are checking if Codes
is nil
return nil | ||
} | ||
|
||
tagNames := make([]string, 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a curiosity question if you know off of the top of your head:
Does this offer any benefit vs tagNames := []string{}
? I find this a little clearer, and I think they're equivalent, but every time I think I've got the semantics of make()
memorized I find small new edge case. :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The IntelliJ linter flags []string{}
for some reason. I don't know if there's any difference.
redox/processor_neworder.go
Outdated
if order.Order.ClinicalInfo != nil { | ||
for _, info := range *order.Order.ClinicalInfo { | ||
if info.Code != nil && info.Value != nil { | ||
if _, ok := codes[*info.Code]; ok { | ||
if separator == nil || *separator == "" { | ||
tagNames = append(tagNames, strings.TrimSpace(*info.Value)) | ||
} else { | ||
for _, tag := range strings.Split(*info.Value, *separator) { | ||
tagNames = append(tagNames, strings.TrimSpace(tag)) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if order.Order.ClinicalInfo != nil { | |
for _, info := range *order.Order.ClinicalInfo { | |
if info.Code != nil && info.Value != nil { | |
if _, ok := codes[*info.Code]; ok { | |
if separator == nil || *separator == "" { | |
tagNames = append(tagNames, strings.TrimSpace(*info.Value)) | |
} else { | |
for _, tag := range strings.Split(*info.Value, *separator) { | |
tagNames = append(tagNames, strings.TrimSpace(tag)) | |
} | |
} | |
} | |
} | |
} | |
} | |
if *order.Order.ClinicalInfo == nil { | |
return nil | |
} | |
for _, info := range *order.Order.ClinicalInfo { | |
if info.Code == nil || info.Value == nil { | |
continue | |
} | |
if _, found := codes[*info.Code]; !found { | |
continue | |
} | |
if separator == nil || *separator == "" { | |
tagNames = append(tagNames, strings.TrimSpace(*info.Value)) | |
continue | |
} | |
for _, tag := range strings.Split(*info.Value, *separator) { | |
tagNames = append(tagNames, strings.TrimSpace(tag)) | |
} | |
} |
Just a suggestion. I find it a bit easier to read, as it doesn't indent as much, and I feel like I don't have to keep as much in my head at once.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the suggestion, definitely more reasble.
@@ -81,48 +81,57 @@ func NewNewOrderProcessor(clinics clinics.ClientWithResponsesInterface, redox Cl | |||
} | |||
|
|||
func (o *newOrderProcessor) ProcessOrder(ctx context.Context, envelope models.MessageEnvelope, order models.NewOrder) error { | |||
match, err := o.matchOrder(ctx, envelope.Id.Hex(), order) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the extraction of matchOrder here, feels good. 👍🏻
/deploy qa2 |
toddkazakov updated values.yaml file in qa2 |
toddkazakov updated flux policies file in qa2 |
toddkazakov deployed clinic-worker tk-order-patient-tags branch to qa2 namespace |
a2acb74
to
2076bfe
Compare