From 34f8660b282ac07f93f0c0250a7a9544da13e397 Mon Sep 17 00:00:00 2001 From: kennsippell Date: Sun, 29 Dec 2024 12:59:14 -0700 Subject: [PATCH] Self code review --- src/config/index.ts | 8 +--- src/services/files.ts | 46 -------------------- src/services/place.ts | 30 ++++++------- src/warnings/index.ts | 32 +++++++------- src/warnings/redundant-replace-classifier.ts | 2 +- test/services/files.spec.ts | 20 --------- 6 files changed, 34 insertions(+), 104 deletions(-) delete mode 100644 src/services/files.ts delete mode 100644 test/services/files.spec.ts diff --git a/src/config/index.ts b/src/config/index.ts index c6caef58..5b2bd4de 100644 --- a/src/config/index.ts +++ b/src/config/index.ts @@ -196,12 +196,8 @@ export class Config { public static getUniqueProperties(contactTypeName: string): ContactProperty[] { const contactMatch = config.contact_types.find(c => c.name === contactTypeName); - if (!contactMatch) { - return []; - } - - return contactMatch.place_properties - .filter(prop => prop.unique); + const uniqueProperties = contactMatch?.place_properties.filter(prop => prop.unique); + return uniqueProperties || []; } // TODO: Joi? Chai? diff --git a/src/services/files.ts b/src/services/files.ts deleted file mode 100644 index 4a898d93..00000000 --- a/src/services/files.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { Config } from '../config'; -import JSZip from 'jszip'; -import SessionCache from './session-cache'; -import { stringify } from 'csv/sync'; - -export default function createZip(sessionCache: SessionCache): JSZip { - const zip = new JSZip(); - for (const contactType of Config.contactTypes()) { - const places = sessionCache.getPlaces({ type: contactType.name }); - if (!places.length) { - continue; - } - - const rows = places.map((place) => [ - ...Object.values(place.hierarchyProperties).map(hierarchy => hierarchy.formatted), - place.name, - place.contact.properties.name?.formatted, - place.contact.properties.phone?.formatted, - place.userRoles.join(' '), - place.creationDetails.username, - place.creationDetails.password, - ]); - - const constraints = Config.getHierarchyWithReplacement(contactType); - const props = Object.keys(places[0].hierarchyProperties).map(prop => constraints.find(c => c.property_name === prop)!.friendly_name); - const columns = [ - ...props, - contactType.friendly, - 'name', - 'phone', - 'role', - 'username', - 'password', - ]; - - zip.file( - `${contactType.name}.csv`, - stringify(rows, { - columns, - header: true, - }), - ); - } - - return zip; -} diff --git a/src/services/place.ts b/src/services/place.ts index f02d010d..e4893b1a 100644 --- a/src/services/place.ts +++ b/src/services/place.ts @@ -1,15 +1,15 @@ -import Contact from './contact'; +import _ from 'lodash'; import { v4 as uuidv4 } from 'uuid'; import { Config, ContactProperty, ContactType } from '../config'; +import Contact from './contact'; +import { ContactPropertyValue, HierarchyPropertyValue } from '../property-value'; import { IPropertyValue, RemotePlacePropertyValue } from '../property-value'; import { PlacePayload } from '../lib/cht-api'; // can't use package.json because of rootDir in ts -import { version as appVersion } from '../package.json'; -import RemotePlaceResolver from '../lib/remote-place-resolver'; -import { HierarchyPropertyValue, ContactPropertyValue } from '../property-value'; import { RemotePlace } from '../lib/remote-place-cache'; -import _ from 'lodash'; +import RemotePlaceResolver from '../lib/remote-place-resolver'; +import { version as appVersion } from '../package.json'; export type FormattedPropertyCollection = { [key: string]: IPropertyValue; @@ -181,22 +181,14 @@ export default class Place { } public asRemotePlace() : RemotePlace { - function getUniqueKeys(properties: FormattedPropertyCollection, place_properties: ContactProperty[]): FormattedPropertyCollection { - const uniquePropertyNames = place_properties - .filter(prop => prop.unique) - .map(prop => prop.property_name); - - return _.pick(properties, uniquePropertyNames); - } - const nameProperty = Config.getPropertyWithName(this.type.place_properties, 'name'); return { id: this.id, name: new RemotePlacePropertyValue(this.name, nameProperty), placeType: this.type.name, type: this.isCreated ? 'remote' : 'local', - uniquePlaceValues: getUniqueKeys(this.properties, this.type.place_properties), - uniqueContactValues: getUniqueKeys(this.contact.properties, this.type.contact_properties), + uniquePlaceValues: this.getUniqueKeys(this.properties, this.type.place_properties), + uniqueContactValues: this.getUniqueKeys(this.contact.properties, this.type.contact_properties), stagedPlace: this, lineage: this.buildLineage(), }; @@ -295,4 +287,12 @@ export default class Place { return lineage; } + + private getUniqueKeys(properties: FormattedPropertyCollection, place_properties: ContactProperty[]): FormattedPropertyCollection { + const uniquePropertyNames = place_properties + .filter(prop => prop.unique) + .map(prop => prop.property_name); + + return _.pick(properties, uniquePropertyNames); + } } diff --git a/src/warnings/index.ts b/src/warnings/index.ts index beb3d338..3d1ba141 100644 --- a/src/warnings/index.ts +++ b/src/warnings/index.ts @@ -35,6 +35,20 @@ export default class WarningSystem { }); } + private static createClassifiers(contactType: ContactType): IWarningClassifier[] { + const createUniquePropertyClassifiers = (properties: ContactProperty[], propertyType: 'place' | 'contact') => properties + .filter(prop => prop.unique) + .map(prop => new UniquePropertyClassifier(propertyType, prop)); + + const classifiers = [ + ...createUniquePropertyClassifiers(contactType.place_properties, 'place'), + ...createUniquePropertyClassifiers(contactType.contact_properties, 'contact'), + new RedundantReplaceClassifier(contactType), + ]; + + return classifiers; + } + private static runClassifiers(warningClassifiers: IWarningClassifier[], remotePlaces: RemotePlace[], localPlaces: Place[]): Warning[] { const warnings: Warning[] = []; const knownWarnings = new Set(); @@ -78,8 +92,8 @@ export default class WarningSystem { } const implicatedLocalPlacesWithoutBase = implicatedPlaces - .filter(remotePlace => remotePlace.stagedPlace) - .map(remotePlace => remotePlace.stagedPlace) as Place[]; + .map(remotePlace => remotePlace.stagedPlace) + .filter(Boolean) as Place[]; const implicatedLocalPlaces = [basePlace.stagedPlace, ...implicatedLocalPlacesWithoutBase]; const implicatedRemotePlaces = implicatedPlaces.filter(remotePlace => !remotePlace.stagedPlace); @@ -89,18 +103,4 @@ export default class WarningSystem { uniqueKey: classifier.uniqueKey(place), })); } - - private static createClassifiers(contactType: ContactType): IWarningClassifier[] { - const createUniquePropertyClassifiers = (properties: ContactProperty[], propertyType: 'place' | 'contact') => properties - .filter(prop => prop.unique) - .map(prop => new UniquePropertyClassifier(propertyType, prop)); - - const classifiers = [ - ...createUniquePropertyClassifiers(contactType.place_properties, 'place'), - ...createUniquePropertyClassifiers(contactType.contact_properties, 'contact'), - new RedundantReplaceClassifier(contactType), - ]; - - return classifiers; - } } diff --git a/src/warnings/redundant-replace-classifier.ts b/src/warnings/redundant-replace-classifier.ts index 1464b390..89c52c54 100644 --- a/src/warnings/redundant-replace-classifier.ts +++ b/src/warnings/redundant-replace-classifier.ts @@ -19,7 +19,7 @@ export default class RedundantReplaceClassifier implements IWarningClassifier { const confirmedDuplicates = placesToCompare .filter(place => place.type !== 'invalid' && place.stagedPlace && - place.stagedPlace?.resolvedHierarchy[0]?.id === replacementDetails.id); + place.stagedPlace.resolvedHierarchy?.[0]?.id === replacementDetails.id); if (confirmedDuplicates.length) { return confirmedDuplicates; diff --git a/test/services/files.spec.ts b/test/services/files.spec.ts deleted file mode 100644 index c815465d..00000000 --- a/test/services/files.spec.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { expect } from 'chai'; -import { ChtDoc, createChu, mockChtApi } from '../mocks'; -import createZip from '../../src/services/files'; -import SessionCache from '../../src/services/session-cache'; - -const subcounty: ChtDoc = { - _id: 'subcounty1-id', - name: 'subcounty1', -}; - -describe('services/files.ts', () => { - it('nominal', async () => { - const sessionCache = new SessionCache(); - const chtApi = mockChtApi([subcounty]); - await createChu(subcounty, 'File CHU', sessionCache, chtApi); - - const actual = createZip(sessionCache); - expect(Object.keys(actual.files)).to.deep.eq(['c_community_health_unit.csv']); - }); -});