Skip to content

Commit

Permalink
Rewrote unifiedDataLoader into typscript functions
Browse files Browse the repository at this point in the history
- Moved UnifiedDataLoader to a separate typescript file.
- The method is no longer an angular service, and instead exports two
'getUnified' methods.
- Updated other files that rely on this service.
- Tested getUnifiedMessagesForoInterval, as used in enketoHelper.
  • Loading branch information
the-bay-kay committed Oct 12, 2023
1 parent 83a4939 commit 2963e12
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 91 deletions.
8 changes: 4 additions & 4 deletions www/js/diary/services.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
'use strict';

import angular from 'angular';
import { getBaseModeByKey, getBaseModeOfLabeledTrip } from './diaryHelper';
import { SurveyOptions } from '../survey/survey';
import { getConfig } from '../config/dynamicConfig';
import { getRawEntries } from '../commHelper';
import { getUnifiedSensorDataForInterval, getUnifiedMessagesForInterval } from '../unifiedDataLoader'

angular.module('emission.main.diary.services', ['emission.plugin.logger',
'emission.services'])
.factory('Timeline', function($http, $ionicLoading, $ionicPlatform, $window,
$rootScope, UnifiedDataLoader, Logger, $injector) {
$rootScope, Logger, $injector) {
var timeline = {};
// corresponds to the old $scope.data. Contains all state for the current
// day, including the indication of the current day
Expand Down Expand Up @@ -232,7 +232,7 @@ angular.module('emission.main.diary.services', ['emission.plugin.logger',
Logger.log("About to pull location data for range "
+ moment.unix(tripStartTransition.data.ts).toString() + " -> "
+ moment.unix(tripEndTransition.data.ts).toString());
return UnifiedDataLoader.getUnifiedSensorDataForInterval("background/filtered_location", tq).then(function(locationList) {
return getUnifiedSensorDataForInterval("background/filtered_location", tq).then(function(locationList) {
if (locationList.length == 0) {
return undefined;
}
Expand Down Expand Up @@ -304,7 +304,7 @@ angular.module('emission.main.diary.services', ['emission.plugin.logger',
}
Logger.log("about to query for unprocessed trips from "
+moment.unix(tq.startTs).toString()+" -> "+moment.unix(tq.endTs).toString());
return UnifiedDataLoader.getUnifiedMessagesForInterval("statemachine/transition", tq)
return getUnifiedMessagesForInterval("statemachine/transition", tq)
.then(function(transitionList) {
if (transitionList.length == 0) {
Logger.log("No unprocessed trips. yay!");
Expand Down
6 changes: 3 additions & 3 deletions www/js/diary/timelineHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import moment from "moment";
import { getAngularService } from "../angular-react-helper";
import { displayError, logDebug } from "../plugin/logger";
import { getBaseModeByKey, getBaseModeOfLabeledTrip } from "./diaryHelper";
import { getUnifiedMessagesForInterval } from "../unifiedDataLoader";
import i18next from "i18next";

const cachedGeojsons = new Map();
Expand Down Expand Up @@ -147,13 +148,12 @@ export function getLocalUnprocessedInputs(pipelineRange, labelsFactory, notesFac
* @returns Promise an array with 1) results for labels and 2) results for notes
*/
export function getAllUnprocessedInputs(pipelineRange, labelsFactory, notesFactory) {
const UnifiedDataLoader = getAngularService('UnifiedDataLoader');
const tq = getUnprocessedInputQuery(pipelineRange);
const labelsPromises = labelsFactory.MANUAL_KEYS.map((key) =>
UnifiedDataLoader.getUnifiedMessagesForInterval(key, tq, true).then(labelsFactory.extractResult)
getUnifiedMessagesForInterval(key, tq).then(labelsFactory.extractResult)
);
const notesPromises = notesFactory.MANUAL_KEYS.map((key) =>
UnifiedDataLoader.getUnifiedMessagesForInterval(key, tq, true).then(notesFactory.extractResult)
getUnifiedMessagesForInterval(key, tq).then(notesFactory.extractResult)
);
return getUnprocessedResults(labelsFactory, notesFactory, labelsPromises, notesPromises);
}
Expand Down
83 changes: 1 addition & 82 deletions www/js/services.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,87 +4,6 @@ import angular from 'angular';
import { getRawEntries } from './commHelper';

angular.module('emission.services', ['emission.plugin.logger'])

.service('UnifiedDataLoader', function($window, Logger) {
var combineWithDedup = function(list1, list2) {
var combinedList = list1.concat(list2);
return combinedList.filter(function(value, i, array) {
var firstIndexOfValue = array.findIndex(function(element, index, array) {
return element.metadata.write_ts == value.metadata.write_ts;
});
return firstIndexOfValue == i;
});
};

// TODO: generalize to iterable of promises
var combinedPromise = function(localPromise, remotePromise, combiner) {
return new Promise(function(resolve, reject) {
var localResult = [];
var localError = null;

var remoteResult = [];
var remoteError = null;

var localPromiseDone = false;
var remotePromiseDone = false;

var checkAndResolve = function() {
if (localPromiseDone && remotePromiseDone) {
// time to return from this promise
if (localError && remoteError) {
reject([localError, remoteError]);
} else {
Logger.log("About to dedup localResult = "+localResult.length
+"remoteResult = "+remoteResult.length);
var dedupedList = combiner(localResult, remoteResult);
Logger.log("Deduped list = "+dedupedList.length);
resolve(dedupedList);
}
}
};

localPromise.then(function(currentLocalResult) {
localResult = currentLocalResult;
localPromiseDone = true;
}, function(error) {
localResult = [];
localError = error;
localPromiseDone = true;
}).then(checkAndResolve);

remotePromise.then(function(currentRemoteResult) {
remoteResult = currentRemoteResult;
remotePromiseDone = true;
}, function(error) {
remoteResult = [];
remoteError = error;
remotePromiseDone = true;
}).then(checkAndResolve);
})
}

// TODO: Generalize this to work for both sensor data and messages
// Do we even need to separate the two kinds of data?
// Alternatively, we can maintain another mapping between key -> type
// Probably in www/json...
this.getUnifiedSensorDataForInterval = function(key, tq) {
var localPromise = $window.cordova.plugins.BEMUserCache.getSensorDataForInterval(key, tq, true);
var remotePromise = getRawEntries([key], tq.startTs, tq.endTs)
.then(function(serverResponse) {
return serverResponse.phone_data;
});
return combinedPromise(localPromise, remotePromise, combineWithDedup);
};

this.getUnifiedMessagesForInterval = function(key, tq, withMetadata) {
var localPromise = $window.cordova.plugins.BEMUserCache.getMessagesForInterval(key, tq, true);
var remotePromise = getRawEntries([key], tq.startTs, tq.endTs)
.then(function(serverResponse) {
return serverResponse.phone_data;
});
return combinedPromise(localPromise, remotePromise, combineWithDedup);
}
})
.service('ControlHelper', function($window,
$ionicPopup,
Logger) {
Expand Down Expand Up @@ -198,4 +117,4 @@ angular.module('emission.services', ['emission.plugin.logger'])
return window.cordova.plugins.BEMConnectionSettings.getSettings();
};

})
});
4 changes: 2 additions & 2 deletions www/js/survey/enketo/enketoHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Form } from 'enketo-core';
import { XMLParser } from 'fast-xml-parser';
import i18next from 'i18next';
import { logDebug } from "../../plugin/logger";
import { getUnifiedMessagesForInterval } from "../../unifiedDataLoader";

export type PrefillFields = {[key: string]: string};

Expand Down Expand Up @@ -107,9 +108,8 @@ const _getMostRecent = (answers) => {
* with incremental updates, we may want to revisit this.
*/
export function loadPreviousResponseForSurvey(dataKey: string) {
const UnifiedDataLoader = getAngularService('UnifiedDataLoader');
const tq = window['cordova'].plugins.BEMUserCache.getAllTimeQuery();
logDebug("loadPreviousResponseForSurvey: dataKey = " + dataKey + "; tq = " + tq);
return UnifiedDataLoader.getUnifiedMessagesForInterval(dataKey, tq)
return getUnifiedMessagesForInterval(dataKey, tq)
.then(answers => _getMostRecent(answers))
}
90 changes: 90 additions & 0 deletions www/js/unifiedDataLoader.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { logInfo } from './plugin/logger'
import { getRawEntries } from './commHelper';

// Helper Functions for the getUnified methods.
const combineWithDedup = function(list1, list2) {
const combinedList = list1.concat(list2);
return combinedList.filter(function(value, i, array) {
const firstIndexOfValue = array.findIndex(function(element, index, array) {
return element.metadata.write_ts == value.metadata.write_ts;
});
return firstIndexOfValue == i;
});
};

// TODO: generalize to iterable of promises
const combinedPromise = function(localPromise, remotePromise, combiner) {
return new Promise(function(resolve, reject) {
var localResult = [];
var localError = null;

var remoteResult = [];
var remoteError = null;

var localPromiseDone = false;
var remotePromiseDone = false;

const checkAndResolve = function() {
if (localPromiseDone && remotePromiseDone) {
// time to return from this promise
if (localError && remoteError) {
reject([localError, remoteError]);
} else {
logInfo("About to dedup localResult = "+localResult.length
+"remoteResult = "+remoteResult.length);
const dedupedList = combiner(localResult, remoteResult);
logInfo("Deduped list = "+dedupedList.length);
resolve(dedupedList);
}
}
};

localPromise.then(function(currentLocalResult) {
localResult = currentLocalResult;
localPromiseDone = true;
}, function(error) {
localResult = [];
localError = error;
localPromiseDone = true;
}).then(checkAndResolve);

remotePromise.then(function(currentRemoteResult) {
remoteResult = currentRemoteResult;
remotePromiseDone = true;
}, function(error) {
remoteResult = [];
remoteError = error;
remotePromiseDone = true;
}).then(checkAndResolve);
})
}

interface serverData {
phone_data: Array<any>;
}
interface tQ {
key: string;
startTs: number;
endTs: number;
}
// TODO: Generalize this to work for both sensor data and messages
// Do we even need to separate the two kinds of data?
export const getUnifiedSensorDataForInterval = function(key: string, tq: tQ) {
const localPromise = window['cordova'].plugins.BEMUserCache.getSensorDataForInterval(key, tq, true);
const remotePromise = getRawEntries([key], tq.startTs, tq.endTs)
.then(function(serverResponse: serverData) {
console.log(`\n\n\n TQ : ${JSON.stringify(tq)}`)
return serverResponse.phone_data;
});
return combinedPromise(localPromise, remotePromise, combineWithDedup);
};

export const getUnifiedMessagesForInterval = function(key: string, tq: tQ) {
const localPromise = window['cordova'].plugins.BEMUserCache.getMessagesForInterval(key, tq, true);
const remotePromise = getRawEntries([key], tq.startTs, tq.endTs)
.then(function(serverResponse: serverData) {
console.log('==>', JSON.stringify(tq.endTs), ':',typeof tq.endTs);
return serverResponse.phone_data;
});
return combinedPromise(localPromise, remotePromise, combineWithDedup);
}

0 comments on commit 2963e12

Please sign in to comment.