// Validate validates that a taxon is valid in the database, and set some // canonical values. It returns an error if the taxon is not valid. func (t *taxonomy) validate(tax *jdh.Taxon) error { tax.Id = strings.TrimSpace(tax.Id) tax.Name = strings.Join(strings.Fields(tax.Name), " ") if (len(tax.Id) == 0) || (len(tax.Name) == 0) { return errors.New("taxon without identification") } if _, ok := t.ids[tax.Id]; ok { return fmt.Errorf("taxon id %s already in use", tax.Id) } p := t.root if tax.Rank > jdh.Species { tax.Rank = jdh.Unranked } if len(tax.Parent) > 0 { var ok bool if p, ok = t.ids[tax.Parent]; !ok { return fmt.Errorf("taxon %s parent [%s] not in database", tax.Name, tax.Parent) } } if p == t.root { if !tax.IsValid { return fmt.Errorf("taxon %s is a synonym without a parent", tax.Name) } } else if !p.data.IsValid { return fmt.Errorf("taxon %s parent [%s] is a synonym", tax.Name, p.data.Name) } if !p.isDescValid(tax.Rank, tax.IsValid) { return fmt.Errorf("taxon %s rank incompatible with database hierarchy", tax.Name) } ext := tax.Extern tax.Extern = nil for _, e := range ext { serv, id, err := jdh.ParseExtern(e) if err != nil { continue } if len(id) == 0 { continue } add := true for _, ex := range tax.Extern { if strings.HasPrefix(ex, serv) { add = false break } } if !add { continue } if _, ok := t.ids[e]; !ok { tax.Extern = append(tax.Extern, e) } } return nil }
// Add adds a new taxon to the database. func (t *taxonomy) add(tax *jdh.Taxon) (string, error) { id := strconv.FormatInt(t.next, 10) tax.Id = id if err := t.validate(tax); err != nil { return "", err } t.addTaxon(tax) t.next++ t.changed = true return id, nil }
// TxSyncUpdate implements the update option of tx.sync. func txSyncUpdate(c *cmdapp.Command, tax *jdh.Taxon) { // first process the descendants (as it is possible that a taxon // will be set as synonym, and then thier descendant set will change) l := getTaxDesc(c, localDB, tax.Id, true) txSyncUpdateNav(c, l) l = getTaxDesc(c, localDB, tax.Id, false) txSyncUpdateNav(c, l) if len(tax.Id) == 0 { return } eid := searchExtern(extDBFlag, tax.Extern) if len(eid) == 0 { return } ext := taxon(c, extDB, eid) if len(ext.Id) == 0 { fmt.Fprintf(os.Stderr, "unable to retrieve %s:%s\n", tax.Extern, eid) return } if validFlag { if tax.IsValid != ext.IsValid { args := new(jdh.Values) args.Add(jdh.KeyId, tax.Id) if ext.IsValid { args.Add(jdh.TaxValid, "") localDB.Exec(jdh.Set, jdh.Taxonomy, args) } else { p := taxon(c, localDB, extDBFlag+":"+ext.Parent) if len(p.Id) == 0 { exPar := taxon(c, extDB, ext.Parent) p = txSyncAddToTaxonomy(c, exPar) } args.Add(jdh.TaxSynonym, p.Id) localDB.Exec(jdh.Set, jdh.Taxonomy, args) } } } if !updateFlag { return } if len(ext.Authority) > 0 { args := new(jdh.Values) args.Add(jdh.KeyId, tax.Id) args.Add(jdh.TaxAuthority, ext.Authority) localDB.Exec(jdh.Set, jdh.Taxonomy, args) } if ext.Rank != jdh.Unranked { args := new(jdh.Values) args.Add(jdh.KeyId, tax.Id) args.Add(jdh.TaxRank, ext.Rank.String()) localDB.Exec(jdh.Set, jdh.Taxonomy, args) } if len(ext.Comment) > 0 { if len(tax.Comment) > 0 { tax.Comment += "\n" } tax.Comment += ext.Comment args := new(jdh.Values) args.Add(jdh.KeyId, tax.Id) args.Add(jdh.KeyComment, tax.Comment) localDB.Exec(jdh.Set, jdh.Taxonomy, args) } }