-
Notifications
You must be signed in to change notification settings - Fork 4
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
[#172621882] Get all data for a specific user #42
Conversation
Affected stories
Generated by 🚫 dangerJS |
tryCatch( | ||
() => | ||
userDataProcessingModel.createOrUpdateByNewOne({ | ||
...currentRecord, | ||
status: nextStatus | ||
}), | ||
(err: Error) => { | ||
return ActivityResultQueryFailure.encode({ | ||
kind: "QUERY_FAILURE", | ||
query: "userDataProcessingModel.createOrUpdateByNewOne", | ||
reason: err.message | ||
}); | ||
} |
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.
Can we use fromQueryEither
in this 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.
I agree, but still fromQueryEither
isn't as generic as to be placed in a dedicated module. I'll just copy it over though, because I think it's more eloquent
Codecov Report
@@ Coverage Diff @@
## master #42 +/- ##
==========================================
- Coverage 88.81% 87.00% -1.81%
==========================================
Files 21 24 +3
Lines 608 762 +154
Branches 37 49 +12
==========================================
+ Hits 540 663 +123
- Misses 67 98 +31
Partials 1 1
Continue to review full report at Codecov.
|
value: fiscalCode | ||
} | ||
], | ||
query: `SELECT * FROM m WHERE m.fiscal_code = @fiscalCode` |
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.
since the partitionKey of the notifications collection is messageId
this results in a cross partition query which should be avoided (see https://docs.microsoft.com/it-it/azure/cosmos-db/how-to-query-container#cross-partition-query).
you should include a condition on messageId
so: get all users messages then, for each retrieved message, loop to get the message-status and the relative nofitications; then, for each retrieved notification, loop to get then the notification-status.
* The validation process use a `id and validator` strategy. | ||
* | ||
* The `id` is generated using an ulid generator and is used when searching | ||
* a specific ValidationToken entity in the table storage. | ||
* | ||
* For the `validator` we use a random-bytes generator. This `validator` value is | ||
* hashed using the `sha256` strategy and then stored in the entity as `validatorHash` | ||
* | ||
* Each token has also a `InvalidAfter` field to set the token lifetime. |
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.
probably we should remove this comments? :)
ExtractUserDataActivity/handler.ts
Outdated
* | ||
* @returns the same document without db metadata | ||
*/ | ||
const fromRetrievedDbDocument = <T>(doc: T & RetrievedDocumentT): T => { |
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.
every model has a class method toBaseType
method which does exactly the same and does not depend on cosmosdb internal, consider using that one and remove this one
ie. https://github.com/pagopa/io-functions-commons/blob/6b60b5cc5fb840ff397f2ebc3261a3c7408b2168/src/models/profile.ts#L129
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.
it seems to to be used by anyone. It's passed to the base class which exposes it as protected, then never actually used.
https://github.com/pagopa/io-functions-commons/blob/master/src/utils/documentdb_model.ts#L31
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 we cannot use that, I suggest to remove this method anyway and just use
t.exact(Message).encode(o);
inline when needed
ExtractUserDataActivity/handler.ts
Outdated
const appendContentToMessage = ( | ||
messageFromDb: RetrievedMessageWithoutContent, | ||
content: MessageContent | ||
): MessageWithContent => ({ |
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.
why do we need to merge the message with its content ?
it's better to just save them in a separate blob
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.
good, even easier
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 structure of the zip should mimic the internal representation (that won't happen, but suppose you have to restore all data fom the content of the zip :)
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.
This includes also document-related data? I mean: should we export also RetrievedDocument
-related fields?
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.
no since they're not needed to rebuild the whole thing
ExtractUserDataActivity/handler.ts
Outdated
.map(([notificationId, channel]) => | ||
fromQueryEither( | ||
() => | ||
notificationStatusModel.findOneNotificationStatusByNotificationChannel( |
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.
why do we need to differentiate by channel?
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.
no, but I wanted to use the actual method which queries by statusId, and calculates the statusId by its channel
ExtractUserDataActivity/handler.ts
Outdated
ReadonlyArray<RetrievedNotification> | ||
> => { | ||
if (messages.length) { | ||
// this spread is needed as typescript wouldn't recognize messages[0] to be defined otherwise |
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.
it's not clear, why do we need this pattern here ? consider using a NonEmptyArray instead and avoid to call the same code twice
NonEmptyArray.decode(messages)... or if (NonEmptyArray.is(message)) ...
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.
"fp-ts/lib/NonEmptyArray"
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.
didn't know that, thanks
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.
are you sure it works like that? it doesn't seem to be a decoder though.
Anyway, I think it doesn't solved the issue: to pass an arbitrary list of taskEither to a sequenceT
to resolve them in parallel: https://github.com/pagopa/io-functions-admin/pull/42/files/98dd1f4ddb37bed424eb078bd0549cd0a9c064b9#diff-6c3441a7b004efdd3512746300508009R339
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 mean: you can just use NonEmptyArray.fromArray(messages).map(...)
instead of check messages length and separate head and tail (it's not clear why do you want to do that). you can use sequence (instead of sequenceT) to process them in parallel
https://grossbart.github.io/fp-ts-recipes/#/async?a=work-with-a-list-of-tasks-in-parallel
ExtractUserDataActivity/handler.ts
Outdated
arrayOfArray => | ||
fromEither( | ||
right( | ||
arrayOfArray.reduce( |
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.
you can use array.flatten from fp-ts
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 think it doesn't support readonly arrays (introduced in v2.5)
ExtractUserDataActivity/handler.ts
Outdated
ReadonlyArray<RetrievedNotification> | ||
> => { | ||
if (messages.length) { | ||
// this spread is needed as typescript wouldn't recognize messages[0] to be defined otherwise |
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 mean: you can just use NonEmptyArray.fromArray(messages).map(...)
instead of check messages length and separate head and tail (it's not clear why do you want to do that). you can use sequence (instead of sequenceT) to process them in parallel
https://grossbart.github.io/fp-ts-recipes/#/async?a=work-with-a-list-of-tasks-in-parallel
ExtractUserDataActivity/handler.ts
Outdated
.foldTaskEither( | ||
e => fromEither(left(e)), | ||
arrayOfArray => | ||
// tslint:disable-next-line: readonly-array | ||
fromEither(right(flatten(arrayOfArray as RetrievedNotification[][]))) | ||
); |
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.
since you are converting back to taskEither, maybe I'm wrong but it looks like you can just use map(flatten)
here
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.
you're right, foldTaskEither
come from a version of the code which has been refactored now. No more reason for that, thanks
() => messageModel.getContentFromBlob(blobService, messageId), | ||
"messageModel.getContentFromBlob" | ||
).foldTaskEither<ActivityResultQueryFailure, MessageContentWithId>( | ||
failure => fromEither(left(failure)), |
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.
when the left value is unchanged, probably you can chain
or map
instead of folding
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.
In this case it's not trivial, because the right path may become left if Option is none.
switch (channel) { | ||
case NotificationChannelEnum.EMAIL: | ||
case NotificationChannelEnum.WEBHOOK: | ||
return [notificationId, channel]; | ||
default: | ||
assertNever(channel); |
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.
cannot ...Object.values(NotificationChannelEnum).map(channel => [notificationId, channel])
just work without the switch here?
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.
Yes, but this way I could implement an exhaustive check that will force us to update this function if in the future we add/remove options in NotificationChannelEnum
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.
why do we want to be forced to update this method in 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.
Maybe we'll add support for another notification channel
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.
and why .map(channel => [notificationId, channel])
won't suffice in that case?
ExtractUserDataActivity/handler.ts
Outdated
ActivityResultQueryFailure, | ||
ReadonlyArray<NotificationStatus> | ||
>( | ||
e => fromEither(left(e)), |
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.
map / chain ?
ExtractUserDataActivity/handler.ts
Outdated
}) | ||
) | ||
.chain(({ fiscalCode }) => queryAllUserData(fiscalCode)) | ||
.map(allUserData => |
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.
when you have map
+ mapLeft
you can use bimap
to handle both
Co-authored-by: Danilo Spinelli <gunzip@users.noreply.github.com>
…tions-admin into 172621882-accesso-ai-dati
Co-authored-by: Danilo Spinelli <gunzip@users.noreply.github.com>
Co-authored-by: Danilo Spinelli <gunzip@users.noreply.github.com>
Co-authored-by: Danilo Spinelli <gunzip@users.noreply.github.com>
Co-authored-by: Danilo Spinelli <gunzip@users.noreply.github.com>
…tions-admin into 172621882-accesso-ai-dati
Implementation of part of the Activit handles needed to complete the task.
Things to note:
io-functions-commons
, like mocks. We might move them there after this activityNotificationModel
has been extended to support a specific use case. This as well might be moved into commons.