Skip to content

Commit

Permalink
Merge branch 'feature/sus-transform'
Browse files Browse the repository at this point in the history
  • Loading branch information
James Cockayne authored and James Cockayne committed Dec 10, 2024
2 parents 43a4ad0 + 4dd21bf commit 1a8622b
Show file tree
Hide file tree
Showing 90 changed files with 6,097 additions and 146 deletions.
46 changes: 45 additions & 1 deletion OmopTransformer/OmopTransformer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -291,8 +291,52 @@
<None Update="SACT\Sact.xml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="SUS\APC\Observation\AnaestheticDuringLabourDelivery\SusAPCAnaestheticDuringLabourDelivery.xml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="SUS\APC\Observation\AnaestheticGivenPostLabourDelivery\SusAPCAnaestheticGivenPostLabourDelivery.xml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="SUS\APC\Observation\BirthWeight\SusAPCBirthWeight.xml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="SUS\APC\Observation\CarerSupportIndicator\SusAPCCarerSupportIndicator.xml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="SUS\APC\Observation\GestationLengthLabourOnset\SusAPCGestationLengthLabourOnset.xml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="SUS\APC\Observation\NumberOfBabies\SusAPCNumberOfBabies.xml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="SUS\APC\Observation\TotalPreviousPregnancies\SusAPCTotalPreviousPregnancies.xml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="SUS\APC\Person\SusAPCPerson.xml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="SUS\APC\Location\SusAPCLocation.xml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="SUS\APC\Death\SusAPCDeath.xml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="SUS\APC\ConditionOccurrence\SusAPCConditionOccurrence.xml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="SUS\APC\ProcedureOccurrence\SusAPCProcedureOccurrence.xml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="SUS\APC\VisitDetails\SusAPCVisitDetails.xml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="SUS\APC\VisitOccurrenceWithoutSpell\SusAPCVisitOccurrenceWithoutSpell.xml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="SUS\APC\VisitOccurrenceWithSpell\SusAPCVisitOccurrenceWithSpell.xml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>

<Target Name="PostBuild" AfterTargets="PostBuildEvent">
<ItemGroup>
<DocumentationDirectory Include="$(MSBuildProjectDirectory)\..\docs\transformation-documentation" />
Expand Down
6 changes: 6 additions & 0 deletions OmopTransformer/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
using OmopTransformer.Omop.DrugExposure;
using OmopTransformer.Omop.Measurement;
using OmopTransformer.Omop.Observation;
using OmopTransformer.SUS.APC;
using OmopTransformer.SUS.Staging.APC;
using OmopTransformer.SUS.Staging.APC.Clearing;
using OmopTransformer.SUS.Staging.OP;
Expand Down Expand Up @@ -251,6 +252,11 @@ private static async Task Main(string[] args)
builder.Services.AddTransient<RtdsTransformer>();
builder.Services.AddHostedService<RtdsTransformHostedService>();
}
else if (string.Equals(transformOptions.Type, "sus-apc", StringComparison.OrdinalIgnoreCase))
{
builder.Services.AddTransient<SusAPCTransformer>();
builder.Services.AddHostedService<SusAPCTransformHostedService>();
}
else
{
await Console.Error.WriteLineAsync($"Unknown transform type {transformOptions.Type}.");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using OmopTransformer.Annotations;
using OmopTransformer.Omop.ConditionOccurrence;
using OmopTransformer.Transformation;

namespace OmopTransformer.SUS.APC.ConditionOccurrence;

internal class SusAPCConditionOccurrence : OmopConditionOccurrence<SusAPCConditionOccurrenceRecord>
{
[CopyValue(nameof(Source.NHSNumber))]
public override string? nhs_number { get; set; }

[Transform(typeof(Icd10Selector), nameof(Source.DiagnosisICD))]
public override int? condition_source_concept_id { get; set; }

[Transform(typeof(SnomedSelector), useOmopTypeAsSource: true, nameof(condition_source_concept_id))]
public override int[]? condition_concept_id { get; set; }

[Transform(typeof(DateConverter), nameof(Source.CDSActivityDate))]
public override DateTime? condition_start_date { get; set; }

[CopyValue(nameof(Source.DiagnosisICD))]
public override string? condition_source_value { get; set; }

[ConstantValue(32020, "EHR encounter diagnosis")]
public override int? condition_type_concept_id { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<Query>
<Sql>
select
distinct
d.DiagnosisICD,
apc.GeneratedRecordIdentifier,
apc.NHSNumber,
apc.CDSActivityDate
from omop_staging.sus_ICDDiagnosis d
inner join omop_staging.sus_APC apc
on d.MessageId = apc.MessageId
where apc.NHSNumber is not null
</Sql>
<Explanations>
<Explanation columnName="DiagnosisICD">
<Description>ICD10 diagnosis code</Description>
<Origin>PRIMARY DIAGNOSIS (ICD)</Origin>
</Explanation>
<Explanation columnName="GeneratedRecordIdentifier">
<Description>CDS specific identifier that binds multiple CDS messages together.</Description>
<Origin>CDS RECORD IDENTIFIER</Origin>
</Explanation>
<Explanation columnName="NHSNumber">
<Description>Patient NHS Number</Description>
<Origin>NHS NUMBER</Origin>
</Explanation>
<Explanation columnName="CDSActivityDate">
<Description>Event date</Description>
<Origin>CDS ACTIVITY DATE</Origin>
</Explanation>
</Explanations>
</Query>
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using OmopTransformer.Annotations;

namespace OmopTransformer.SUS.APC.ConditionOccurrence;

[DataOrigin("SUS")]
[Description("SUS Inpatient Condition Occurrence")]
[SourceQuery("SusAPCConditionOccurrence.xml")]
internal class SusAPCConditionOccurrenceRecord
{
public string? DiagnosisICD { get; set; }
public string? GeneratedRecordIdentifier { get; set; }
public string? NHSNumber { get; set; }
public string? CDSActivityDate { get; set; }
}
24 changes: 24 additions & 0 deletions OmopTransformer/SUS/APC/Death/SusAPCDeath.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using OmopTransformer.Annotations;
using OmopTransformer.Omop.Death;
using OmopTransformer.Transformation;

namespace OmopTransformer.SUS.APC.Death;

internal class SusAPCDeath : OmopDeath<SusAPCDeathRecord>
{
[CopyValue(nameof(Source.nhs_number))]
public override string? NhsNumber { get; set; }

[Transform(typeof(DateConverter), nameof(Source.death_date))]
public override DateTime? death_date { get; set; }

[Transform(typeof(DateAndTimeCombiner), nameof(Source.death_date), nameof(Source.death_time))]
public override DateTime? death_datetime { get; set; }

[CopyValue(nameof(Source.DiagnosisICD))]
public override string? cause_source_value { get; set; }

[Transform(typeof(Icd10Selector), nameof(Source.DiagnosisICD))]
public override int? cause_concept_id { get; set; }

}
50 changes: 50 additions & 0 deletions OmopTransformer/SUS/APC/Death/SusAPCDeath.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<Query>
<Sql>
;with primarydiagnosis as (
select *
from omop_staging.sus_ICDDiagnosis
where IsPrimaryDiagnosis = 1
)

select
apc.NHSNumber as nhs_number,
max(apc.DischargeDateFromHospitalProviderSpell) as death_date,
max(apc.DischargeTimeHospitalProviderSpell) as death_time,
max(d.DiagnosisICD) as DiagnosisICD
from
omop_staging.sus_APC apc
left join primarydiagnosis d
on apc.MessageId = d.MessageId
where
apc.NHSNumber is not null and
apc.DischargeDateFromHospitalProviderSpell is not null and
(
apc.DischargeMethodHospitalProviderSpell = '4'
or (
apc.DischargeDestinationHospitalProviderSpell = '79'
and
apc.DischargeMethodHospitalProviderSpell != '5'
)
)
group by apc.NHSNumber
</Sql>

<Explanations>
<Explanation columnName="death_date">
<Description>Discharge date of the patient's spell.</Description>
<Origin>DISCHARGE DATE (HOSPITAL PROVIDER SPELL)</Origin>
</Explanation>
<Explanation columnName="nhs_number">
<Description>Patient NHS Number</Description>
<Origin>NHS NUMBER</Origin>
</Explanation>
<Explanation columnName="death_time">
<Description>Discharge time of the patient's spell.</Description>
<Origin>DISCHARGE TIME (HOSPITAL PROVIDER SPELL)</Origin>
</Explanation>
<Explanation columnName="DiagnosisICD">
<Description>Primary Diagnosis</Description>
<Origin>PRIMARY DIAGNOSIS</Origin>
</Explanation>
</Explanations>
</Query>
14 changes: 14 additions & 0 deletions OmopTransformer/SUS/APC/Death/SusAPCDeathRecord.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using OmopTransformer.Annotations;

namespace OmopTransformer.SUS.APC.Death;

[DataOrigin("SUS")]
[Description("SUS Inpatient Death")]
[SourceQuery("SusAPCDeath.xml")]
internal class SusAPCDeathRecord
{
public string? nhs_number { get; set; }
public string? death_date { get; set; }
public string? death_time { get; set; }
public string? DiagnosisICD { get; set; }
}
17 changes: 17 additions & 0 deletions OmopTransformer/SUS/APC/Location/SusAPCLocation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using OmopTransformer.Annotations;
using OmopTransformer.Omop.Location;
using OmopTransformer.Transformation;

namespace OmopTransformer.SUS.APC.Location;

internal class SusAPCLocation : OmopLocation<SusAPCLocationRecord>
{
[CopyValue(nameof(Source.NHSNumber))]
public override string? nhs_number { get; set; }

[Transform(typeof(PostcodeFormatter), nameof(Source.Postcode))]
public override string? zip { get; set; }

[CopyValue(nameof(Source.Postcode))]
public override string? location_source_value { get; set; }
}
25 changes: 25 additions & 0 deletions OmopTransformer/SUS/APC/Location/SusAPCLocation.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<Query>
<Sql>
select
distinct
Postcode,
NHSNumber
from omop_staging.sus_APC
where LocationClassAtEpisodeStartDate = '04'
and
(
Postcode is not null
);
</Sql>

<Explanations>
<Explanation columnName="Postcode">
<Description>Patient Postcode</Description>
<Origin>POSTCODE</Origin>
</Explanation>
<Explanation columnName="NHSNumber">
<Description>Patient NHS Number</Description>
<Origin>NHS NUMBER</Origin>
</Explanation>
</Explanations>
</Query>
13 changes: 13 additions & 0 deletions OmopTransformer/SUS/APC/Location/SusAPCLocationRecord.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using OmopTransformer.Annotations;

namespace OmopTransformer.SUS.APC.Location;

[DataOrigin("SUS")]
[Description("SUS Inpatient Location")]
[SourceQuery("SusAPCLocation.xml")]
internal class SusAPCLocationRecord
{
public string? Postcode { get; set; }
public string? NHSNumber { get; set; }

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using OmopTransformer.Annotations;
using OmopTransformer.Omop.Observation;
using OmopTransformer.Transformation;

namespace OmopTransformer.SUS.APC.Observation.AnaestheticDuringLabourDelivery;

[Notes(
"Notes",
"Observations do not require a standardized test or other activity to generate clinical fact. Typical observations are medical history, family history, lifestyle choices, healthcare utilization patterns, social circumstances etc",
"Valid Observation Concepts are not enforced to be from any domain. They should still be standard concepts and typically belong to the Observation or Measurement domain.",
"Observations can be stored as attribute value pairs, with the attribute as the Observation Concept and the value representing the clinical fact. This fact can be stored as a Concept (value_as_concept), a numerical value (value_as_number) or a verbatim string (value_as_string)")]
internal class SusAPCAnaestheticDuringLabourDelivery : OmopObservation<SusAPCAnaestheticDuringLabourDeliveryRecord>
{
[CopyValue(nameof(Source.NHSNumber))]
public override string? nhs_number { get; set; }

[CopyValue(nameof(Source.GeneratedRecordIdentifier))]
public override string? RecordConnectionIdentifier { get; set; }

[Transform(typeof(NumberParser), nameof(Source.HospitalProviderSpellNumber))]
public override int? HospitalProviderSpellNumber { get; set; }

[ConstantValue(4163264, "Type of anesthetic")]
public override int? observation_concept_id { get; set; }

[Transform(typeof(DateConverter), nameof(Source.observation_date))]
public override DateTime? observation_date { get; set; }

[Transform(typeof(DateConverter), nameof(Source.observation_date))]
public override DateTime? observation_datetime { get; set; }

[ConstantValue(38000281, "Observation recorded from EHR with text result")]
public override int? observation_type_concept_id { get; set; }

[CopyValue(nameof(Source.AnaestheticDuringLabourDelivery))]
public override string? value_as_string { get; set; }

[ConstantValue(2000500001, "ANAESTHETIC GIVEN DURING LABOUR OR DELIVERY CODE")]
public override int? observation_source_concept_id { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<Query>
<Sql>
select
apc.NHSNumber,
apc.GeneratedRecordIdentifier,
coalesce(max(apc.DeliveryDate), max(apc.CDSActivityDate)) as observation_date,
apc.HospitalProviderSpellNumber,
apc.AnaestheticGivenDuringLabourDelivery
from omop_staging.sus_APC as apc
where apc.AnaestheticGivenDuringLabourDelivery is not null
and apc.NHSNumber is not null
and apc.CdsType in ('140', '120')
group by
apc.NHSNumber,
apc.GeneratedRecordIdentifier,
apc.HospitalProviderSpellNumber,
apc.DeliveryDate,
apc.AnaestheticGivenDuringLabourDelivery;
</Sql>
<Explanations>
<Explanation columnName="NHSNumber">
<Description>Patient NHS Number</Description>
<Origin>NHS NUMBER</Origin>
</Explanation>
<Explanation columnName="GeneratedRecordIdentifier">
<Description>CDS specific identifier that binds multiple CDS messages together.</Description>
<Origin>CDS RECORD IDENTIFIER</Origin>
</Explanation>
<Explanation columnName="HospitalProviderSpellNumber">
<Description>CDS specific hospital spell number that binds many episodes together.</Description>
<Origin>HOSPITAL PROVIDER SPELL NUMBER</Origin>
</Explanation>
<Explanation columnName="observation_date">
<Description>Event date</Description>
<Origin>CDS ACTIVITY DATE</Origin>
<Origin>DELIVERY DATE</Origin>
</Explanation>
<Explanation columnName="AnaestheticDuringLabourDelivery">
<Description>Records whether anaesthetic was given during Labour/ Delivery, and the type used.</Description>
<Origin>ANAESTHETIC GIVEN DURING LABOUR OR DELIVERY CODE</Origin>
</Explanation>
</Explanations>
</Query>
Loading

0 comments on commit 1a8622b

Please sign in to comment.