import "utils" as utils; def calculateIngestionDose($customUnits): . as $ingestion | if .customUnitId != null then ($customUnits | map(select(.id == $ingestion.customUnitId))[0]) as $customUnit | .dose * $customUnit.dose | . as $dose | $dose * 100 | round / 100 else .dose end; def ingestionUnit($customUnits): . as $ingestion | if .customUnitId != null then ($customUnits | map(select(.id == $ingestion.customUnitId))[0]) as $customUnit | $customUnit.originalUnit else .units end; def ingestionConsumerName: . as $ingestion | $ingestion.consumerName // "default"; def filterIngestions($substanceFilter; $consumerFilter): . as $ingestions | 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 | [$ingestions[].substanceName] | utils::orderedUnique; def ingestionsConsumerNames: . as $ingestions | [$ingestions[] | ingestionConsumerName] | utils::orderedUnique; def ingestionsByConsumer: . as $ingestions | ($ingestions | ingestionsConsumerNames) as $consumerNames | [ $consumerNames[] as $consumerName | { key: $consumerName, value: [$ingestions | map(select( . | ingestionConsumerName == $consumerName ))], } ] | from_entries; def experienceStats($customUnits): . as $experience | $experience.ingestions as $ingestions | (reduce $ingestions[] as $ingestion ({}; . as $stats | $ingestion | .substanceName as $name | .administrationRoute as $administrationRoute | . | calculateIngestionDose($customUnits) as $dose | . | ingestionUnit($customUnits) as $unit | . | ingestionConsumerName as $consumerName | $stats | .[$consumerName].[$name].[$administrationRoute] |= ($stats.[$consumerName].[$name].[$administrationRoute] // { unit: "", # null because null+null = null for ingestions with unknown dose which .dose is null dose: null }) | .[$consumerName].[$name].[$administrationRoute].unit |= $unit | .[$consumerName].[$name].[$administrationRoute].dose += $dose )); def statsCalculateCombinedDose($substanceName; $consumerName): . as $stats | (.[$consumerName].[$substanceName] | [to_entries[] | .value.dose] | add) as $combinedDose | (.[$consumerName].[$substanceName] | to_entries[0] | .value.unit) as $combinedDoseUnit | {dose: $combinedDose, unit: $combinedDoseUnit}; def experiencesWithExtraData($customUnits): . as $experiences | (reduce $experiences[] as $experience ([]; ($experience | experienceStats($customUnits)) as $stats | . += [{ $stats, $experience }] )); def filterSortExperiences($customUnits; $substanceFilter; $consumerFilter; $sortMethod; $sortOptions): . as $experiences | ($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 utils::assert($sortOptions.substanceName != null; "substanceName not provided as sortOption") | filterBySubstanceAndConsumer | sort_by(highestCombinedDoseSort, oldToNewSort) | reverse elif $sortMethod == "highest-dose-for-method" then utils::assert($sortOptions.substanceName != null; "substanceName not provided as sortOption") | filterByIngestionMethodForSubstance | sort_by(highestMethodDoseSort, oldToNewSort) | reverse end; $experiences | experiencesWithExtraData($customUnits) | sortFilter; def experienceByTitle($name): utils::assert((. | type) == "array"; "experienceByTitle takes a array of experiences as input") | map(select(.title == $name))[0];