-
-
Notifications
You must be signed in to change notification settings - Fork 217
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
feat(#9238): add functionality of getting people as an AsyncGenerator in cht-datasource #9281
Conversation
Co-authored-by: Joshua Kuestersteffen <jkuester@kuester7.com>
Co-authored-by: Joshua Kuestersteffen <jkuester@kuester7.com>
Co-authored-by: Joshua Kuestersteffen <jkuester@kuester7.com>
Co-authored-by: Joshua Kuestersteffen <jkuester@kuester7.com>
Co-authored-by: Joshua Kuestersteffen <jkuester@kuester7.com>
Co-authored-by: Joshua Kuestersteffen <jkuester@kuester7.com>
Co-authored-by: Joshua Kuestersteffen <jkuester@kuester7.com>
@jkuester @m5r I've created a draft PR for discussion. |
Additionally, the plan to implement the iterable for the local function Update: |
So, my thinking here was that we might be able to get away without having any separate remote/local logic at all. Instead we implement Should not need any separate REST endpoint for this functionality. In reality, all we are implementing here is a TS convenience wrapper over top of |
That is an interesting one and I agree that the whole implementation would be simpler and is also feasible. I might be a bit out of context here but why not the remote logic? |
03e19f1
to
c34716a
Compare
If the |
/** @internal */ | ||
export interface Page<T> { | ||
readonly data: T[]; | ||
readonly cursor: string; |
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 know that we have reached the end of the results, we should not return a cursor value.
readonly cursor?: string;
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 catch! I believe cursor
's type should be
interface Page {
readonly cursor: string | null;
}
That's more explicit to express "you've reached the end"
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 we should be more explicit and return "-1"
and not nothing to indicate the end of iteration.
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.
@m5r and I commented simultaneously, null
should do as well.
const docs = await getDocsByPage([personType.contactType], limit, skip); | ||
const getDocsByPage = queryDocsByKey(medicDb, 'medic-client/contacts_by_type'); | ||
|
||
const fetchAndFilter = async ( |
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.
Solid logic here! 👍 I think we can tighten up the cursor calculation a bit (at least reduce the nesting if-statements):
const fetchAndFilter = async (
currentLimit: number,
currentSkip: number,
currentPersons: Person.v1.Person[] = []
): Promise<Page<Person.v1.Person>> => {
const docs = await getDocsByPage([personType.contactType], currentLimit, currentSkip);
const noMoreResults = docs.length < currentLimit;
const newPersons = docs.filter((doc): doc is Person.v1.Person => isPerson(settings, doc, doc?._id));
// Need to slice here because we retrieve extra docs on re-fetches and may end up with too many.
const overFetchCount = currentPersons.length + newPersons.length - limit || 0;
const totalPersons = [...currentPersons, ...newPersons].slice(0, limit);
if (noMoreResults) {
return { data: totalPersons };
}
if (totalPersons.length === limit) {
const nextSkip = currentSkip + currentLimit - overFetchCount;
return { data: totalPersons, cursor: (nextSkip).toString() };
}
// Re-fetch twice as many docs as we need to limit number of recursions
const missingCount = currentLimit - newPersons.length;
logger.debug(`Found [${missingCount}] invalid persons. Re-fetching additional records.`);
const nextLimit = missingCount * 2;
const nextSkip = currentSkip + currentLimit;
return fetchAndFilter(nextLimit, nextSkip, totalPersons);
};
return fetchAndFilter(limit, skip);
Co-authored-by: Joshua Kuestersteffen <jkuester@kuester7.com>
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.
Nothing to add to Josh's comments, I'll approve to not block merging after Josh's approval
…ion in local/person.ts
|
de5f786
to
3eeb049
Compare
…238-add-functionality-of-getting-people-as-an-iterator-in-cht-datasource
bf8a77d
into
9193-api-endpoints-for-getting-contacts-by-type
Description
Add functionality of getting people as an
AsyncGenerator
incht-datasource
.Ticket: #9238
Usage:
Code review checklist
License
The software is provided under AGPL-3.0. Contributions to this project are accepted under the same license.