LP#1848550: client-side caching of org settings for AngularJS user/jeffdavis/lp1848550-cache-settings
authorJeff Davis <jeff.davis@bc.libraries.coop>
Wed, 23 Oct 2019 23:25:41 +0000 (16:25 -0700)
committerJeff Davis <jeff.davis@bc.libraries.coop>
Tue, 29 Oct 2019 23:24:58 +0000 (16:24 -0700)
The web client almost always does live lookups any time it needs to
check an org setting.  But these settings rarely change, so it would
make sense to cache them.  They're already cached using Lovefield in
order to support offline; this commit checks the cache first, and only
does a live lookup if the setting is uncached or expired (i.e. added to
cache more than 12 hours ago).  Offline ignores the 12-hour expire time
so that we always have settings to work with when the server is
unreachable.

Signed-off-by: Jeff Davis <jeff.davis@bc.libraries.coop>
Open-ILS/web/js/ui/default/staff/offline-db-worker.js
Open-ILS/web/js/ui/default/staff/services/lovefield.js
Open-ILS/web/js/ui/default/staff/services/org.js

index 3239900..4a139dd 100644 (file)
@@ -30,6 +30,7 @@ function createCacheTables(meta) {
     meta.createTable('Setting').
         addColumn('name', lf.Type.STRING).
         addColumn('value', lf.Type.STRING).
+        addColumn('cachedate', lf.Type.DATE_TIME).  // when was it last updated
         addPrimaryKey(['name']);
 
     meta.createTable('Object').
index e7ec496..5a82a12 100644 (file)
@@ -296,7 +296,7 @@ angular.module('egCoreMod')
 
         var rows = [];
         angular.forEach(settings, function (val, key) {
-            rows.push({name  : key, value : JSON.stringify(val)});
+            rows.push({name  : key, value : JSON.stringify(val), cachedate : new Date()});
         });
 
         return service.request({
index 36c9ed2..e4b054a 100644 (file)
@@ -99,6 +99,7 @@ function($q,  egEnv,  egAuth,  egNet , $injector) {
     }
 
     var egLovefield = null;
+
     // returns a promise, resolved with a hash of setting name =>
     // setting value for the selected org unit.  Org unit defaults to 
     // auth workstation org unit.
@@ -111,6 +112,9 @@ function($q,  egEnv,  egAuth,  egNet , $injector) {
         if (!angular.isArray(names)) names = [names];
 
         if (lf.isOffline) {
+            // for offline, just use whatever we have managed to cache,
+            // even if the value is expired (since we can't refresh it
+            // from the server)
             return egLovefield.getSettingsCache(names).then(
                 function(settings) {
                     var hash = {};
@@ -126,26 +130,73 @@ function($q,  egEnv,  egAuth,  egNet , $injector) {
 
         if (!egAuth.user()) return $q.when();
 
-        var deferred = $q.defer();
         ou_id = ou_id || egAuth.user().ws_ou();
-        var here = (ou_id == egAuth.user().ws_ou());
+        if (ou_id != egAuth.user().ws_ou()) {
+            // we only cache settings for the current working location;
+            // if we have requested settings for some other org unit,
+            // skip the cache and pull settings directly from the server
+            return service.settingsFromServer(names, ou_id);
+        }
 
-       
-        if (here) { 
-            // only cache org settings retrieved for the current 
-            // workstation org unit.
-            var newNames = [];
+        var deferred = $q.defer();
+        
+        var newNames = [];
+        angular.forEach(names, function(name) {
+            if (!angular.isDefined(service.cachedSettings[name]))
+                // we don't have a value for this setting yet 
+                newNames.push(name)
+        });
+
+        // only retrieve uncached values
+        names = newNames;
+        if (names.length == 0)
+            return $q.when(service.cachedSettings);
+
+        // get settings from online cache where possible;
+        // otherwise, get settings from server
+        egLovefield.getSettingsCache(names)
+        .then(function(settings) {
+
+            // populate values from offline cache
+            var cache_expiry = 43200000; // XXX hard-coded to 12 hours; make configurable?
+            angular.forEach(settings, function (s) {
+                if ((new Date().getTime() - s.cachedate.getTime()) <= cache_expiry)
+                    service.cachedSettings[s.name] = s.value;
+            });
+
+            // check if any requested settings were not in offline cache
+            var uncached = [];
             angular.forEach(names, function(name) {
                 if (!angular.isDefined(service.cachedSettings[name]))
-                    newNames.push(name)
+                    uncached.push(name);
             });
 
-            // only retrieve uncached values
-            names = newNames;
-            if (names.length == 0)
-                return $q.when(service.cachedSettings);
+            if (uncached.length == 0) {
+                // all requested settings were in the offline cache already
+                deferred.resolve(service.cachedSettings);
+            } else {
+                // cache was missing some settings; grab those from the server
+                service.settingsFromServer(uncached, ou_id)
+                .then(function() {
+                    deferred.resolve(service.cachedSettings);
+                });
+            }
+        });
+        return deferred.promise;
+    }
+
+    service.settingsFromServer = function(names, ou_id) {
+        if (!egLovefield) {
+            egLovefield = $injector.get('egLovefield');
         }
 
+        // allow non-array
+        if (!angular.isArray(names)) names = [names];
+
+        var deferred = $q.defer();
+        ou_id = ou_id || egAuth.user().ws_ou();
+        var here = (ou_id == egAuth.user().ws_ou());
+
         egNet.request(
             'open-ils.actor',
             'open-ils.actor.ou_setting.ancestor_default.batch',