Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[candidate_parameters] Add candidate parameters query engine #8288

Merged
merged 28 commits into from
Nov 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
31a5287
[Query Interface] Add Module->getQueryEngine()
driusan Dec 7, 2022
5b50f0a
Add NullQueryEngine
driusan Dec 7, 2022
05dece6
Add Candidate Query Engine
driusan Dec 7, 2022
1e45948
Add SQLQueryEngine class
driusan Dec 7, 2022
55b04e4
Fix some phan errors
driusan Dec 7, 2022
a089c22
Fix make checkstatic
driusan Dec 19, 2022
fd4ec79
Move SQL related functions from CandidateQueryEngine to SQLQueryEngine
driusan Dec 19, 2022
3293030
Improve documentation for SQLQueryEngine
driusan Dec 19, 2022
1d49d3b
Add getQueryEngine to module
driusan Dec 19, 2022
3dc8c9b
test signature must be compatible
driusan Jan 24, 2023
c47f628
Remove reference to Module::factory, which no longer exists
driusan Aug 16, 2023
fe8fd43
Remove call to non-existent Database::singleton
driusan Aug 16, 2023
1f845f9
Do not change return value of QueryEngine, causes errors with Instrum…
driusan Aug 16, 2023
1d02b12
Change subproject to cohort
driusan Nov 14, 2023
d4cc1e8
Update module search path in test, replace subproject with cohort in …
driusan Nov 14, 2023
79b3c3f
Capitalize table name
driusan Nov 14, 2023
ea03db4
Handle both traversable and arrays in assertion
driusan Nov 14, 2023
3109701
More test fixing
driusan Nov 14, 2023
de30750
phpcs
driusan Nov 15, 2023
360b064
fix duplicate call to iterator_to_array causing error
driusan Nov 15, 2023
85ea04f
Change substring search.
driusan Nov 15, 2023
1427b5f
Remove unnecessary assertion that is failing
driusan Nov 15, 2023
1b2ad6f
Fix substring search after subproject->cohort change, add debug for o…
driusan Nov 15, 2023
b25e024
fix test, handle session variables in newest return format
driusan Nov 15, 2023
d75e56c
Use sessionID as array key
driusan Nov 15, 2023
0a906d0
Cohort is also session scoped
driusan Nov 15, 2023
d27fdf0
put session tests in proper format in getCandidateData too
driusan Nov 15, 2023
cb86714
RegistrationSite is a Candidate variable, not session
driusan Nov 15, 2023
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
2 changes: 2 additions & 0 deletions .phan/config.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
"unused_variable_detection" => true,
"suppress_issue_types" => [
"PhanUnusedPublicNoOverrideMethodParameter",
// Until phan/phan#4746 is fixed
"PhanTypeMismatchArgumentInternal"
],
"analyzed_file_extensions" => ["php", "inc"],
"directory_list" => [
Expand Down
271 changes: 271 additions & 0 deletions modules/candidate_parameters/php/candidatequeryengine.class.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,271 @@
<?php declare(strict_types=1);

namespace LORIS\candidate_parameters;
use LORIS\Data\Scope;
use LORIS\Data\Cardinality;
use LORIS\Data\Dictionary\DictionaryItem;

/**
* A CandidateQueryEngine providers a QueryEngine interface to query
* against general candidate data such as identifiers, DoB, Entity Type,
* etc.
*
* @license http://www.gnu.org/licenses/gpl-3.0.txt GPLv3
*/
class CandidateQueryEngine extends \LORIS\Data\Query\SQLQueryEngine
{
/**
* Return a data dictionary of data types managed by this module.
* DictionaryItems are grouped into categories and a module may
* provide 0 or more categories of dictionaryitems.
*
* @return \LORIS\Data\Dictionary\Category[]
*/
public function getDataDictionary() : iterable
{
$candscope = new Scope(Scope::CANDIDATE);
$sesscope = new Scope(Scope::SESSION);

$ids = new \LORIS\Data\Dictionary\Category(
"Identifiers",
"Candidate Identifiers"
);

$ids = $ids->withItems(
[
new DictionaryItem(
"CandID",
"LORIS Candidate Identifier",
$candscope,
new \LORIS\Data\Types\IntegerType(999999),
new Cardinality(Cardinality::UNIQUE),
),
new DictionaryItem(
"PSCID",
"Project Candidate Identifier",
$candscope,
new \LORIS\Data\Types\StringType(255),
new Cardinality(Cardinality::UNIQUE),
),
]
);

$demographics = new \LORIS\Data\Dictionary\Category(
"Demographics",
"Candidate Demographics",
);
$demographics = $demographics->withItems(
[
new DictionaryItem(
"DoB",
"Date of Birth",
$candscope,
new \LORIS\Data\Types\DateType(),
new Cardinality(Cardinality::SINGLE),
),
new DictionaryItem(
"DoD",
"Date of Death",
$candscope,
new \LORIS\Data\Types\DateType(),
new Cardinality(Cardinality::OPTIONAL),
),
new DictionaryItem(
"Sex",
"Candidate's biological sex",
$candscope,
new \LORIS\Data\Types\Enumeration('Male', 'Female', 'Other'),
new Cardinality(Cardinality::SINGLE),
),
new DictionaryItem(
"EDC",
"Expected Data of Confinement",
$candscope,
new \LORIS\Data\Types\DateType(),
new Cardinality(Cardinality::OPTIONAL),
),
]
);

$meta = new \LORIS\Data\Dictionary\Category("Meta", "Other parameters");

$db = $this->loris->getDatabaseConnection();
$participantstatus_options = $db->pselectCol(
"SELECT Description FROM participant_status_options",
[]
);
$meta = $meta->withItems(
[
new DictionaryItem(
"VisitLabel",
"The study visit label",
$sesscope,
new \LORIS\Data\Types\StringType(255),
new Cardinality(Cardinality::UNIQUE),
),
new DictionaryItem(
"Project",
"The LORIS project to categorize this session",
$sesscope,
new \LORIS\Data\Types\StringType(255), // FIXME: Make an enum
new Cardinality(Cardinality::SINGLE),
),
new DictionaryItem(
"Cohort",
"The LORIS cohort used for battery selection",
$sesscope,
new \LORIS\Data\Types\StringType(255),
new Cardinality(Cardinality::SINGLE),
),
new DictionaryItem(
"Site",
"The Site at which a visit occurred",
$sesscope,
new \LORIS\Data\Types\Enumeration(...\Utility::getSiteList()),
new Cardinality(Cardinality::SINGLE),
),
new DictionaryItem(
"EntityType",
"The type of entity which this candidate represents",
$candscope,
new \LORIS\Data\Types\Enumeration('Human', 'Scanner'),
new Cardinality(Cardinality::SINGLE),
),
new DictionaryItem(
"ParticipantStatus",
"The status of the participant within the study",
$candscope,
new \LORIS\Data\Types\Enumeration(...$participantstatus_options),
new Cardinality(Cardinality::SINGLE),
),
new DictionaryItem(
"RegistrationSite",
"The site at which this candidate was initially registered",
$candscope,
new \LORIS\Data\Types\Enumeration(...\Utility::getSiteList()),
new Cardinality(Cardinality::SINGLE),
),
new DictionaryItem(
"RegistrationProject",
"The project for which this candidate was initially registered",
$candscope,
new \LORIS\Data\Types\StringType(255), // FIXME: Make an enum
new Cardinality(Cardinality::SINGLE),
),
]
);
return [$ids, $demographics, $meta];
}
/**
* {@inheritDoc}
*
* @param \Loris\Data\Dictionary\Category $cat The dictionaryItem
* category
* @param \Loris\Data\Dictionary\DictionaryItem $item The item
*
* @return string[]
*/
public function getVisitList(
\LORIS\Data\Dictionary\Category $cat,
\LORIS\Data\Dictionary\DictionaryItem $item
) : iterable {
if ($item->getScope()->__toString() !== 'session') {
return [];
}

// Session scoped variables: VisitLabel, project, site, cohort
return array_keys(\Utility::getVisitList());
}

/**
* Get the SQL field name to use to refer to a dictionary item.
*
* @param \LORIS\Data\Dictionary\DictionaryItem $item The dictionary item
*
* @return string
*/
protected function getFieldNameFromDict(
\LORIS\Data\Dictionary\DictionaryItem $item
) : string {
switch ($item->getName()) {
case 'CandID':
return 'c.CandID';
case 'PSCID':
return 'c.PSCID';
case 'Site':
$this->addTable('LEFT JOIN session s ON (s.CandID=c.CandID)');
$this->addTable('LEFT JOIN psc site ON (s.CenterID=site.CenterID)');
$this->addWhereClause("s.Active='Y'");
return 'site.Name';
case 'RegistrationSite':
$this->addTable(
'LEFT JOIN psc rsite'
. ' ON (c.RegistrationCenterID=rsite.CenterID)'
);
return 'rsite.Name';
case 'Sex':
return 'c.Sex';
case 'DoB':
return 'c.DoB';
case 'DoD':
return 'c.DoD';
case 'EDC':
return 'c.EDC';
case 'Project':
$this->addTable('LEFT JOIN session s ON (s.CandID=c.CandID)');
$this->addTable(
'LEFT JOIN Project proj ON (s.ProjectID=proj.ProjectID)'
);
$this->addWhereClause("s.Active='Y'");

return 'proj.Name';
case 'RegistrationProject':
$this->addTable(
'LEFT JOIN Project rproj'
.' ON (c.RegistrationProjectID=rproj.ProjectID)'
);
return 'rproj.Name';
case 'Cohort':
$this->addTable('LEFT JOIN session s ON (s.CandID=c.CandID)');
$this->addTable(
'LEFT JOIN cohort cohort'
.' ON (s.CohortID=cohort.CohortID)'
);
$this->addWhereClause("s.Active='Y'");

return 'cohort.title';
case 'VisitLabel':
$this->addTable('LEFT JOIN session s ON (s.CandID=c.CandID)');
$this->addWhereClause("s.Active='Y'");
return 's.Visit_label';
case 'EntityType':
return 'c.Entity_type';
case 'ParticipantStatus':
$this->addTable(
'LEFT JOIN participant_status ps ON (ps.CandID=c.CandID)'
);
$this->addTable(
'LEFT JOIN participant_status_options pso ' .
'ON (ps.participant_status=pso.ID)'
);
return 'pso.Description';
default:
throw new \DomainException("Invalid field " . $item->getName());
}
}


/**
* {@inheritDoc}
*
* @param string $fieldname A field name
*
* @return string
*/
protected function getCorrespondingKeyField($fieldname)
{
// There are no cardinality::many fields in this query engine, so this
// should never get called
throw new \Exception("Unhandled Cardinality::MANY field $fieldname");
}
}
10 changes: 10 additions & 0 deletions modules/candidate_parameters/php/module.class.inc
Original file line number Diff line number Diff line change
Expand Up @@ -185,4 +185,14 @@ class Module extends \Module
}
return $entries;
}

/**
* {@inheritDoc}
*
* @return \LORIS\Data\Query\QueryEngine
*/
public function getQueryEngine() : \LORIS\Data\Query\QueryEngine
{
return new CandidateQueryEngine($this->loris);
}
}
Loading