// myPeople provides functions to manage a user's genome people // Each person can have many genomes and a genetic analysis // Each person's genomes are stored in myGenomes // This package stores each person's identifier, name, sex, and createdTime package myPeople import "seekia/internal/myDatastores/myMapList" import "seekia/internal/helpers" import "seekia/internal/genetics/myGenomes" import "seekia/internal/genetics/myCouples" import "seekia/internal/genetics/myAnalyses" import "time" import "sync" import "errors" // This will be locked anytime People are being added/deleted var updatingMyPeopleMutex sync.Mutex var myGenomePeopleMapListDatastore *myMapList.MyMapList // This function must be called whenever an app user signs in func InitializeMyGenomePeopleDatastore()error{ updatingMyPeopleMutex.Lock() defer updatingMyPeopleMutex.Unlock() newMyGenomePeopleMapListDatastore, err := myMapList.CreateNewMapList("MyGenomePeople") if (err != nil) { return err } myGenomePeopleMapListDatastore = newMyGenomePeopleMapListDatastore return nil } //Outputs: // -[]map[string]string // -PersonIdentifier -> Person Identifier // -PersonName -> Person Name // -CreatedTime -> Time the person was created // -error func GetMyGenomePeopleMapList()([]map[string]string, error){ peopleMapList, err := myGenomePeopleMapListDatastore.GetMapList() if (err != nil) { return nil, err } return peopleMapList, nil } //Outputs: // -bool: Person with this name already exists // -error func AddPerson(personName string, personSex string)(bool, error){ if (personName == ""){ return false, errors.New("AddPerson called with empty personName") } if (personSex != "Male" && personSex != "Female" && personSex != "Intersex"){ return false, errors.New("AddPerson called with invalid personSex: " + personSex) } personIdentifier, err := helpers.GetNewRandomHexString(15) if (err != nil) { return false, err } createdTime := time.Now().Unix() createdTimeString := helpers.ConvertInt64ToString(createdTime) updatingMyPeopleMutex.Lock() defer updatingMyPeopleMutex.Unlock() lookupMap := map[string]string{ "PersonName": personName, } anyExist, _, err := myGenomePeopleMapListDatastore.GetMapListItems(lookupMap) if (err != nil) { return false, err } if (anyExist == true){ return true, nil } peopleMapList, err := myGenomePeopleMapListDatastore.GetMapList() if (err != nil) { return false, err } newPersonMap := map[string]string{ "PersonIdentifier": personIdentifier, "PersonName": personName, "CreatedTime": createdTimeString, "PersonSex": personSex, } newPeopleMapList := append(peopleMapList, newPersonMap) err = myGenomePeopleMapListDatastore.OverwriteMapList(newPeopleMapList) if (err != nil) { return false, err } return false, nil } //Outputs: // -bool: Person with this name already exists // -error func EditPerson(personIdentifier string, newPersonName string, newPersonSex string)(bool, error){ if (newPersonName == ""){ return false, errors.New("EditPerson called with empty newPersonName") } if (newPersonSex != "Male" && newPersonSex != "Female" && newPersonSex != "Intersex"){ return false, errors.New("EditPerson called with invalid newPersonSex: " + newPersonSex) } updatingMyPeopleMutex.Lock() defer updatingMyPeopleMutex.Unlock() lookupMap := map[string]string{ "PersonName": newPersonName, } anyExist, _, err := myGenomePeopleMapListDatastore.GetMapListItems(lookupMap) if (err != nil) { return false, err } if (anyExist == true){ // Someone else already has this name return true, nil } peopleMapList, err := myGenomePeopleMapListDatastore.GetMapList() if (err != nil) { return false, err } for _, personMap := range peopleMapList{ currentPersonIdentifier, exists := personMap["PersonIdentifier"] if (exists == false){ return false, errors.New("MyGenomePeopleMapList malformed: contains entry missing PersonIdentifier") } if (currentPersonIdentifier == personIdentifier){ personMap["PersonName"] = newPersonName personMap["PersonSex"] = newPersonSex } } err = myGenomePeopleMapListDatastore.OverwriteMapList(peopleMapList) if (err != nil) { return false, err } return false, nil } // This function will delete the person, any couples with the person, and all of the person's genomes func DeletePerson(personIdentifier string)error{ updatingMyPeopleMutex.Lock() defer updatingMyPeopleMutex.Unlock() err := myGenomes.DeleteAllPersonGenomes(personIdentifier) if (err != nil) { return err } err = myCouples.DeleteAllCouplesForPerson(personIdentifier) if (err != nil) { return err } mapToDelete := map[string]string{ "PersonIdentifier": personIdentifier, } err = myGenomePeopleMapListDatastore.DeleteMapListItems(mapToDelete) if (err != nil) { return err } err = myAnalyses.DeleteAllAnalysesForPerson(personIdentifier) if (err != nil) { return err } return nil } //Outputs: // -bool: Person found // -string: Person name // -int64: Created time // -string: Sex ("Male"/"Female"/"Intersex") // -error func GetPersonInfo(personIdentifier string)(bool, string, int64, string, error){ if (personIdentifier == "111111111111111111111111111111" || personIdentifier == "222222222222222222222222222222"){ // These are the identifiers we use for sample analyses // These are analyses the user can view if they want to see what an analysis will look like getPersonName := func()string{ if (personIdentifier == "111111111111111111111111111111"){ return "Person A" } return "Person B" } personName := getPersonName() currentTime := time.Now().Unix() getPersonSex := func()string{ if (personIdentifier == "111111111111111111111111111111"){ return "Male" } return "Female" } personSex := getPersonSex() return true, personName, currentTime, personSex, nil } lookupMap := map[string]string{ "PersonIdentifier": personIdentifier, } anyItemFound, retrievedItemsList, err := myGenomePeopleMapListDatastore.GetMapListItems(lookupMap) if (err != nil) { return false, "", 0, "", err } if (anyItemFound == false){ return false, "", 0, "", nil } if (len(retrievedItemsList) != 1){ return false, "", 0, "", errors.New("myGenomePeopleMapList malformed: Multiple entries exist for 1 person") } personMap := retrievedItemsList[0] createdTime, exists := personMap["CreatedTime"] if (exists == false) { return false, "", 0, "", errors.New("myGenomePeopleMapList malformed: Entry missing CreatedTime") } createdTimeInt64, err := helpers.ConvertStringToInt64(createdTime) if (err != nil) { return false, "", 0, "", errors.New("myGenomePeopleMapList malformed: Invalid CreatedTime: " + createdTime) } personName, exists := personMap["PersonName"] if (exists == false) { return false, "", 0, "", errors.New("myGenomePeopleMapList malformed: Entry missing PersonName") } personSex, exists := personMap["PersonSex"] if (exists == false) { return false, "", 0, "", errors.New("myGenomePeopleMapList malformed: Entry missing PersonSex") } return true, personName, createdTimeInt64, personSex, nil } // This will return true if a person's analysis is ready // This means it was created with all of the person's genomes using the newest available analysis version // Outputs: // -bool: Any Genomes exist // -bool: Person analysis is ready // -string: Newest ready person genetic analysis // -error func CheckIfPersonAnalysisIsReady(personIdentifier string)(bool, bool, string, error){ allPersonRawGenomeIdentifiersList, err := myGenomes.GetAllPersonRawGenomeIdentifiersList(personIdentifier) if (err != nil){ return false, false, "", err } if (len(allPersonRawGenomeIdentifiersList) == 0){ return false, false, "", nil } anyAnalysisFound, newestAnalysisIdentifier, _, newestAnalysisListOfGenomesAnalyzed, newerAnalysisVersionAvailable, err := myAnalyses.GetPersonNewestGeneticAnalysisInfo(personIdentifier) if (err != nil){ return false, false, "", err } if (anyAnalysisFound == false){ return true, false, "", nil } if (newerAnalysisVersionAvailable == true){ return true, false, "", nil } genomesAreIdentical := helpers.CheckIfTwoListsContainIdenticalItems(allPersonRawGenomeIdentifiersList, newestAnalysisListOfGenomesAnalyzed) if (genomesAreIdentical == false){ // A newer genome has been added return true, false, "", nil } return true, true, newestAnalysisIdentifier, nil }