Fdans has uploaded a new change for review. ( 
https://gerrit.wikimedia.org/r/347305 )

Change subject: [wip] Unifies usage of aqs api and datasets api
......................................................................

[wip] Unifies usage of aqs api and datasets api

Bug: T161933

Change-Id: I10f37f9998b83d07f7c411b62563de2521e7a90b
---
M src/app/apis/aqs-api.js
M src/components/visualizers/visualizer/visualizer.js
2 files changed, 116 insertions(+), 104 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/analytics/dashiki 
refs/changes/05/347305/1

diff --git a/src/app/apis/aqs-api.js b/src/app/apis/aqs-api.js
index 8f339d2..e9379b5 100644
--- a/src/app/apis/aqs-api.js
+++ b/src/app/apis/aqs-api.js
@@ -27,91 +27,118 @@
         });
     }
 
-    /**
-     * Parameters
-     *  metric         : An object representing a metric.
-     *  project        : A Wiki project database name (enwiki, commonswiki, 
etc).
-     *  accessMethods  : Access methods to split data by.
-     * Returns
-     *  A promise that wraps data for the metric/project transformed via the 
converter
-     *  Mobile, desktop and app breakdowns translate to different requests.
-     */
-    AQSApi.prototype.getData = function (metric, project, accessMethods) {
-        var deferred = new $.Deferred(),
-            apiConfig = this.config.aqsApi[metric.name],
-            converter = this.dataConverters[metric.name];
+    AQSApi.prototype = {
+        /**
+         * Parameters
+         *  metric         : An object representing a metric.
+         *  project        : A Wiki project database name (enwiki, 
commonswiki, etc).
+         *  accessMethods  : Access methods to split data by.
+         * Returns
+         *  A promise that wraps data for the metric/project transformed via 
the converter
+         *  Mobile, desktop and app breakdowns translate to different requests.
+         */
+        getData: function (metric, projects, accessMethods) {
+            var converter = this.dataConverters[metric.name];
+            var deferred = new $.Deferred(),
+                apiConfig = this.config.aqsApi[metric.name];
 
-        if (!apiConfig) {
-            deferred.resolve(new TimeseriesData());
+            if (!apiConfig) {
+                deferred.resolve(new TimeseriesData());
+                return deferred.promise();
+            }
+
+            // Normalize the access method breakdown.
+            if (!accessMethods || !accessMethods.length) {
+                accessMethods = ['All'];
+            }
+            accessMethods = _.map(accessMethods, function (method) {
+                return apiConfig.breakdownOptions[method];
+            });
+
+            if (typeof projects === 'string') {
+                projects = [projects];
+            }
+
+            var promises = [];
+            apiConfig.projectMap = {};
+
+            projects.forEach(function (project) {
+                // Get the project URL with sitematrix.
+                var sitematrixPromise = sitematrix.getProjectUrl(this.config, 
project);
+                function handleProjectUrl(projectUrl) {
+                    var granularity = metric.granularity || 'daily';
+                    // Perform the requests.
+                    apiConfig.projectMap[projectUrl.replace('.org', '')] = 
project;
+                    promises = promises.concat(getPromisesForAccessMethods(
+                        accessMethods,
+                        projectUrl,
+                        granularity,
+                        apiConfig
+                    ));
+                    if(promises.length === projects.length * 
accessMethods.length) {
+                        handlePromisesFinished(promises, apiConfig, converter, 
deferred);
+                    }
+                }
+                sitematrixPromise.done(handleProjectUrl);
+                sitematrixPromise.fail(function () {
+                    handleProjectUrl('all-projects');
+                });
+            }.bind(this));
             return deferred.promise();
         }
-
-        // Normalize the access method breakdown.
-        if (!accessMethods || !accessMethods.length) {
-            accessMethods = ['All'];
-        }
-        accessMethods = _.map(accessMethods, function (method) {
-            return apiConfig.breakdownOptions[method];
-        });
-
-        // Get the project URL with sitematrix.
-        var sitematrixPromise = sitematrix.getProjectUrl(this.config, project);
-        sitematrixPromise.done(function (projectUrl) {
-            var promises = [],
-                granularity = metric.granularity || 'daily',
-                endDate = moment().format(apiConfig.dateFormat[granularity]),
-                breakdownCamelCase = _.camelCase(apiConfig.breakdownParameter);
-
-            // Perform the requests.
-            _.forEach(accessMethods, function (method) {
-                var params = {
-                    project: projectUrl,
-                    agent: 'user',  // Only used in the Pageviews endpoint.
-                    granularity: granularity,
-                    start: apiConfig.dataStart,
-                    end: endDate
-                };
-                params[breakdownCamelCase] = method;
-                promises.push(pageviews[apiConfig.endpoint](params));
-            });
-
-            // Return when we have all data.
-            Promise.all(promises).then(function (data) {
-                var timeseries = [],
-                    breakdownKebabCase = 
_.kebabCase(apiConfig.breakdownParameter);
-
-                _.forEach(data, function (dataForMethod) {
-                    // Use the dbname as the label, to match colors with 
Project Selector
-                    // if we want to re-label, we need to change both.
-                    var opt = {
-                        label: project,
-                        pattern: dataForMethod.items[0][breakdownKebabCase]
-                    };
-                    timeseries.push(converter(opt, dataForMethod));
-                });
-
-                // Datasets are disjoint but we need to add them so that
-                // the timeseries object makes sense.
-                var ts = TimeseriesData.mergeAll(timeseries)
-                deferred.resolve(ts);
-
-            }, function (reason) {
-                deferred.resolve(new TimeseriesData());
-                logger.error(reason);
-            }).catch(function (error) {
-                deferred.resolve(new TimeseriesData());
-                logger.error(error);
-            });
-
-        });
-
-        sitematrixPromise.fail(function () {
-            //something went wrong, make sure to return empty data
-            deferred.resolve(new TimeseriesData());
-        });
-
-        return deferred.promise();
     };
 
+    function getPromisesForAccessMethods (methods, projectUrl, granularity, 
apiConfig) {
+        var breakdownCamelCase = _.camelCase(apiConfig.breakdownParameter),
+            endDate = moment().format(apiConfig.dateFormat[granularity]);
+        return methods.map(function (method) {
+            var params = {
+                project: projectUrl,
+                agent: 'user',  // Only used in the Pageviews endpoint.
+                granularity: granularity,
+                start: apiConfig.dataStart,
+                end: endDate
+            };
+            params[breakdownCamelCase] = method;
+            return pageviews[apiConfig.endpoint](params);
+        });
+    }
+
+    function handlePromisesFinished (promises, apiConfig, converter, deferred) 
{
+        // Return when we have all data.
+        Promise.all(promises).then(function (data) {
+            deferred.resolve(_generateTimeseriesForAllData(
+                    data,
+                    apiConfig,
+                    converter
+            ));
+        }, function (reason) {
+            deferred.resolve(new TimeseriesData());
+            logger.error(reason);
+        }).catch(function (error) {
+            deferred.resolve(new TimeseriesData());
+            logger.error(error);
+        });
+    }
+
+    function _generateTimeseriesForAllData (data, apiConfig, converter) {
+        var timeseries = [],
+            breakdownKebabCase = _.kebabCase(apiConfig.breakdownParameter);
+
+        _.forEach(data, function (dataForMethod) {
+            // Use the dbname as the label, to match colors with Project 
Selector
+            // if we want to re-label, we need to change both.
+            var opt = {
+                label: apiConfig.projectMap[dataForMethod.items[0].project],
+                pattern: dataForMethod.items[0][breakdownKebabCase]
+            };
+            timeseries.push(converter(opt, dataForMethod));
+        }.bind(this));
+
+        // Datasets are disjoint but we need to add them so that
+        // the timeseries object makes sense.
+        return TimeseriesData.mergeAll(timeseries);
+    }
+
     return new AQSApi(siteConfig);
 });
diff --git a/src/components/visualizers/visualizer/visualizer.js 
b/src/components/visualizers/visualizer/visualizer.js
index 19002a9..18cfe41 100644
--- a/src/components/visualizers/visualizer/visualizer.js
+++ b/src/components/visualizers/visualizer/visualizer.js
@@ -39,30 +39,15 @@
         }
 
         this.data = ko.observable(new TimeseriesData());
-
-        // don't love this , the point of having an api finder is to have a 
common interface
-        // for apis such it doesn't matter which one we are using
-        if (apiType === 'aqsApi'){
-            var aqs = params.aqs;
-            var projects = aqs.projects;
-
-            // no changes should be needed to api if we wait until all 
promises are resolved to render
-            var promises = projects.map(function (project) {
-                    return api.getData({'name':aqs.name, 
'granularity':aqs.granularity}, project);
-            });
-
-            //invoqued when all promises are done
-            Promise.all(promises).then(function (data) {
-                this.data(TimeseriesData.mergeAll(data));
-            }.bind(this));
-
-
-        } else {
-            api.getData(graph, 'all').done(this.data);
+        var projects = 'all';
+        var aqs = params.aqs;
+        if (aqs) {
+            graph.granularity = aqs.granularity;
+            graph.name = aqs.name;
+            projects = aqs.projects;
         }
-
-
-
+        var metricInfo = graph;
+        api.getData(metricInfo, projects).done(this.data);
         this.startDate = ko.observable(graph.startDate);
         this.minDate = ko.observable(graph.startDate);
         this.endDate = ko.observable();

-- 
To view, visit https://gerrit.wikimedia.org/r/347305
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I10f37f9998b83d07f7c411b62563de2521e7a90b
Gerrit-PatchSet: 1
Gerrit-Project: analytics/dashiki
Gerrit-Branch: master
Gerrit-Owner: Fdans <fd...@wikimedia.org>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to