Example #1
0
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
}
Example #2
0
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
}
Example #3
0
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
		}
	}
}
Example #4
0
// 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
}
Example #5
0
// 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
}