Skip to content

Commit

Permalink
Order datasets selectors
Browse files Browse the repository at this point in the history
Previously the dataset selectors were not in the desired order due to the default value appearing first. This commit fixes this for the nextstrain.org server. Note that this functionality will be moved to the client when the new server API is implemented (see nextstrain/auspice#687).

This commit closes Auspice issue nextstrain/auspice#696.
  • Loading branch information
jameshadfield committed Feb 28, 2019
1 parent 8fcbe07 commit 653355a
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 29 deletions.
49 changes: 32 additions & 17 deletions auspice/server/getDatasetHelpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,32 +31,47 @@ const decideSourceFromPrefix = (prefix) => {
* "default" one.
*/
const correctPrefixFromAvailable = (source, prefixParts) => {

if (!global.availableDatasets[source]) {
utils.verbose("Cant compare against available datsets as there are none!");
return prefixParts;
}
const prefix = prefixParts.join("/");

/* is there an exact match in the manifest? */
for (let i=0; i<global.availableDatasets[source].length; i++) {
if (global.availableDatasets[source][i].request === prefix) {
utils.verbose("Matches an availible dataset");
return prefixParts;
if (source === "staging" && prefixParts[0] !== "staging") {
prefixParts.unshift("staging");
}

const doesPathExist = (pathToCheck) => {
for (let i=0; i<global.availableDatasets[source].length; i++) {
if (global.availableDatasets[source][i].request === pathToCheck) {
utils.verbose(` ${pathToCheck} Matches an availible dataset`);
return true;
}
}
return false;
};

const removeStagingFromFront = (parts) => {
if (parts[0] === "staging") parts.shift();
return parts;
};

let prefix = prefixParts.join("/");

if (doesPathExist(prefix)) {
return removeStagingFromFront(prefixParts);
}

/* is there a partial match in the manifest? If so, use the
available datasets to return the correct path */
let possibleDatasets = global.availableDatasets[source]
.map((d) => d.request.split("/"));
prefixParts.forEach((part, idx) => {
possibleDatasets = possibleDatasets.filter((dataset) => dataset[idx] === part);
});
if (possibleDatasets.length) {
utils.verbose(`Changing ${prefixParts.join("/")} to ${possibleDatasets[0]}`);
return possibleDatasets[0];
/* if we are here, then the path doesn't match any available datasets exactly */
if (prefix in global.availableDatasets.defaults[source]) {
prefix = `${prefix}/${global.availableDatasets.defaults[source][prefix]}`;
const parts = prefix.split("/");
if (doesPathExist(prefix)) {
return removeStagingFromFront(parts);
}
return correctPrefixFromAvailable(source, parts);
}
utils.verbose("No matches in available datasets for this prefix. Proceeding anyway.");

return prefixParts;
};

Expand Down
35 changes: 23 additions & 12 deletions auspice/server/setAvailableDatasets.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,28 +10,36 @@ const utils = require("./utils");
* This mimics the behavior of the auspice server around version 1.32.
* Ideally we can find a solution which doesn't use globals.
*/
global.availableDatasets = {};
global.availableDatasets = {defaults: {}};


const convertManifestJsonToAvailableDatasetList = (old) => {
const convertManifestJsonToAvailableDatasetList = (old, pathPrefix=false) => {
const allParts = [];
const defaults = {}; /* holds the defaults, used to complete incomplete paths */
const recurse = (partsSoFar, obj) => {
if (typeof obj === "string") {
// done
allParts.push(partsSoFar);
}
let keys = Object.keys(obj);

/* if there's only one key in the object it's the "name" of the level
in the heirachy, e.g. "category" or "lineage", which we skip over.
Note that for levels with only 1 option there's 2 keys (one is "default") */
if (keys.length === 1) {
obj = obj[keys[0]]; // eslint-disable-line
keys = Object.keys(obj); // skip level
}

const defaultValue = obj.default;
if (!defaultValue) {
return;
}
const orderedKeys = [defaultValue];
defaults[partsSoFar.join("/")] = defaultValue;

const orderedKeys = [];
keys.forEach((k) => {
if (k !== defaultValue && k !== "default") {
if (k !== "default") {
orderedKeys.push(k);
}
});
Expand All @@ -42,9 +50,11 @@ const convertManifestJsonToAvailableDatasetList = (old) => {
});
};

recurse([], old.pathogen);
return allParts
.map((fileParts) => ({request: fileParts.join("/")}));
recurse(pathPrefix ? [pathPrefix] : [], old.pathogen);
return [
allParts.map((fileParts) => ({request: fileParts.join("/")})),
defaults
];
};

/* setAvailableDatasetsFromManifest
Expand All @@ -60,22 +70,23 @@ const setAvailableDatasetsFromManifest = async () => {
try {
let data = await fetch(`http://data.nextstrain.org/manifest_guest.json`)
.then((result) => result.json());
data = convertManifestJsonToAvailableDatasetList(data);
let defaultsForPathCompletion;
[data, defaultsForPathCompletion] = convertManifestJsonToAvailableDatasetList(data);
utils.verbose(`Successfully got manifest for "live"`);
global.availableDatasets.live = data;
global.availableDatasets.defaults.live = defaultsForPathCompletion;
} catch (err) {
utils.warn(`Failed to getch manifest for "live"`);
}
/* STAGING */
try {
let data = await fetch(`http://staging.nextstrain.org/manifest_guest.json`)
.then((result) => result.json());
data = convertManifestJsonToAvailableDatasetList(data);
data.forEach((dataset) => {
dataset.request = `staging/${dataset.request}`;
});
let defaultsForPathCompletion;
[data, defaultsForPathCompletion] = convertManifestJsonToAvailableDatasetList(data, "staging");
utils.verbose(`Successfully got manifest for "staging"`);
global.availableDatasets.staging = data;
global.availableDatasets.defaults.staging = defaultsForPathCompletion;
} catch (err) {
utils.warn(`Failed to fetch manifest for "staging"`);
}
Expand Down

0 comments on commit 653355a

Please sign in to comment.