Skip to content
Merged
45 changes: 0 additions & 45 deletions nbri_ehr/resources/queries/nbri_ehr/Conception.js

This file was deleted.

106 changes: 0 additions & 106 deletions nbri_ehr/resources/queries/nbri_ehr/Conception.query.xml

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,25 @@
* Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0
*/
SELECT
c.Dam AS Id,
c.ConceptId,
c.ConceptDate,
c.Estimated,
c.Sire,
c.Id,
c.conceptId,
c.date,
c.conceptionDays,
c.estimated,
c.sire,
c.isActive,
CASE
WHEN c.isActive = true THEN 'Unknown'
WHEN b.conceptId IS NOT NULL THEN 'Live Birth'
ELSE COALESCE(po.result, 'Unknown')
END AS conceptionOutcome,
b.offspring,
c.Remark,
c.QCState AS qcstate
FROM Conception c
c.remark,
c.qcstate
FROM conception c
-- Both joins match isActive: a record claims its conception unless its QC state is explicitly non-public, so a null state counts as public.
-- The birth trigger blocks a duplicate conceptId, but ETL imports skip that check, so the aggregate guards against one.
LEFT JOIN (SELECT b.conceptId, MAX(b.Id) AS offspring FROM study.birth b WHERE b.conceptId IS NOT NULL AND (b.qcstate IS NULL OR b.qcstate.publicdata = true) GROUP BY b.conceptId) b
ON b.conceptId = c.ConceptId
ON b.conceptId = c.conceptId
LEFT JOIN (SELECT p.conceptId, MAX(p.result.title) AS result FROM study.pregnancy p WHERE p.conceptId IS NOT NULL AND (p.qcstate IS NULL OR p.qcstate.publicdata = true) GROUP BY p.conceptId) po
ON po.conceptId = c.ConceptId
ON po.conceptId = c.conceptId
10 changes: 5 additions & 5 deletions nbri_ehr/resources/queries/study/activeConceptions.sql
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
* Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0
*/
SELECT
c.Dam AS Id,
c.ConceptId,
c.ConceptDate
FROM nbri_ehr.Conception c
WHERE c.isActive = true AND c.Dam IS NOT NULL
c.Id,
c.conceptId,
c.date
FROM study.conception c
WHERE c.isActive = true AND c.Id IS NOT NULL
4 changes: 2 additions & 2 deletions nbri_ehr/resources/queries/study/birth.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Even
}

if (damsToSync.length) {
triggerHelper.reportDataChange('nbri_ehr', 'Conception', damsToSync);
triggerHelper.reportDataChange('study', 'conception', damsToSync);
damsToSync = [];
}
});
Expand All @@ -104,7 +104,7 @@ EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Even
}

if (!helper.isETL() && row.conceptId) {
if (triggerHelper.totalRecords('nbri_ehr', 'Conception', 'ConceptId', row.conceptId) === 0) {
if (triggerHelper.totalRecords('study', 'conception', 'conceptId', row.conceptId) === 0) {
EHR.Server.Utils.addError(scriptErrors, 'conceptId', 'This conception Id does not match any conception record', 'WARN');
}

Expand Down
6 changes: 3 additions & 3 deletions nbri_ehr/resources/queries/study/birth.query.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@
<column columnName="conceptId">
<columnTitle>Conception Id</columnTitle>
<fk>
<fkDbSchema>nbri_ehr</fkDbSchema>
<fkTable>Conception</fkTable>
<fkColumnName>ConceptId</fkColumnName>
<fkDbSchema>study</fkDbSchema>
<fkTable>conception</fkTable>
<fkColumnName>conceptId</fkColumnName>
</fk>
</column>
<column columnName="cage">
Expand Down
47 changes: 47 additions & 0 deletions nbri_ehr/resources/queries/study/conception.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright (c) 2026 LabKey Corporation
*
* Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0
*/
require("ehr/triggers").initScript(this);

var triggerHelper = new org.labkey.nbri_ehr.query.NBRI_EHRTriggerHelper(LABKEY.Security.currentUser.id, LABKEY.Security.currentContainer.id);

// conception ids claimed by the rows of this save that have already been validated. Rows entered together are not in
// study.conception yet when each one is checked, so this is the only way the one-record-per-conception rule can see them.
var conceptIdsInSave = [];

EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.INIT, 'study', 'conception', function(event, helper){
helper.setScriptOptions({
// gestation puts the conception date months behind the entry date, so a distant past date is the normal case
allowDatesInDistantPast: true,
allowDeadIds: true,
skipHousingCheck: true,
skipAssignmentCheck: true
});

// the script scope can outlive a single save, so never inherit ids from a prior one
conceptIdsInSave = [];
});

// conceptId was a unique constraint before this became a dataset, and the birth and pregnancy triggers still resolve a
// conception by that id alone, so the rule is enforced here now. Unlike the sibling checks in birth.js and
// pregnancy.js this one does not exempt ETL: getConceptionDam() reads the dam with getObject(), which throws on a
// second match, so a duplicate from any write path breaks later birth and pregnancy saves.
EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.BEFORE_UPSERT, 'study', 'conception', function(helper, scriptErrors, row, oldRow) {
if (!row.conceptId)
return;

//when updating a record that already carries this conception id, the existing row accounts for one match
var conceptIdThreshold = (oldRow && oldRow.conceptId === row.conceptId) ? 1 : 0;
var claimedBySavedRow = triggerHelper.totalRecords('study', 'conception', 'conceptId', row.conceptId) > conceptIdThreshold;

// rows are validated one at a time and collected below, so this list holds the earlier rows of this save only
var claimedByEarlierRow = conceptIdsInSave.indexOf(row.conceptId) > -1;

if (claimedBySavedRow || claimedByEarlierRow) {
EHR.Server.Utils.addError(scriptErrors, 'conceptId', 'This conception Id is already used by another conception record', 'ERROR');
}

conceptIdsInSave.push(row.conceptId);
});
31 changes: 31 additions & 0 deletions nbri_ehr/resources/queries/study/conception.query.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<query xmlns="http://labkey.org/data/xml/query">
<metadata>
<tables xmlns="http://labkey.org/data/xml">
<table tableName="conception" tableDbType="TABLE" useColumnOrder="true">
<tableTitle>Conception Records</tableTitle>
<tableUrl>/query/recordDetails.view?schemaName=study&amp;query.queryName=conception&amp;keyField=conceptId&amp;key=${conceptId}</tableUrl>
<!-- Without this the lookup display falls back to the first string column, which is the dam -->
<titleColumn>conceptId</titleColumn>
<columns>
<column columnName="Id">
<columnTitle>Dam</columnTitle>
</column>
<column columnName="date">
<columnTitle>Conception Date</columnTitle>
<formatString>Date</formatString>
</column>
<column columnName="conceptId">
<columnTitle>Conception Id</columnTitle>
<required>true</required>
</column>
<column columnName="estimated">
<columnTitle>Estimated</columnTitle>
<description>Conception date is estimated rather than observed</description>
</column>
<column columnName="sire"/>
<column columnName="remark"/>
</columns>
</table>
</tables>
</metadata>
</query>
4 changes: 2 additions & 2 deletions nbri_ehr/resources/queries/study/pregnancy.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Even

EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.BEFORE_UPSERT, 'study', 'pregnancy', function(helper, scriptErrors, row, oldRow) {
if (!helper.isETL() && row.conceptId) {
if (triggerHelper.totalRecords('nbri_ehr', 'Conception', 'ConceptId', row.conceptId) === 0) {
if (triggerHelper.totalRecords('study', 'conception', 'conceptId', row.conceptId) === 0) {
EHR.Server.Utils.addError(scriptErrors, 'conceptId', 'This conception Id does not match any conception record', 'WARN');
}

Expand Down Expand Up @@ -61,7 +61,7 @@ EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Even

EHR.Server.TriggerManager.registerHandlerForQuery(EHR.Server.TriggerManager.Events.COMPLETE, 'study', 'pregnancy', function(event, errors, helper){
if (damsToSync.length) {
triggerHelper.reportDataChange('nbri_ehr', 'Conception', damsToSync);
triggerHelper.reportDataChange('study', 'conception', damsToSync);
damsToSync = [];
}
});
Expand Down
6 changes: 3 additions & 3 deletions nbri_ehr/resources/queries/study/pregnancy.query.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@
<column columnName="conceptId">
<columnTitle>Conception Id</columnTitle>
<fk>
<fkDbSchema>nbri_ehr</fkDbSchema>
<fkTable>Conception</fkTable>
<fkColumnName>ConceptId</fkColumnName>
<fkDbSchema>study</fkDbSchema>
<fkTable>conception</fkTable>
<fkColumnName>conceptId</fkColumnName>
</fk>
</column>
<column columnName="type">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
<dataset name="clinremarks" id="1009" category="Clinical" type="Standard"/>
<dataset name="cases" id="1023" category="Clinical" type="Standard"/>
<dataset name="chemistryResults" id="1024" category="ClinPath" type="Standard"/>
<dataset name="conception" id="1050" category="Reproductive Management" type="Standard"/>
<dataset name="deaths" id="1011" category="Pathology" demographicData="true" type="Standard"/>
<dataset name="demographics" id="1012" category="Colony Management" demographicData="true" type="Standard"/>
<dataset name="departure" id="1013" category="Colony Management" type="Standard"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,42 @@
</column>
</columns>
</table>
<table tableName="conception" tableDbType="TABLE">
<tableTitle>Conception Records</tableTitle>
<description>Records a conception, filed against the dam. The outcome is claimed later by a birth or pregnancy outcome record carrying the same conception Id.</description>
<columns>
<column columnName="Id">
<columnTitle>Dam</columnTitle>
<datatype>varchar</datatype>
<propertyURI>http://cpas.labkey.com/Study#ParticipantId</propertyURI>
<importAliases>
<importAlias>ptid</importAlias>
<importAlias>dam</importAlias>
</importAliases>
</column>
<column columnName="date">
<columnTitle>Conception Date</columnTitle>
<datatype>timestamp</datatype>
<propertyURI>http://cpas.labkey.com/Study#VisitDate</propertyURI>
<conceptURI>http://cpas.labkey.com/Study#VisitDate</conceptURI>
<importAliases>
<importAlias>conceptDate</importAlias>
</importAliases>
</column>
<column columnName="conceptId">
<columnTitle>Conception Id</columnTitle>
<datatype>varchar</datatype>
</column>
<column columnName="estimated">
<columnTitle>Estimated</columnTitle>
<datatype>boolean</datatype>
</column>
<column columnName="sire">
<columnTitle>Sire</columnTitle>
<datatype>varchar</datatype>
</column>
</columns>
</table>
<table tableName="demographics" tableDbType="TABLE">
<tableTitle>Demographics</tableTitle>
<description>Contains core demographic information for each primate, including species, sex, parentage, birth and death dates, and colony status.</description>
Expand Down
Loading