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

Update base survey objects for serialized data #374

Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,9 @@ export class BaseAddress extends Uuidable {
this.addressId = params.addressId;
this.internalId = params.internalId;
}

// params must be sanitized and must be valid:
static unserialize(params: BaseAddressAttributes): BaseAddress {
return new BaseAddress(params);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,13 @@
*/

import { OptionalValidity, IValidatable } from './Validatable';
import { BasePerson } from './BasePerson';
import { BasePlace } from './BasePlace';
import { Weightable, Weight, validateWeights } from './Weight';
import * as HAttr from './attributeTypes/HouseholdAttributes';
import { Uuidable } from './Uuidable';
import { Vehicleable } from './Vehicleable';
import { BaseVehicle } from './BaseVehicle';

type BaseHouseholdAttributes = {
_uuid?: string;

baseMembers?: BasePerson[];
baseHome?: BasePlace;

size?: number;
carNumber?: number;
twoWheelNumber?: number;
Expand All @@ -32,20 +25,14 @@ type BaseHouseholdAttributes = {
// must be anonymized:
contactPhoneNumber?: string; // TODO: normalize and/or validate phone numbers
contactEmail?: string;
} & Weightable &
Vehicleable;
} & Weightable;

type ExtendedHouseholdAttributes = BaseHouseholdAttributes & { [key: string]: any };

class BaseHousehold extends Uuidable implements IValidatable {
_isValid: OptionalValidity;
_weights?: Weight[];

baseMembers?: BasePerson[];
baseHome?: BasePlace;

baseVehicles?: BaseVehicle[];

/**
* Here it would be better to just calculate from household members,
* but in most surveys, we first ask the respondent for the household
Expand Down Expand Up @@ -84,11 +71,6 @@ class BaseHousehold extends Uuidable implements IValidatable {
this._isValid = undefined;
this._weights = params._weights;

this.baseMembers = params.baseMembers || [];
this.baseHome = params.baseHome;

this.baseVehicles = params.baseVehicles || [];

this.size = params.size;
this.carNumber = params.carNumber;
this.twoWheelNumber = params.twoWheelNumber;
Expand All @@ -101,6 +83,11 @@ class BaseHousehold extends Uuidable implements IValidatable {
this.contactEmail = params.contactEmail;
}

// params must be sanitized and must be valid:
static unserialize(params: BaseHouseholdAttributes): BaseHousehold {
return new BaseHousehold(params);
}

validate(): OptionalValidity {
// TODO: implement:
this._isValid = true;
Expand Down Expand Up @@ -148,43 +135,6 @@ class BaseHousehold extends Uuidable implements IValidatable {
errors.push(...weightsErrors);
}

// Validate baseMembers:
if (dirtyParams.baseMembers !== undefined && !Array.isArray(dirtyParams.baseMembers)) {
errors.push(new Error('BaseHousehold validateParams: baseMembers should be an array'));
} else if (dirtyParams.baseMembers !== undefined && dirtyParams.baseMembers.length > 0) {
for (let i = 0, countI = dirtyParams.baseMembers.length; i < countI; i++) {
if (!dirtyParams.baseMembers[i] || !(dirtyParams.baseMembers[i] instanceof BasePerson)) {
errors.push(
new Error(
`BaseHousehold validateParams: baseMembers index ${i} is not an instance of BasePerson`
)
);
}
}
}

// Validate baseVehicles:
if (dirtyParams.baseVehicles !== undefined && !Array.isArray(dirtyParams.baseVehicles)) {
errors.push(new Error('BaseHousehold validateParams: baseVehicles should be an array'));
} else if (dirtyParams.baseVehicles !== undefined && dirtyParams.baseVehicles.length > 0) {
for (let i = 0, countI = dirtyParams.baseVehicles.length; i < countI; i++) {
if (!dirtyParams.baseVehicles[i] || !(dirtyParams.baseVehicles[i] instanceof BaseVehicle)) {
errors.push(
new Error(
`BaseHousehold validateParams: baseVehicles index ${i} is not an instance of BaseVehicle`
)
);
}
}
}

// Validate baseHome:
if (dirtyParams.baseHome !== undefined) {
if (!(dirtyParams.baseHome instanceof BasePlace)) {
errors.push(new Error('BaseHousehold validateParams: baseHome is not an instance of BasePlace'));
}
}

// Validate size:
if (dirtyParams.size !== undefined && (!Number.isInteger(dirtyParams.size) || dirtyParams.size < 0)) {
errors.push(new Error('BaseHousehold validateParams: size should be a positive integer'));
Expand Down
72 changes: 26 additions & 46 deletions packages/evolution-common/src/services/baseObjects/BaseInterview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,12 @@
* License text available at https://opensource.org/licenses/MIT
*/

import { parsePhoneNumber } from 'libphonenumber-js';
import { OptionalValidity, IValidatable } from './Validatable';
import { Surveyable, SurveyableAttributes } from './Surveyable';
import { Survey, SurveyAttributes } from './Survey';
import { Sample, SampleAttributes } from './Sample';
import { Uuidable } from './Uuidable';
import { BasePerson } from './BasePerson';
import { BaseHousehold } from './BaseHousehold';
import { BaseOrganization } from './BaseOrganization';
import { parseDate } from '../../utils/DateUtils';

export const devices = ['tablet', 'mobile', 'desktop', 'other', 'unknown'] as const;

Expand All @@ -21,34 +20,26 @@ export type BaseInterviewAttributes = {
_uuid?: string;

accessCode?: string;
assignedDate?: Date; // date, the assigned date for the survey (trips date most of the time)
assignedDate?: Date | string; // date, the assigned date for the survey (trips date most of the time)
contactPhoneNumber?: string; // phone number
contactEmail?: string; // email

_startedAt?: Date;
_updatedAt?: Date;
_completedAt?: Date;

baseHousehold?: BaseHousehold; // for household-based surveys
basePerson?: BasePerson; // for person-based with no household data surveys
baseOrganization?: BaseOrganization; // for organization-based surveys
_startedAt?: Date | string;
_updatedAt?: Date | string;
_completedAt?: Date | string;

_language?: string; // two-letter ISO 639-1 code
_source?: string; // source for the interview (web, phone, social, etc.)
_isCompleted?: boolean;

_device?: Device;
} & SurveyableAttributes;
};

export type ExtendedInterviewAttributes = BaseInterviewAttributes & { [key: string]: any };

export class BaseInterview extends Surveyable implements IValidatable {
_isValid: OptionalValidity;

baseHousehold?: BaseHousehold;
basePerson?: BasePerson;
baseOrganization?: BaseOrganization;

accessCode?: string;
assignedDate?: Date; // date, the assigned date for the survey (trips date most of the time)
contactPhoneNumber?: string; // phone number
Expand All @@ -71,21 +62,17 @@ export class BaseInterview extends Surveyable implements IValidatable {
'accessCode'
];

constructor(params: BaseInterviewAttributes | ExtendedInterviewAttributes) {
constructor(params: (BaseInterviewAttributes | ExtendedInterviewAttributes) & SurveyableAttributes) {
super(params.survey, params.sample, params.sampleBatchNumber, params._uuid);

this.baseHousehold = params.baseHousehold;
this.basePerson = params.basePerson;
this.baseOrganization = params.baseOrganization;

this.accessCode = params.accessCode;
this.assignedDate = params.assignedDate;
this.assignedDate = parseDate(params.assignedDate);
this.contactPhoneNumber = params.contactPhoneNumber;
this.contactEmail = params.contactEmail;

this._startedAt = params._startedAt;
this._updatedAt = params._updatedAt;
this._completedAt = params._completedAt;
this._startedAt = parseDate(params._startedAt);
this._updatedAt = parseDate(params._updatedAt);
this._completedAt = parseDate(params._completedAt);

this._language = params._language;
this._source = params._source;
Expand All @@ -94,6 +81,13 @@ export class BaseInterview extends Surveyable implements IValidatable {
this._device = params._device;
}

// params must be sanitized and must be valid:
static unserialize(params: BaseInterviewAttributes & { survey: SurveyAttributes; sample: SampleAttributes, sampleBatchNumber?: number }): BaseInterview {
const survey = Survey.unserialize(params.survey);
const sample = Sample.unserialize(params.sample);
return new BaseInterview({ ...params, survey, sample, sampleBatchNumber: params.sampleBatchNumber });
}

validate(): OptionalValidity {
// TODO: implement:
this._isValid = true;
Expand All @@ -112,7 +106,7 @@ export class BaseInterview extends Surveyable implements IValidatable {
*/
static create(dirtyParams: { [key: string]: any }): BaseInterview | Error[] {
const errors = BaseInterview.validateParams(dirtyParams);
return errors.length > 0 ? errors : new BaseInterview(dirtyParams as ExtendedInterviewAttributes);
return errors.length > 0 ? errors : new BaseInterview(dirtyParams as (ExtendedInterviewAttributes & SurveyableAttributes));
}

/**
Expand All @@ -126,6 +120,11 @@ export class BaseInterview extends Surveyable implements IValidatable {
static validateParams(dirtyParams: { [key: string]: any }): Error[] {
const errors: Error[] = [];

dirtyParams.assignedDate = parseDate(dirtyParams.assignedDate);
dirtyParams._startedAt = parseDate(dirtyParams._startedAt);
dirtyParams._updatedAt = parseDate(dirtyParams._updatedAt);
dirtyParams._completedAt = parseDate(dirtyParams._completedAt);

// Validate params object:
if (!dirtyParams || typeof dirtyParams !== 'object') {
errors.push(new Error('BaseInterview validateParams: params is undefined or invalid'));
Expand Down Expand Up @@ -193,25 +192,6 @@ export class BaseInterview extends Surveyable implements IValidatable {
errors.push(new Error('BaseInterview validateParams: invalid _updatedAt'));
}

// Validate baseHousehold (if provided)
if (dirtyParams.baseHousehold !== undefined && !(dirtyParams.baseHousehold instanceof BaseHousehold)) {
errors.push(
new Error('BaseInterview validateParams: baseHousehold should be an instance of BaseHousehold')
);
}

// Validate basePerson (if provided)
if (dirtyParams.basePerson !== undefined && !(dirtyParams.basePerson instanceof BasePerson)) {
errors.push(new Error('BaseInterview validateParams: basePerson should be an instance of BasePerson'));
}

// Validate baseOrganization (if provided)
if (dirtyParams.baseOrganization !== undefined && !(dirtyParams.baseOrganization instanceof BaseOrganization)) {
errors.push(
new Error('BaseInterview validateParams: baseOrganization should be an instance of BaseOrganization')
);
}

// Validate contactPhoneNumber (if provided):
// Precise phone number validation must be done in audits, because incorrect phone number should not prevent the interview from being created.
if (dirtyParams.contactPhoneNumber !== undefined && typeof dirtyParams.contactPhoneNumber !== 'string') {
Expand Down
70 changes: 20 additions & 50 deletions packages/evolution-common/src/services/baseObjects/BaseJourney.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,17 @@
import { OptionalValidity, IValidatable } from './Validatable';
import { Weightable, Weight, validateWeights } from './Weight';
import { Uuidable } from './Uuidable';
import { BaseVisitedPlace } from './BaseVisitedPlace';
import { BaseTripChain } from './BaseTripChain';
import { BaseTrip } from './BaseTrip';
import { parseDate } from '../../utils/DateUtils';

type BaseJourneyAttributes = {
_uuid?: string;

startDate: Date;
startTime: number;
endDate: Date;
endTime: number;
startDate?: Date | string;
startTime?: number;
endDate?: Date | string;
endTime?: number;
name?: string;
baseVisitedPlaces?: BaseVisitedPlace[];
baseTrips?: BaseTrip[];
baseTripChains?: BaseTripChain[];

} & Weightable;

type ExtendedJourneyAttributes = BaseJourneyAttributes & { [key: string]: any };
Expand All @@ -41,14 +37,11 @@ class BaseJourney extends Uuidable implements IBaseJourneyAttributes, IValidatab
_isValid: OptionalValidity;
_weights?: Weight[];

startDate: Date;
startTime: number;
endDate: Date;
endTime: number;
startDate?: Date;
startTime?: number;
endDate?: Date;
endTime?: number;
name?: string;
baseVisitedPlaces?: BaseVisitedPlace[];
baseTrips?: BaseTrip[];
baseTripChains?: BaseTripChain[];

_confidentialAttributes: string[] = [
// these attributes should be hidden when exporting
Expand All @@ -60,14 +53,16 @@ class BaseJourney extends Uuidable implements IBaseJourneyAttributes, IValidatab
this._isValid = undefined;
this._weights = params._weights;

this.startDate = params.startDate;
this.startDate = parseDate(params.startDate);
this.startTime = params.startTime;
this.endDate = params.endDate;
this.endDate = parseDate(params.endDate);
this.endTime = params.endTime;
this.name = params.name;
this.baseVisitedPlaces = params.baseVisitedPlaces;
this.baseTripChains = params.baseTripChains;
this.baseTrips = params.baseTrips;
}

// params must be sanitized and must be valid:
static unserialize(params: BaseJourneyAttributes): BaseJourney {
return new BaseJourney(params);
}

validate(): OptionalValidity {
Expand Down Expand Up @@ -99,6 +94,9 @@ class BaseJourney extends Uuidable implements IBaseJourneyAttributes, IValidatab
static validateParams(dirtyParams: { [key: string]: any }): Error[] {
const errors: Error[] = [];

dirtyParams.startDate = parseDate(dirtyParams.startDate);
dirtyParams.endDate = parseDate(dirtyParams.endDate);

// Validate params object:
if (!dirtyParams || typeof dirtyParams !== 'object') {
errors.push(new Error('BaseJourney validateParams: params is undefined or invalid'));
Expand Down Expand Up @@ -155,34 +153,6 @@ class BaseJourney extends Uuidable implements IBaseJourneyAttributes, IValidatab
errors.push(new Error('BaseJourney validateParams: name should be a string'));
}

// Validate baseVisitedPlaces (if provided)
if (
dirtyParams.baseVisitedPlaces !== undefined &&
(!Array.isArray(dirtyParams.baseVisitedPlaces) ||
!dirtyParams.baseVisitedPlaces.every((vp) => vp instanceof BaseVisitedPlace))
) {
errors.push(
new Error('BaseJourney validateParams: baseVisitedPlaces should be an array of BaseVisitedPlace')
);
}

// Validate baseTrips (if provided)
if (
dirtyParams.baseTrips !== undefined &&
(!Array.isArray(dirtyParams.baseTrips) || !dirtyParams.baseTrips.every((trip) => trip instanceof BaseTrip))
) {
errors.push(new Error('BaseJourney validateParams: baseTrips should be an array of BaseTrip'));
}

// Validate baseTripChains (if provided)
if (
dirtyParams.baseTripChains !== undefined &&
(!Array.isArray(dirtyParams.baseTripChains) ||
!dirtyParams.baseTripChains.every((tc) => tc instanceof BaseTripChain))
) {
errors.push(new Error('BaseJourney validateParams: baseTripChains should be an array of BaseTripChain'));
}

return errors;
}
}
Expand Down
Loading
Loading