seekia/internal/genetics/myPeople/myPeople.go

284 lines
8.2 KiB
Go
Raw Normal View History

// 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
}