2019-12-03 22:00:21 +00:00
|
|
|
|
import * as mock from './data/mock.js';
|
2019-11-27 05:49:19 +00:00
|
|
|
|
|
2019-11-27 08:33:03 +00:00
|
|
|
|
/**
|
2019-12-03 22:00:21 +00:00
|
|
|
|
* Recherche l’ensemble des maladies liées par une relation « a pour symptôme »
|
|
|
|
|
* avec un ensemble de termes donné.
|
2019-11-27 08:33:03 +00:00
|
|
|
|
*
|
2019-12-03 22:00:21 +00:00
|
|
|
|
* @param query Ensemble de termes attendus.
|
|
|
|
|
* @return Liste des maladies correspondantes.
|
2019-11-27 08:33:03 +00:00
|
|
|
|
*/
|
2019-12-03 22:00:21 +00:00
|
|
|
|
export const diseasesBySymptoms = async query =>
|
2019-11-27 08:33:03 +00:00
|
|
|
|
{
|
2019-12-03 22:00:21 +00:00
|
|
|
|
// Si aucun terme dans la requête, toutes les maladies correspondent
|
|
|
|
|
if (!query.length)
|
2019-11-27 08:33:03 +00:00
|
|
|
|
{
|
2019-12-03 22:00:21 +00:00
|
|
|
|
return Object.values(mock.terms);
|
|
|
|
|
}
|
2019-11-27 08:33:03 +00:00
|
|
|
|
|
2019-12-03 22:00:21 +00:00
|
|
|
|
// Marqueurs indiquant pour chaque terme l’ensemble des éléments de la
|
|
|
|
|
// requête qu’il a pour symptôme au travers d’une relation directe ou
|
|
|
|
|
// transitive
|
|
|
|
|
const matchingSymptoms = {};
|
2019-11-27 08:33:03 +00:00
|
|
|
|
|
2019-12-03 22:00:21 +00:00
|
|
|
|
// 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];
|
2019-11-27 08:33:03 +00:00
|
|
|
|
|
2019-12-03 22:00:21 +00:00
|
|
|
|
while (stack.length)
|
|
|
|
|
{
|
|
|
|
|
const current = stack.pop();
|
|
|
|
|
const neighbors = mock.symptomOf.filter(
|
|
|
|
|
([from]) => from === current
|
|
|
|
|
).map(
|
|
|
|
|
([, to]) => to
|
|
|
|
|
);
|
2019-11-27 08:33:03 +00:00
|
|
|
|
|
2019-12-03 22:00:21 +00:00
|
|
|
|
for (let neighbor of neighbors)
|
2019-11-27 08:33:03 +00:00
|
|
|
|
{
|
2019-12-03 22:00:21 +00:00
|
|
|
|
if (!(neighbor in matchingSymptoms))
|
2019-11-27 08:33:03 +00:00
|
|
|
|
{
|
2019-12-03 22:00:21 +00:00
|
|
|
|
matchingSymptoms[neighbor] = [];
|
2019-11-27 08:33:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-12-03 22:00:21 +00:00
|
|
|
|
if (!matchingSymptoms[neighbor].includes(queryTerm.id))
|
2019-11-27 08:33:03 +00:00
|
|
|
|
{
|
2019-12-03 22:00:21 +00:00
|
|
|
|
matchingSymptoms[neighbor].push(queryTerm.id);
|
|
|
|
|
stack.push(neighbor);
|
2019-11-27 08:33:03 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2019-12-03 22:00:21 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Seuls les termes ayant été visités par tous les éléments de la requête
|
|
|
|
|
// et qui sont des maladies constituent des résultats valides
|
|
|
|
|
return Object.entries(matchingSymptoms).filter(
|
|
|
|
|
([id, matches]) => (
|
|
|
|
|
matches.length === query.length
|
|
|
|
|
&& mock.terms[id].types.includes(mock.types.disease)
|
|
|
|
|
)
|
|
|
|
|
).map(
|
|
|
|
|
([id]) => mock.terms[id]
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 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];
|
2019-11-27 08:33:03 +00:00
|
|
|
|
|
2019-12-03 22:00:21 +00:00
|
|
|
|
while (stack.length)
|
|
|
|
|
{
|
|
|
|
|
const current = stack.pop();
|
|
|
|
|
const neighbors = mock.hasSymptom.filter(
|
|
|
|
|
([from]) => from === current
|
|
|
|
|
).map(
|
|
|
|
|
([, to]) => to
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
for (let neighbor of neighbors)
|
|
|
|
|
{
|
|
|
|
|
if (!selected.includes(neighbor))
|
2019-11-27 08:33:03 +00:00
|
|
|
|
{
|
2019-12-03 22:00:21 +00:00
|
|
|
|
selected.push(neighbor);
|
|
|
|
|
stack.push(neighbor);
|
2019-11-27 08:33:03 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2019-12-03 22:00:21 +00:00
|
|
|
|
}
|
2019-11-27 05:49:19 +00:00
|
|
|
|
|
2019-12-03 22:00:21 +00:00
|
|
|
|
return selected.map(id => mock.terms[id]);;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Calcule le sous-graphe issu d’un 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 mock.hasSymptom)
|
|
|
|
|
{
|
|
|
|
|
if (
|
|
|
|
|
termsIds.includes(from)
|
|
|
|
|
&& termsIds.includes(to)
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
edges.push([from, to]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return {nodes, edges};
|
|
|
|
|
};
|