Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions mapserver/competency/flatmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ def anatomical_map_knowledge(map_uuid: str, competency_db: CompetencyKnowledge)
'nerves': path_knowledge.get('node-nerves', []),
'phenotypes': path_phenotypes.get(path_id, []),
'references': path_evidence.get(path_id, []),
'node-mappings': path_knowledge.get('node-mappings', []),
}
if 'alert' in properties:
knowledge_terms[path_id]['alert'] = properties['alert']
Expand Down
146 changes: 146 additions & 0 deletions mapserver/competency/queries.d/query_27.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
queries:
- id: 27
label: Node mapping from sckan to map
sql: >
WITH node_mappings AS (
SELECT DISTINCT
sckan.sckan_id,
sckan.path_id,
sckan.sckan_node_id,
map.source_id,
map.node_id
FROM (
SELECT
source_id AS sckan_id,
path_id,
node_id AS sckan_node_id
FROM path_nodes
WHERE source_id IN (
SELECT sckan_id
FROM path_node_mappings
WHERE %CONDITION_1%
)
AND %CONDITION_0%
) AS sckan
LEFT JOIN (
SELECT
source_id,
path_id,
node_id,
sckan_id,
sckan_node_id
FROM path_node_mappings
WHERE %CONDITION_1%
AND %CONDITION_0%
) AS map
ON sckan.path_id = map.path_id
AND sckan.sckan_node_id = map.sckan_node_id
),

sckan_labels AS (
SELECT
nm.sckan_id,
nm.sckan_node_id,
string_agg(pt.label, ', ' ORDER BY seq.pos) AS sckan_node_label
FROM node_mappings nm
JOIN path_node_features pnf
ON nm.sckan_id = pnf.source_id
AND nm.path_id = pnf.path_id
AND nm.sckan_node_id = pnf.node_id
JOIN feature_terms pt
ON pnf.source_id = pt.source_id
AND pnf.feature_id = pt.term_id
CROSS JOIN LATERAL (
SELECT pos
FROM (
SELECT pnf.node_id::jsonb->>0 AS value, 1 AS pos
UNION ALL
SELECT value, ordinality + 1 AS pos
FROM jsonb_array_elements_text(pnf.node_id::jsonb->1) WITH ORDINALITY
) s
WHERE s.value = pt.term_id
) AS seq
GROUP BY nm.sckan_id, nm.sckan_node_id
),

map_labels AS (
SELECT
nm.source_id,
nm.node_id,
string_agg(pt.label, ', ' ORDER BY seq.pos) AS node_label
FROM node_mappings nm
JOIN path_node_features pnf
ON nm.source_id = pnf.source_id
AND nm.path_id = pnf.path_id
AND nm.node_id = pnf.node_id
JOIN feature_terms pt
ON pnf.source_id = pt.source_id
AND pnf.feature_id = pt.term_id
CROSS JOIN LATERAL (
SELECT pos
FROM (
SELECT pnf.node_id::jsonb->>0 AS value, 1 AS pos
UNION ALL
SELECT value, ordinality + 1 AS pos
FROM jsonb_array_elements_text(pnf.node_id::jsonb->1) WITH ORDINALITY
) s
WHERE s.value = pt.term_id
) AS seq
GROUP BY nm.source_id, nm.node_id
)

SELECT
nm.sckan_id,
nm.path_id,
nm.sckan_node_id,
UPPER(SUBSTRING(sl.sckan_node_label, 1, 1)) ||
SUBSTRING(sl.sckan_node_label, 2) AS sckan_node_label,
COALESCE(nm.source_id, '') AS source_id,
COALESCE(nm.node_id, '') AS node_id,
COALESCE(UPPER(SUBSTRING(ml.node_label, 1, 1)) ||
SUBSTRING(ml.node_label, 2), '') AS node_label
FROM node_mappings nm
NATURAL JOIN sckan_labels sl
LEFT JOIN map_labels ml
ON nm.source_id = ml.source_id
AND nm.node_id = ml.node_id;
parameters:
- id: path_id
column: path_id
label: Neuron population
type: string
multiple: true
condition: CONDITION_0
- id: source_id
column: source_id
label: Knowledge source
type: string
multiple: true
condition: CONDITION_1
default_msg: the latest source is used
default_sql: >
select source_id from knowledge_sources where source_id like 'sckan%'
order by source_id desc limit 1
order: ''
results:
- key: sckan_id
label: SKCAN Knowledge source
type: string
- key: path_id
label: Neuron population
type: string
- key: sckan_node_id
label: SKCAN Node ID
type: string
- key: sckan_node_label
label: SKCAN Node Label
type: string
- key: source_id
label: Knowledge source
type: string
- key: node_id
label: Map Node ID
type: string
- key: node_label
label: Map Node Label
type: string
67 changes: 67 additions & 0 deletions tests/test_query_27.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import pytest
from utility import cq_request, assert_valid_query_response, MALE_UUID, FEMALE_UUID, RAT_UUID

base_query = {
'query_id': '27',
'parameters': [
{'column': 'path_id','value': 'ilxtr:neuron-type-bolew-unbranched-15'}
]
}

expected_sckan_node_ids = [
'["ILX:0738293", []]',
'["ILX:0738305", ["UBERON:0001532"]]',
'["ILX:0793621", []]',
'["UBERON:0001989", []]',
'["UBERON:0003708", []]'
]
expected_node_ids = [
'["ILX:0738293", []]',
'["ILX:0738305", []]',
'["ILX:0793621", []]',
'["UBERON:0001989", []]',
'["UBERON:0003708", []]'
]

def test_human_male_map():
query = {**base_query, 'parameters': base_query['parameters'] + [{'column': 'source_id', 'value': MALE_UUID}]}
response = cq_request(query)

assert_valid_query_response(
response,
expected_num_keys=7,
expected_num_values=5,
expected_column_values={
'sckan_node_id': expected_sckan_node_ids,
'node_id': expected_node_ids
}
)

def test_human_female_map():
query = {**base_query, 'parameters': base_query['parameters'] + [{'column': 'source_id', 'value': FEMALE_UUID}]}
response = cq_request(query)

assert_valid_query_response(
response,
expected_num_keys=7,
expected_num_values=5,
expected_column_values={
'sckan_node_id': expected_sckan_node_ids,
'node_id': expected_node_ids
}
)

def test_human_rat_map():
query = {**base_query, 'parameters': base_query['parameters'] + [{'column': 'source_id', 'value': RAT_UUID}]}
response = cq_request(query)

assert_valid_query_response(
response,
expected_num_keys=7,
expected_num_values=5,
expected_column_values={
'sckan_node_id': expected_sckan_node_ids,
'node_id': expected_node_ids
}
)
#===============================================================================
23 changes: 18 additions & 5 deletions tests/utility.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,28 @@
import requests
from tools.portal_maps import ENDPOINTS, latest_maps

END_POINT = 'https://mapcore-demo.org/devel/flatmap/v4/competency/query'
END_POINT = ENDPOINTS['development']
CQ_END_POINT = f'{END_POINT}/competency/query'
HEADERS = {'Content-Type': 'application/json'}

MALE_UUID = '2b76d336-5c56-55e3-ab1e-795d6c63f9c1'
FEMALE_UUID = '91359a0f-9e32-5309-b365-145d9956817d'
RAT_UUID = 'fb6d0345-cb70-5c7e-893c-d744a6313c95'
# latest flatmap UUIDs for testing obtained dynamically
maps = latest_maps(END_POINT)
MALE_UUID = (
maps.get(('NCBITaxon:9606', 'PATO:0000384'), {}).get('uuid')
or "2b76d336-5c56-55e3-ab1e-795d6c63f9c1"
)
FEMALE_UUID = (
maps.get(('NCBITaxon:9606', 'PATO:0000383'), {}).get('uuid')
or "91359a0f-9e32-5309-b365-145d9956817d"
)
RAT_UUID = (
maps.get(('NCBITaxon:10114', None), {}).get('uuid')
or "fb6d0345-cb70-5c7e-893c-d744a6313c95"
)
SCKAN_VERSION = 'sckan-2024-09-21'

def cq_request(query: dict):
response = requests.post(END_POINT, json=query, headers=HEADERS)
response = requests.post(CQ_END_POINT, json=query, headers=HEADERS)
return response

def assert_valid_query_response(
Expand Down