// myChosenAnalysis provides a function to get a mate user's chosen genetic analysis // Mate users choose a genome person and genome in the Build Profile gui. // The genome person's analysis is used for calculating genetic attributes with other users and for sharing on their profile // The user can choose to not share any of the genetic analysis information on their profile, in which case // the analysis is only used when calculating attributes with other users // An example of one of these calculated attributes is "OffspringProbabilityOfAnyMonogenicDisease" package myChosenAnalysis import "seekia/internal/genetics/myAnalyses" import "seekia/internal/genetics/myPeople" import "seekia/internal/genetics/readGeneticAnalysis" import "seekia/internal/helpers" import "seekia/internal/profiles/myLocalProfiles" import "errors" import "sync" // We use this mutex whenever we update the cacheChosenGeneticAnalysis global variables var myCacheChosenGeneticAnalysisMutex sync.RWMutex // We use this identifier to keep track of which analysis we have stored in the cache // Whenever we update our genome person's analysis, we will update our cache analysis var myCacheChosenGeneticAnalysisIdentifier string // We use this variable to store the analysis in memory // This prevents us from having to read and unmarshal the json file each time we want to retrieve the analysis // TODO: Read attributes from the analysis into maps for faster retrieval var myCacheChosenGeneticAnalysis []map[string]string // These variables store metadata about the cache genetic analysis var myCacheChosenGeneticAnalysis_GenomeIdentifierToUse string // This variable tells us if the current cache chosen genetic analysis contains multiple genomes var myCacheChosenGeneticAnalysis_MultipleGenomesExist bool // This function is used to retrieve the user's chosen person genetic analysis // The user must choose a person to link to their mate profile/identity // This genetic analysis is not shared on the person's profile publicly. // Portions of the analysis may be shared if the user opts in. //Outputs: // -bool: Person identifier chosen // -bool: Any genomes exist // -bool: Person analysis is ready // -[]map[string]string: Genetic analysis map list // -string: Genome identifier to use // -bool: Multiple genomes exist // -error func GetMyChosenMateGeneticAnalysis()(bool, bool, bool, []map[string]string, string, bool, error){ // We check if the user has added a genome person, and add their genome info if necessary myGenomePersonIdentifierExists, myGenomePersonIdentifier, err := myLocalProfiles.GetProfileData("Mate", "GenomePersonIdentifier") if (err != nil){ return false, false, false, nil, "", false, err } if (myGenomePersonIdentifierExists == false){ return false, false, false, nil, "", false, nil } anyGenomesExist, personAnalysisIsReady, personAnalysisIdentifier, err := myPeople.CheckIfPersonAnalysisIsReady(myGenomePersonIdentifier) if (err != nil){ return false, false, false, nil, "", false, err } if (anyGenomesExist == false){ return true, false, false, nil, "", false, nil } if (personAnalysisIsReady == false){ return true, true, false, nil, "", false, nil } myCacheChosenGeneticAnalysisMutex.RLock() myCacheChosenGeneticAnalysisIdentifierCopy := myCacheChosenGeneticAnalysisIdentifier myCacheChosenGeneticAnalysisMutex.RUnlock() if (myCacheChosenGeneticAnalysisIdentifierCopy == personAnalysisIdentifier){ // The analysis exists in cache // We copy it and return it myCacheChosenGeneticAnalysisMutex.RLock() myCacheChosenGeneticAnalysisCopy := helpers.DeepCopyStringToStringMapList(myCacheChosenGeneticAnalysis) myCacheChosenGeneticAnalysis_GenomeIdentifierToUseCopy := myCacheChosenGeneticAnalysis_GenomeIdentifierToUse myCacheChosenGeneticAnalysis_MultipleGenomesExistCopy := myCacheChosenGeneticAnalysis_MultipleGenomesExist myCacheChosenGeneticAnalysisMutex.RUnlock() return true, true, true, myCacheChosenGeneticAnalysisCopy, myCacheChosenGeneticAnalysis_GenomeIdentifierToUseCopy, myCacheChosenGeneticAnalysis_MultipleGenomesExistCopy, nil } // The analysis and its metadata have not been read into the cache yet // We will retrieve it from its .json file myAnalysisFound, myGeneticAnalysisMapList, err := myAnalyses.GetGeneticAnalysis(personAnalysisIdentifier) if (err != nil){ return false, false, false, nil, "", false, err } if (myAnalysisFound == false){ return false, false, false, nil, "", false, errors.New("CheckIfPersonAnalysisIsReady returning missing genetic analysis.") } allRawGenomeIdentifiersList, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(myGeneticAnalysisMapList) if (err != nil) { return false, false, false, nil, "", false, err } getGenomeIdentifierToUse := func()(string, error){ if (multipleGenomesExist == false){ // The analysis only has 1 genome identifier. analysisOnlyRawGenomeIdentifier := allRawGenomeIdentifiersList[0] return analysisOnlyRawGenomeIdentifier, nil } currentCombinedGenomeToUse, err := GetMyCombinedGenomeToUse() if (err != nil){ return "", err } if (currentCombinedGenomeToUse == "Only Exclude Conflicts"){ return onlyExcludeConflictsGenomeIdentifier, nil } // currentCombinedGenomeToUse == "Only Include Shared" return onlyIncludeSharedGenomeIdentifier, nil } genomeIdentifierToUse, err := getGenomeIdentifierToUse() if (err != nil) { return false, false, false, nil, "", false, err } myCacheChosenGeneticAnalysisMutex.Lock() myCacheChosenGeneticAnalysisIdentifier = personAnalysisIdentifier myCacheChosenGeneticAnalysis = myGeneticAnalysisMapList myCacheChosenGeneticAnalysis_GenomeIdentifierToUse = genomeIdentifierToUse myCacheChosenGeneticAnalysis_MultipleGenomesExist = multipleGenomesExist myChosenGeneticAnalysisCopy := helpers.DeepCopyStringToStringMapList(myGeneticAnalysisMapList) myCacheChosenGeneticAnalysisMutex.Unlock() return true, true, true, myChosenGeneticAnalysisCopy, genomeIdentifierToUse, multipleGenomesExist, nil } //Outputs: // -string: "Only Include Shared", "Only Exclude Conflicts" // -error func GetMyCombinedGenomeToUse()(string, error){ combinedGenomeToUseExists, combinedGenomeToUse, err := myLocalProfiles.GetProfileData("Mate", "CombinedGenomeToUse") if (err != nil){ return "", err } if (combinedGenomeToUseExists == false){ return "Only Exclude Conflicts", nil } if (combinedGenomeToUse != "Only Include Shared" && combinedGenomeToUse != "Only Exclude Conflicts"){ return "", errors.New("myLocalProfiles is malformed: Contains invalid combinedGenomeToUse: " + combinedGenomeToUse) } return combinedGenomeToUse, nil } func SetMyCombinedGenomeToUse(combinedGenomeToUse string)error{ if (combinedGenomeToUse != "Only Include Shared" && combinedGenomeToUse != "Only Exclude Conflicts"){ return errors.New("SetCombinedGenomeToUse called with invalid combinedGenomeToUse: " + combinedGenomeToUse) } err := myLocalProfiles.SetProfileData("Mate", "CombinedGenomeToUse", combinedGenomeToUse) if (err != nil) { return err } // We reset the global variables so the new analysis GenomeIdentifierToUse global variable will be updated myCacheChosenGeneticAnalysisMutex.Lock() myCacheChosenGeneticAnalysisIdentifier = "" myCacheChosenGeneticAnalysis = nil myCacheChosenGeneticAnalysis_GenomeIdentifierToUse = "" myCacheChosenGeneticAnalysis_MultipleGenomesExist = false myCacheChosenGeneticAnalysisMutex.Unlock() return nil }