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 }
// 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 }
func (db *DB) occurrences(kvs []jdh.KeyValue) (jdh.ListScanner, error) { l := &listScanner{ c: make(chan interface{}, 20), end: make(chan struct{}), } id := "" var tax int64 for _, kv := range kvs { if len(kv.Value) == 0 { continue } if kv.Key == jdh.SpeTaxon { id = strings.TrimSpace(kv.Value[0]) var err error tax, err = strconv.ParseInt(id, 10, 64) if err != nil { return nil, err } break } if kv.Key == jdh.SpeTaxonParent { id = strings.TrimSpace(kv.Value[0]) break } } if len(id) == 0 { return nil, errors.New("taxon " + id + " without [ny] identification") } go func() { vals := url.Values{} vals.Add("taxonKey", id) vals.Add("basisOfRecord", "PRESERVED_SPECIMEN") vals.Add("basisOfRecord", "FOSSIL_SPECIMEN") for _, kv := range kvs { if len(kv.Value) == 0 { continue } switch kv.Key { case jdh.GeoCountry: for _, v := range kv.Value { vals.Add("country", string(geography.GetCountry(v))) } case jdh.SpeGeoref: if kv.Value[0] == "true" { vals.Set("has_coordinate", "true") } else if kv.Value[0] == "false" { vals.Set("has_coordinate", "false") } } } for off := int64(0); ; { if off > 0 { vals.Set("offset", strconv.FormatInt(off, 10)) } request := wsHead + "occurrence/search?" + vals.Encode() an := new(occAnswer) if err := db.listRequest(request, an); err != nil { l.setErr(err) return } for _, oc := range an.Results { if tax > 0 { if oc.TaxonKey != tax { continue } } select { case l.c <- oc.copy(): case <-l.end: return } } if an.EndOfRecords { break } off += an.Limit } select { case l.c <- nil: case <-l.end: } }() return l, nil }
// List returns a list of specimens. func (s *specimens) list(vals []jdh.KeyValue) (*list.List, error) { l := list.New() noVal := true // creates the list for _, kv := range vals { if len(kv.Value) == 0 { continue } if kv.Key == jdh.SpeTaxon { if len(kv.Value[0]) == 0 { return nil, errors.New("taxon without identification") } tax, ok := s.taxId[kv.Value[0]] if !ok { return l, nil } for e := tax.specs.Front(); e != nil; e = e.Next() { sp := e.Value.(*specimen) l.PushBack(sp.data) } noVal = false break } if kv.Key == jdh.SpeTaxonParent { if len(kv.Value[0]) == 0 { return nil, errors.New("taxon without identification") } pId := kv.Value[0] if !s.db.t.isInDB(pId) { return l, nil } for m := s.taxLs.Front(); m != nil; m = m.Next() { tax := m.Value.(*speTaxon) if tax.id != pId { if !s.db.t.isDesc(tax.id, pId) { continue } } for e := tax.specs.Front(); e != nil; e = e.Next() { sp := e.Value.(*specimen) l.PushBack(sp.data) } } noVal = false break } } if noVal { return nil, errors.New("taxon without identification") } //filters the list. for _, kv := range vals { if l.Len() == 0 { break } if len(kv.Value) == 0 { continue } switch kv.Key { case jdh.GeoCountry: for e := l.Front(); e != nil; { nx := e.Next() spe := e.Value.(*jdh.Specimen) remove := true for _, v := range kv.Value { c := geography.GetCountry(v) if len(c) == 0 { continue } if spe.Geography.Country == c { remove = false break } } if remove { l.Remove(e) } e = nx } case jdh.SpeGeoref: if (kv.Value[0] != "true") && (kv.Value[0] != "false") { continue } ok := false if kv.Value[0] == "true" { ok = true } for e := l.Front(); e != nil; { nx := e.Next() spe := e.Value.(*jdh.Specimen) if spe.Georef.IsValid() != ok { l.Remove(e) } e = nx } } } return l, nil }