func addToSpecimens(c *cmdapp.Command, src *jdh.Specimen, tax string) string { dest := &jdh.Specimen{} *dest = *src dest.Id = "" dest.Taxon = tax dest.Extern = []string{extDBFlag + ":" + src.Id} if !src.Georef.IsValid() { dest.Georef = geography.InvalidGeoref() } if len(src.Dataset) > 0 { dest.Dataset = getValidDataset(c, src.Dataset) } id, err := localDB.Exec(jdh.Add, jdh.Specimens, dest) if err != nil { fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr(err)) os.Exit(1) } return id }
func (o *occurrence) copy() *jdh.Specimen { cat := strings.TrimSpace(o.InstitutionCode) cat += ":" + strings.TrimSpace(o.CollectionCode) cat += ":" + strings.TrimSpace(o.CatalogNumber) t, _ := time.Parse("2006-01-02T15:04:05.000-0700", o.OccurrenceDate) spe := &jdh.Specimen{ Id: strconv.FormatInt(o.Key, 10), Taxon: strconv.FormatInt(o.TaxonKey, 10), Basis: getBasis(o.BasisOfRecord), Dataset: strings.TrimSpace(o.DatasetKey), Catalog: cat, Determiner: strings.Join(strings.Fields(o.IdentifierName), " "), Collector: strings.Join(strings.Fields(o.CollectorName), " "), Date: t, Geography: geography.Location{ Country: geography.GetCountry(o.CountryCode), State: strings.Join(strings.Fields(o.StateProvince), " "), County: strings.Join(strings.Fields(o.County), " "), }, Locality: strings.Join(strings.Fields(o.Locality), " "), Comment: strings.TrimSpace(o.FieldNotes + "\n" + o.OccurrenceRemarks), } if (len(spe.Locality) == 0) && (len(o.VerbatimLocality) > 0) { spe.Locality = strings.Join(strings.Fields(o.VerbatimLocality), " ") } lon, lat := float64(360), float64(360) if o.DecimalLongitude != 0 { lon = o.DecimalLongitude } if o.DecimalLatitude != 0 { lat = o.DecimalLatitude } if geography.IsLon(lon) && geography.IsLat(lat) { spe.Georef.Point = geography.Point{Lon: lon, Lat: lat} spe.Georef.Source = strings.Join(strings.Fields(o.GeoreferenceSources), " ") } else { spe.Georef = geography.InvalidGeoref() } return spe }
func spInTxt(c *cmdapp.Command, fname, parent string, rank jdh.Rank, set *jdh.Dataset) { var in *bufio.Reader if len(fname) > 0 { f, err := os.Open(fname) if err != nil { fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr(err)) return } defer f.Close() in = bufio.NewReader(f) } else { in = bufio.NewReader(os.Stdin) } for { ln, err := readLine(in) if err != nil { break } if len(ln) < 3 { continue } id := ln[0] lon, err := strconv.ParseFloat(ln[1], 64) if err != nil { fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr(err)) continue } lat, err := strconv.ParseFloat(ln[2], 64) if err != nil { fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr(err)) continue } cat := "" if len(ln) > 3 { cat = ln[3] if sp := specimen(c, localDB, cat); len(sp.Id) > 0 { continue } } if ((!geography.IsLon(lon)) || (!geography.IsLat(lat))) && (len(cat) == 0) { continue } sId := set.Id if len(ln) > 4 { sId = ln[4] if ds := dataset(c, localDB, sId); len(ds.Id) > 0 { sId = ds.Id } else { sId = "" } } spe := &jdh.Specimen{ Taxon: id, Catalog: cat, Dataset: sId, } if geography.IsLon(lon) && geography.IsLat(lat) { spe.Georef.Point = geography.Point{Lon: lon, Lat: lat} } else { if len(cat) == 0 { fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr(fmt.Sprintf("invalid coordinates %.5f %.5f", lon, lat))) continue } spe.Georef = geography.InvalidGeoref() } _, err = localDB.Exec(jdh.Add, jdh.Specimens, spe) if err != nil { fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr(err)) continue } } }
// Validate validates that an specimen is valid in the database, and set // some canonical values. It returns an error if the specimen is not valid. func (s *specimens) validate(spe *jdh.Specimen) error { spe.Id = strings.TrimSpace(spe.Id) spe.Taxon = strings.TrimSpace(spe.Taxon) if (len(spe.Id) == 0) || (len(spe.Taxon) == 0) { return errors.New("specimen without identification") } if _, ok := s.ids[spe.Id]; ok { return fmt.Errorf("specimen id %s already in use", spe.Id) } spe.Catalog = strings.TrimSpace(spe.Catalog) if len(spe.Catalog) > 0 { if _, ok := s.ids[spe.Catalog]; ok { return fmt.Errorf("specimen catalog code %s already in use", spe.Catalog) } } if !s.db.t.isInDB(spe.Taxon) { return fmt.Errorf("taxon %s [associated with specimen %s] not in database", spe.Taxon, spe.Id) } if !spe.Geography.IsValid() { spe.Geography = geography.Location{} } if !spe.Georef.IsValid() { spe.Georef = geography.InvalidGeoref() } else if (spe.Georef.Point.Lon == 0) || (spe.Georef.Point.Lon == 1) || (spe.Georef.Point.Lat == 0) || (spe.Georef.Point.Lat == 1) { spe.Georef = geography.InvalidGeoref() } if spe.Basis > jdh.Remote { spe.Basis = jdh.UnknownBasis } spe.Reference = strings.TrimSpace(spe.Reference) spe.Determiner = strings.Join(strings.Fields(spe.Determiner), " ") spe.Collector = strings.Join(strings.Fields(spe.Collector), " ") spe.Dataset = strings.TrimSpace(spe.Dataset) if len(spe.Dataset) > 0 { if !s.db.d.isInDB(spe.Dataset) { spe.Dataset = "" } } ext := spe.Extern spe.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 spe.Extern { if strings.HasPrefix(ex, serv) { add = false break } } if !add { continue } if _, ok := s.ids[e]; !ok { spe.Extern = append(spe.Extern, e) } } return nil }
// Set sets a value of an specimen in the database. func (s *specimens) set(vals []jdh.KeyValue) error { id := "" for _, kv := range vals { if len(kv.Value) == 0 { continue } if kv.Key == jdh.KeyId { id = kv.Value[0] break } } if len(id) == 0 { return errors.New("specimen without identification") } sp, ok := s.ids[id] if !ok { return nil } spe := sp.data for _, kv := range vals { switch kv.Key { case jdh.SpeBasis: v := jdh.UnknownBasis if len(kv.Value) > 0 { v = jdh.GetBasisOfRecord(strings.TrimSpace(kv.Value[0])) } if spe.Basis == v { continue } spe.Basis = v case jdh.SpeCatalog: v := "" if len(kv.Value) > 0 { v = strings.TrimSpace(kv.Value[0]) } if spe.Catalog == v { continue } if len(v) > 0 { if _, ok := s.ids[v]; ok { return fmt.Errorf("specimen catalog code %s already in use", kv.Value) } } if len(spe.Catalog) > 0 { delete(s.ids, spe.Catalog) } spe.Catalog = v if len(v) > 0 { s.ids[v] = sp } case jdh.SpeCollector: v := "" if len(kv.Value) > 0 { v = strings.Join(strings.Fields(kv.Value[0]), " ") } if spe.Collector == v { continue } spe.Collector = v case jdh.SpeDataset: v := "" if len(kv.Value) > 0 { v = strings.TrimSpace(kv.Value[0]) } if spe.Dataset == v { continue } if len(v) > 0 { if !s.db.d.isInDB(v) { continue } } spe.Dataset = v case jdh.SpeDate: if len(kv.Value) > 0 { v := strings.TrimSpace(kv.Value[0]) t, err := time.Parse(jdh.Iso8601, v) if err != nil { return err } if spe.Date.Equal(t) { continue } spe.Date = t break } if spe.Date.IsZero() { continue } spe.Date = time.Time{} case jdh.SpeDeterminer: v := "" if len(kv.Value) > 0 { v = strings.Join(strings.Fields(kv.Value[0]), " ") } if spe.Determiner == v { continue } spe.Determiner = v case jdh.SpeLocality: v := "" if len(kv.Value) > 0 { v = strings.Join(strings.Fields(kv.Value[0]), " ") } if spe.Locality == v { continue } spe.Locality = v case jdh.SpeTaxon: v := "" if len(kv.Value) > 0 { v = strings.TrimSpace(kv.Value[0]) } if len(v) == 0 { continue } if spe.Taxon == v { continue } tax, ok := s.taxId[v] if !ok { if !s.db.t.isInDB(v) { continue } tax = &speTaxon{ id: v, specs: list.New(), } tax.elem = s.taxLs.PushBack(tax) s.taxId[tax.id] = tax } oldtax := sp.taxon oldtax.specs.Remove(sp.elem) sp.elem = tax.specs.PushBack(sp) sp.taxon = tax sp.data.Taxon = tax.id if oldtax.specs.Len() == 0 { oldtax.specs = nil s.taxLs.Remove(oldtax.elem) oldtax.elem = nil delete(s.taxId, oldtax.id) } case jdh.GeoCountry: v := geography.Country("") if len(kv.Value) > 0 { v = geography.GetCountry(strings.Join(strings.Fields(kv.Value[0]), " ")) } if spe.Geography.Country == v { continue } spe.Geography.Country = v case jdh.GeoCounty: v := "" if len(kv.Value) > 0 { v = strings.Join(strings.Fields(kv.Value[0]), " ") } if spe.Geography.County == v { continue } spe.Geography.County = v case jdh.GeoLonLat: v := "" if len(kv.Value) > 0 { v = strings.TrimSpace(kv.Value[0]) } if len(v) == 0 { if !spe.Georef.IsValid() { continue } spe.Georef = geography.InvalidGeoref() break } coor := strings.Split(v, ",") if len(coor) != 2 { return errors.New("invalid geographic coordinate values") } lon, err := strconv.ParseFloat(coor[0], 64) if err != nil { return err } lat, err := strconv.ParseFloat(coor[1], 64) if err != nil { return err } if (lon == 0) || (lon == 1) || (lat == 0) || (lat == 1) { return errors.New("invalid geographic coordinate values") } if (!geography.IsLon(lon)) || (!geography.IsLat(lat)) { return errors.New("invalid geographic coordinate values") } spe.Georef.Point = geography.Point{Lon: lon, Lat: lat} case jdh.GeoSource: if !spe.Georef.IsValid() { continue } v := "" if len(kv.Value) > 0 { v = strings.Join(strings.Fields(kv.Value[0]), " ") } if spe.Georef.Source == v { continue } spe.Georef.Source = v case jdh.GeoState: v := "" if len(kv.Value) > 0 { v = strings.Join(strings.Fields(kv.Value[0]), " ") } if spe.Geography.State == v { continue } spe.Geography.State = v case jdh.GeoUncertainty: if !spe.Georef.IsValid() { continue } v := "" if len(kv.Value) > 0 { v = strings.TrimSpace(kv.Value[0]) } un64, err := strconv.ParseUint(v, 10, 0) if err != nil { return err } un := uint(un64) if un == spe.Georef.Uncertainty { continue } spe.Georef.Uncertainty = un case jdh.GeoValidation: if !spe.Georef.IsValid() { continue } v := "" if len(kv.Value) > 0 { v = strings.Join(strings.Fields(kv.Value[0]), " ") } if spe.Georef.Validation == v { continue } spe.Georef.Validation = v case jdh.KeyComment: v := "" if len(kv.Value) > 0 { v = strings.TrimSpace(kv.Value[0]) } if spe.Comment == v { continue } spe.Comment = v case jdh.KeyExtern: ok := false for _, v := range kv.Value { v = strings.TrimSpace(v) if len(v) == 0 { continue } serv, ext, err := jdh.ParseExtern(v) if err != nil { return err } if len(ext) == 0 { if !s.delExtern(sp, serv) { continue } ok = true continue } if s.addExtern(sp, v) != nil { continue } ok = true } if !ok { continue } case jdh.KeyReference: v := "" if len(kv.Value) > 0 { v = strings.TrimSpace(kv.Value[0]) } if spe.Reference == v { continue } spe.Reference = v default: continue } s.changed = true } return nil }