import "utilsLib" as utilsLib; import "journalTypes" as journalTypes; def ingestionDose($customUnits): . as $ingestion | journalTypes::ensureIngestion | if .customUnitId != null then ($customUnits | map(select(.id == $ingestion.customUnitId))[0]) as $customUnit | .dose * $customUnit.dose | . as $dose | $dose else .dose end; # this probably isnt right def addStandardDeviations($expectationX; $standardDeviationX; $expectationY; $standardDeviationY): (pow($standardDeviationX; 2) + pow($expectationX; 2)) as $sumX | (pow($standardDeviationY; 2) + pow($expectationY; 2)) as $sumY | (pow($expectationX; 2) * pow($expectationY; 2)) as $expectations | ($sumX * $sumY - $expectations) as $productVariance | if $productVariance > 0.0000001 then $productVariance | debug | sqrt else null end; def ingestionStandardDeviation($customUnits): . as $ingestion | journalTypes::ensureIngestion | if .customUnitId != null then ($customUnits | map(select(.id == $ingestion.customUnitId))[0]) as $customUnit | ($ingestion | ingestionDose($customUnits) // 0) as $expectationX | ($ingestion.estimatedDoseStandardDeviation // 0) as $standardDeviationX | ($customUnit.dose // 0) as $expectationY | ($customUnit.estimatedDoseStandardDeviation // 0) as $standardDeviationY | addStandardDeviations($expectationX; $standardDeviationX; $expectationY; $standardDeviationY) else .standardDeviation end; def ingestionUnit($customUnits): . as $ingestion | journalTypes::ensureIngestion | if .customUnitId != null then ($customUnits | map(select(.id == $ingestion.customUnitId))[0]) as $customUnit | $customUnit.originalUnit else .units end; def ingestionConsumerName: . as $ingestion | journalTypes::ensureIngestion | $ingestion.consumerName // "default"; def filterIngestions($substanceFilter; $consumerFilter): . as $ingestions | journalTypes::ensureIngestions | if (($substanceFilter // [] | length) > 0) then [ $ingestions[] as $ingestion | if ([$substanceFilter[] | . == $ingestion.substanceName] | any) and ([$consumerFilter[] | . == ($ingestion | ingestionConsumerName)] | any) then $ingestion else null end ] | map(select(. != null)) else $ingestions end; def ingestionsSubstanceNames: . as $ingestions | journalTypes::ensureIngestions | [$ingestions[].substanceName] | utilsLib::orderedUnique; def ingestionsConsumerNames: . as $ingestions | journalTypes::ensureIngestions | [$ingestions[] | ingestionConsumerName] | utilsLib::orderedUnique; def ingestionsByConsumer: . as $ingestions | journalTypes::ensureIngestions | ($ingestions | ingestionsConsumerNames) as $consumerNames | [ $consumerNames[] as $consumerName | { key: $consumerName, value: [$ingestions | map(select( . | ingestionConsumerName == $consumerName ))], } ] | from_entries; def defaultIngestionInfo: { unit: "", dose: null, isUnknown: false, isEstimate: false, # TODO standardDeviation: null }; def ingestionInfo($customUnits): . as $ingestion | .substanceName as $name | .administrationRoute as $administrationRoute | . | ingestionStandardDeviation($customUnits) as $standardDeviation | . | ingestionDose($customUnits) as $dose | . | ingestionUnit($customUnits) as $unit | . | ingestionConsumerName as $consumerName | defaultIngestionInfo as $ingestionInfo | $ingestionInfo | if ($dose == null) then .isUnknown |= true end | if ($standardDeviation != null) then .isEstimate |= true end | .unit |= $unit | .dose += $dose; def addIngestionInfo($rhs): . as $lhs | if (.unit != "" and $rhs.unit != "") then utilsLib::assert(.unit == $rhs.unit; "units mismatch, todo add reasonable conversions") else .unit |= $rhs.unit end | if ($rhs.dose == null) then .isUnknown |= true end | if ($rhs.standardDeviation != null) then .isEstimate |= true end | .dose += $rhs.dose; def addIngestionInfos: . as $ingestionInfos | reduce $ingestionInfos[] as $ingestionInfo (defaultIngestionInfo; . | addIngestionInfo($ingestionInfo) ); def experienceStats($customUnits): . as $experience | journalTypes::ensureExperience | $experience.ingestions as $ingestions | (reduce $ingestions[] as $ingestion ({}; . as $stats | $ingestion | .substanceName as $name | .administrationRoute as $administrationRoute | . | ingestionConsumerName as $consumerName | $stats | .[$consumerName].[$ingestion.substanceName].[$administrationRoute] as $ingestionStats | if $ingestionStats == null then ($ingestion | ingestionInfo($customUnits)) else $ingestionStats | addIngestionInfo($ingestion | ingestionInfo($customUnits)) end | . as $ingestionStats | $stats | .[$consumerName].[$ingestion.substanceName].[$administrationRoute] |= $ingestionStats )); def statsCalculateCombinedDose($substanceName; $consumerName): . as $stats | utilsLib::assert($stats | has($consumerName); "consumer not found in stats") | utilsLib::assert($stats[$consumerName] | has($substanceName); "substance for consumer not found in stats" ) | .[$consumerName].[$substanceName] | values | addIngestionInfos; def experiencesWithExtraData($customUnits): . as $experiences | journalTypes::ensureExperiences | (reduce $experiences[] as $experience ([]; ($experience | experienceStats($customUnits)) as $stats | . += [{ $stats, $experience }] )); def filterSortExperiences($customUnits; $substanceFilter; $consumerFilter; $sortMethod; $sortOptions): . as $experiences | journalTypes::ensureExperiences | ($consumerFilter // ["default"]) as $consumerFilter | $sortOptions | # If filtering results by substances but no sortOptions.substanceName is defined, use the first one as a default (.substanceName |= if $sortOptions.substanceName == null and (($substanceFilter | length) >= 1) then $substanceFilter[0] else null end ) | . as $sortOptions | $sortOptions | (.ingestionMethod |= ($sortOptions.ingestionMethod // "ORAL")) | . as $sortOptions | $sortOptions | (.consumerName |= ($sortOptions.consumerName // "default")) | . as $sortOptions | def sortFilter: def oldToNewSort: .experience.sortDate; def highestCombinedDoseSort: .stats.[$sortOptions.consumerName].[$sortOptions.substanceName] | [to_entries[] | .value.dose] | add; def highestMethodDoseSort: .stats.[$sortOptions.consumerName].[$sortOptions.substanceName].[$sortOptions.ingestionMethod // "ORAL"].dose; def filterBySubstanceFilter: . as $experiencesData | [ $experiencesData[] as $experienceData | ($experienceData.experience.ingestions) as $ingestions | if ($experienceData.experience.ingestions | any( . as $ingestion | $substanceFilter | any(index($ingestion.substanceName)) ) ) then $experienceData else null end ] | map(select(. != null)); def filterByConsumerFilter: . as $experiencesData | (reduce $experiencesData[] as $experienceData ([]; ($experienceData.experience.ingestions) as $ingestions | . += if ($experienceData.experience.ingestions | any( (. | ingestionConsumerName) as $consumerName | $consumerFilter | any(index($consumerName)) ) ) then [$experienceData] else [] end )); def filterBySubstanceAndConsumer: . as $experiencesData | (reduce $experiencesData[] as $experienceData ([]; ($experienceData.experience.ingestions) as $ingestions | . += if ($experienceData.experience.ingestions | any( .substanceName == $sortOptions.substanceName and (. | ingestionConsumerName) == $sortOptions.consumerName )) then [$experienceData] else [] end )); def filterByIngestionMethodForSubstance: . as $experiencesData | filterBySubstanceAndConsumer as $experiencesData | (reduce $experiencesData[] as $experienceData ([]; ($experienceData.experience.ingestions) as $ingestions | . += if ($experienceData.experience.ingestions | any(.substanceName == $sortOptions.substanceName and .administrationRoute == $sortOptions.ingestionMethod)) then [$experienceData] else [] end )); # speeds up by excluding everything not containing substances & consumers not in filters, wouldn't show any data anyway if $substanceFilter != null then filterBySubstanceFilter end | filterByConsumerFilter | if $sortMethod == "old-to-new" or $sortMethod == null then sort_by(oldToNewSort) elif $sortMethod == "highest-combined-dose" then utilsLib::assert($sortOptions.substanceName != null; "substanceName not provided as sortOption") | filterBySubstanceAndConsumer | sort_by(highestCombinedDoseSort, oldToNewSort) | reverse elif $sortMethod == "highest-dose-for-method" then utilsLib::assert($sortOptions.substanceName != null; "substanceName not provided as sortOption") | filterByIngestionMethodForSubstance | sort_by(highestMethodDoseSort, oldToNewSort) | reverse end; $experiences | experiencesWithExtraData($customUnits) | sortFilter; def experienceByTitle($name): utilsLib::assert((. | type) == "array"; "experienceByTitle takes a array of experiences as input") | map(select(.title == $name))[0];