wikimedica-disease-search/app/src/data/mock/index.js

153 lines
4.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @module
* Fonctions de requêtage des données dexemple.
*/
import {termTypes} from '../model.js';
import * as data from './data.js';
/**
* Recherche lensemble des maladies liées par une relation « a pour symptôme »
* avec un ensemble de termes donné.
*
* @param query Ensemble de termes attendus.
* @return Liste des maladies correspondantes.
*/
export const diseasesBySymptoms = async query =>
{
let allMatches = [];
if (!query.length)
{
// Si aucun terme dans la requête, tout correspond
allMatches = Object.values(data.terms).map(({id}) => id);
}
else
{
// Marqueurs indiquant pour chaque terme lensemble des éléments de la
// requête quil a pour symptôme au travers dune relation directe ou
// transitive
const matchingSymptoms = {};
// Réalise un parcours en profondeur du graphe en partant de chaque terme
// de la requête pour marquer les résultats
for (let queryTerm of query)
{
const stack = [queryTerm.id];
while (stack.length)
{
const current = stack.pop();
const neighbors = data.symptomOf.filter(
([from]) => from === current
).map(
([, to]) => to
);
for (let neighbor of neighbors)
{
if (!(neighbor in matchingSymptoms))
{
matchingSymptoms[neighbor] = [];
}
if (!matchingSymptoms[neighbor].includes(queryTerm.id))
{
matchingSymptoms[neighbor].push(queryTerm.id);
stack.push(neighbor);
}
}
}
}
// Seuls les termes ayant été visités par tous les éléments de la
// requête sont des résultats valides
allMatches = Object.entries(matchingSymptoms).filter(
([, matches]) => matches.length === query.length
).map(
([id]) => id
);
}
// On ne garde que les maladies
return allMatches.map(
id => data.terms[id]
).filter(
term => term.types.includes(termTypes.disease)
);
};
/**
* Récupère tous les termes liés à un ensemble de termes par une relation « a
* pour symptôme », directe ou transitive.
*
* @param terms Ensemble de termes initiaux.
* @return Termes de `terms` ainsi que leurs voisins par la relation symptôme.
*/
export const exploreSymptoms = async terms =>
{
// Voisins des termes de la requête
const selected = terms.map(({id}) => id);
// Fait un parcours en profondeur issu de chaque résultat pour obtenir
// tous les voisins directs ou transitifs par la relation « a pour
// symptôme »
const stack = [...selected];
while (stack.length)
{
const current = stack.pop();
const neighbors = data.hasSymptom.filter(
([from]) => from === current
).map(
([, to]) => to
);
for (let neighbor of neighbors)
{
if (!selected.includes(neighbor))
{
selected.push(neighbor);
stack.push(neighbor);
}
}
}
return selected.map(id => data.terms[id]);
};
/**
* Calcule le sous-graphe issu dun ensemble de termes.
*
* @param terms Ensemble de termes à mettre dans le sous-graphe.
* @return Objet contenant les nœuds et les arêtes du graphe.
*/
export const symptomsSubgraph = async terms =>
{
const termsIds = terms.map(({id}) => id);
// Construction du graphe constitué des éléments sélectionnés et des
// arêtes qui les lient
const nodes = {};
const edges = [];
for (let term of terms)
{
nodes[term.id] = term;
}
// Sélection des arêtes liant les nœuds sélectionnés
for (let [from, to] of data.hasSymptom)
{
if (
termsIds.includes(from)
&& termsIds.includes(to)
)
{
edges.push([from, to]);
}
}
return {nodes, edges};
};