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

feat: refactor contact code to remove contact-types.ts #9753

Open
wants to merge 1 commit into
base: 9586-implement-freetext-search-in-cht-datasource
Choose a base branch
from
Open
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
28 changes: 0 additions & 28 deletions shared-libs/cht-datasource/src/contact-types.ts

This file was deleted.

16 changes: 12 additions & 4 deletions shared-libs/cht-datasource/src/contact.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {
getPagedGenerator,
getPagedGenerator, NormalizedParent,
Nullable,
Page,
} from './libs/core';
Expand All @@ -13,7 +13,6 @@ import { LocalDataContext } from './local/libs/data-context';
import { RemoteDataContext } from './remote/libs/data-context';
import * as Local from './local';
import * as Remote from './remote';
import * as ContactTypes from './contact-types';
import { DEFAULT_DOCS_PAGE_LIMIT } from './libs/constants';
import {
assertContactTypeFreetextQualifier,
Expand All @@ -25,17 +24,26 @@ import {
isContactType,
isFreetextType,
} from './libs/parameter-validators';
import { Doc } from './libs/doc';

/** */
export namespace v1 {
/**
* Immutable data about a Contact.
*/
export type Contact = ContactTypes.v1.Contact;
export interface Contact extends Doc, NormalizedParent {
readonly contact_type?: string;
readonly name?: string;
readonly reported_date?: Date;
readonly type: string;
}

/**
* Immutable data about a contact, including the full records of the parent's lineage.
*/
export type ContactWithLineage = ContactTypes.v1.ContactWithLineage;
export interface ContactWithLineage extends Contact {
readonly parent?: ContactWithLineage | NormalizedParent;
}

const getContact =
<T>(
Expand Down
11 changes: 11 additions & 0 deletions shared-libs/cht-datasource/src/libs/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,3 +144,14 @@ export const getPagedGenerator = async function* <S, T>(

return null;
};

/** @internal */
export interface NormalizedParent extends DataObject, Identifiable {
readonly parent?: NormalizedParent;
}

/** @ignore */
export const isNormalizedParent = (value: unknown): value is NormalizedParent => {
return isDataObject(value) && isIdentifiable(value) && (!value.parent || isNormalizedParent(value.parent));
};

8 changes: 4 additions & 4 deletions shared-libs/cht-datasource/src/local/contact.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
queryDocUuidsByRange
} from './libs/doc';
import { ContactTypeQualifier, FreetextQualifier, isKeyedFreetextQualifier, UuidQualifier } from '../qualifier';
import * as ContactType from '../contact-types';
import * as Contact from '../contact';
import { isNonEmptyArray, NonEmptyArray, Nullable, Page } from '../libs/core';
import { Doc } from '../libs/doc';
import logger from '@medic/logger';
Expand All @@ -25,7 +25,7 @@ export namespace v1 {
};

const isContact =
(settings: SettingsService) => (doc: Nullable<Doc>, uuid?: string): doc is ContactType.v1.Contact => {
(settings: SettingsService) => (doc: Nullable<Doc>, uuid?: string): doc is Contact.v1.Contact => {
if (!doc) {
if (uuid) {
logger.warn(`No contact found for identifier [${uuid}].`);
Expand All @@ -43,7 +43,7 @@ export namespace v1 {
/** @internal */
export const get = ({ medicDb, settings }: LocalDataContext) => {
const getMedicDocById = getDocById(medicDb);
return async (identifier: UuidQualifier): Promise<Nullable<ContactType.v1.Contact>> => {
return async (identifier: UuidQualifier): Promise<Nullable<Contact.v1.Contact>> => {
const doc = await getMedicDocById(identifier.uuid);
if (!isContact(settings)(doc, identifier.uuid)) {
return null;
Expand All @@ -57,7 +57,7 @@ export namespace v1 {
export const getWithLineage = ({ medicDb, settings }: LocalDataContext) => {
const getLineageDocs = getLineageDocsById(medicDb);

return async (identifier: UuidQualifier): Promise<Nullable<ContactType.v1.ContactWithLineage>> => {
return async (identifier: UuidQualifier): Promise<Nullable<Contact.v1.ContactWithLineage>> => {
const [contact, ...lineageContacts] = await getLineageDocs(identifier.uuid);
if (!isContact(settings)(contact, identifier.uuid)) {
return null;
Expand Down
9 changes: 4 additions & 5 deletions shared-libs/cht-datasource/src/local/libs/lineage.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import * as Contact from '../../contact';
import * as ContactTypes from '../../contact-types';
import * as Person from '../../person';
import {
DataObject,
Expand All @@ -9,7 +8,7 @@ import {
isIdentifiable,
isNonEmptyArray,
isNotNull,
NonEmptyArray,
NonEmptyArray, NormalizedParent,
Nullable
} from '../../libs/core';
import { Doc } from '../../libs/doc';
Expand Down Expand Up @@ -50,7 +49,7 @@ export const hydratePrimaryContact = (contacts: Doc[]) => (place: Nullable<Doc>)
};
};

const getParentUuid = (index: number, contact?: ContactTypes.v1.NormalizedParent): Nullable<string> => {
const getParentUuid = (index: number, contact?: NormalizedParent): Nullable<string> => {
if (!contact) {
return null;
}
Expand Down Expand Up @@ -101,7 +100,7 @@ export const getContactLineage = (medicDb: PouchDB.Database<Doc>) => {
contacts: NonEmptyArray<Nullable<Doc>>,
person?: Person.v1.Person,
filterSelf = false,
): Promise<Nullable<ContactTypes.v1.ContactWithLineage>> => {
): Promise<Nullable<Contact.v1.ContactWithLineage>> => {
const contactUuids = getPrimaryContactIds(contacts);
const uuidsToFetch = filterSelf ? contactUuids.filter(uuid => uuid !== person?._id) : contactUuids;
const fetchedContacts = await getMedicDocsById(uuidsToFetch);
Expand All @@ -111,7 +110,7 @@ export const getContactLineage = (medicDb: PouchDB.Database<Doc>) => {
).filter(item => item ?? false);
const [mainContact, ...lineageContacts] = contactsWithHydratedPrimaryContact;
const contactWithLineage = hydrateLineage(
(person ?? mainContact) as ContactTypes.v1.Contact,
(person ?? mainContact) as Contact.v1.Contact,
person ? contactsWithHydratedPrimaryContact : lineageContacts
);

Expand Down
5 changes: 2 additions & 3 deletions shared-libs/cht-datasource/src/person.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { ContactTypeQualifier, UuidQualifier } from './qualifier';
import { adapt, assertDataContext, DataContext } from './libs/data-context';
import * as Contact from './contact';
import * as ContactTypes from './contact-types';
import * as Remote from './remote';
import * as Local from './local';
import * as Place from './place';
import { LocalDataContext } from './local/libs/data-context';
import { RemoteDataContext } from './remote/libs/data-context';
import { getPagedGenerator, Nullable, Page } from './libs/core';
import { getPagedGenerator, NormalizedParent, Nullable, Page } from './libs/core';
import { DEFAULT_DOCS_PAGE_LIMIT } from './libs/constants';
import { assertCursor, assertLimit, assertTypeQualifier, assertUuidQualifier } from './libs/parameter-validators';

Expand All @@ -27,7 +26,7 @@ export namespace v1 {
* Immutable data about a person contact, including the full records of the parent place lineage.
*/
export interface PersonWithLineage extends Person {
readonly parent?: Place.v1.PlaceWithLineage | ContactTypes.v1.NormalizedParent;
readonly parent?: Place.v1.PlaceWithLineage | NormalizedParent;
}

const getPerson =
Expand Down
9 changes: 4 additions & 5 deletions shared-libs/cht-datasource/src/place.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import * as Contact from './contact';
import * as ContactTypes from './contact-types';
import * as Person from './person';
import { LocalDataContext } from './local/libs/data-context';
import { ContactTypeQualifier, UuidQualifier } from './qualifier';
import { RemoteDataContext } from './remote/libs/data-context';
import { adapt, assertDataContext, DataContext } from './libs/data-context';
import * as Local from './local';
import * as Remote from './remote';
import { getPagedGenerator, Nullable, Page } from './libs/core';
import { getPagedGenerator, NormalizedParent, Nullable, Page } from './libs/core';
import { DEFAULT_DOCS_PAGE_LIMIT } from './libs/constants';
import { assertCursor, assertLimit, assertTypeQualifier, assertUuidQualifier } from './libs/parameter-validators';

Expand All @@ -17,7 +16,7 @@ export namespace v1 {
* Immutable data about a place contact.
*/
export interface Place extends Contact.v1.Contact {
readonly contact?: ContactTypes.v1.NormalizedParent;
readonly contact?: NormalizedParent;
readonly place_id?: string;
}

Expand All @@ -26,8 +25,8 @@ export namespace v1 {
* contact for the place.
*/
export interface PlaceWithLineage extends Place {
readonly contact?: Person.v1.PersonWithLineage | ContactTypes.v1.NormalizedParent;
readonly parent?: PlaceWithLineage | ContactTypes.v1.NormalizedParent;
readonly contact?: Person.v1.PersonWithLineage | NormalizedParent;
readonly parent?: PlaceWithLineage | NormalizedParent;
}

const getPlace =
Expand Down
6 changes: 3 additions & 3 deletions shared-libs/cht-datasource/src/remote/contact.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { getResource, getResources, RemoteDataContext } from './libs/data-context';
import { ContactTypeQualifier, FreetextQualifier, UuidQualifier } from '../qualifier';
import { Nullable, Page } from '../libs/core';
import * as ContactType from '../contact-types';
import * as Contact from '../contact';
import { isContactType, isFreetextType } from '../libs/parameter-validators';

/** @internal */
Expand All @@ -13,14 +13,14 @@ export namespace v1 {
/** @internal */
export const get = (remoteContext: RemoteDataContext) => (
identifier: UuidQualifier
): Promise<Nullable<ContactType.v1.Contact>> => getContact(remoteContext)(identifier.uuid);
): Promise<Nullable<Contact.v1.Contact>> => getContact(remoteContext)(identifier.uuid);

/** @internal */
export const getWithLineage = (
remoteContext: RemoteDataContext
) => (
identifier: UuidQualifier
): Promise<Nullable<ContactType.v1.ContactWithLineage>> => getContact(remoteContext)(identifier.uuid, {
): Promise<Nullable<Contact.v1.ContactWithLineage>> => getContact(remoteContext)(identifier.uuid, {
with_lineage: 'true',
});

Expand Down
26 changes: 0 additions & 26 deletions shared-libs/cht-datasource/test/contact.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import * as Local from '../src/local';
import * as Remote from '../src/remote';
import * as Qualifier from '../src/qualifier';
import * as Contact from '../src/contact';
import * as ContactType from '../src/contact-types';
import { expect } from 'chai';
import * as Core from '../src/libs/core';

Expand All @@ -28,31 +27,6 @@ describe('contact', () => {
afterEach(() => sinon.restore());

describe('v1', () => {
describe('isNormalizedParent', () => {
let isDataObject: SinonStub;

beforeEach(() => isDataObject = sinon.stub(Core, 'isDataObject'));
afterEach(() => sinon.restore());

([
[{ _id: 'my-id' }, true, true],
[{ _id: 'my-id' }, false, false],
[{ hello: 'my-id' }, true, false],
[{ _id: 1 }, true, false],
[{ _id: 'my-id', parent: 'hello' }, true, false],
[{ _id: 'my-id', parent: null }, true, true],
[{ _id: 'my-id', parent: { hello: 'world' } }, true, false],
[{ _id: 'my-id', parent: { _id: 'parent-id' } }, true, true],
[{ _id: 'my-id', parent: { _id: 'parent-id', parent: { hello: 'world' } } }, true, false],
[{ _id: 'my-id', parent: { _id: 'parent-id', parent: { _id: 'grandparent-id' } } }, true, true],
] as [unknown, boolean, boolean][]).forEach(([value, dataObj, expected]) => {
it(`evaluates ${JSON.stringify(value)}`, () => {
isDataObject.returns(dataObj);
expect(ContactType.v1.isNormalizedParent(value)).to.equal(expected);
});
});
});

describe('get', () => {
const contact = { _id: 'my-contact' } as Contact.v1.Contact;
const qualifier = { uuid: contact._id } as const;
Expand Down
28 changes: 27 additions & 1 deletion shared-libs/cht-datasource/test/libs/core.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@ import {
hasFields,
isDataObject,
isIdentifiable,
isNonEmptyArray,
isNonEmptyArray, isNormalizedParent,
isRecord,
isString,
NonEmptyArray
} from '../../src/libs/core';
import sinon, { SinonStub } from 'sinon';
import * as Core from '../../src/libs/core';

describe('core lib', () => {
afterEach(() => sinon.restore());
Expand Down Expand Up @@ -274,4 +275,29 @@ describe('core lib', () => {
expect(fetchFunctionStub.calledOnce).to.be.true;
});
});

describe('isNormalizedParent', () => {
let isDataObject: SinonStub;

beforeEach(() => isDataObject = sinon.stub(Core, 'isDataObject'));
afterEach(() => sinon.restore());

([
[{ _id: 'my-id' }, true, true],
[{ _id: 'my-id' }, false, false],
[{ hello: 'my-id' }, true, false],
[{ _id: 1 }, true, false],
[{ _id: 'my-id', parent: 'hello' }, true, false],
[{ _id: 'my-id', parent: null }, true, true],
[{ _id: 'my-id', parent: { hello: 'world' } }, true, false],
[{ _id: 'my-id', parent: { _id: 'parent-id' } }, true, true],
[{ _id: 'my-id', parent: { _id: 'parent-id', parent: { hello: 'world' } } }, true, false],
[{ _id: 'my-id', parent: { _id: 'parent-id', parent: { _id: 'grandparent-id' } } }, true, true],
] as [unknown, boolean, boolean][]).forEach(([value, dataObj, expected]) => {
it(`evaluates ${JSON.stringify(value)}`, () => {
isDataObject.returns(dataObj);
expect(isNormalizedParent(value)).to.equal(expected);
});
});
});
});