changeset 4316:3d6a2c6b436c

shape upload stretch import: Store features in database. Still broken [WIP].
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Tue, 03 Sep 2019 19:01:51 +0200
parents ee4c47c3e7b2
children fa067eaf4e5a
files pkg/imports/stsh.go pkg/wkb/data.go
diffstat 2 files changed, 169 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- a/pkg/imports/stsh.go	Tue Sep 03 17:47:57 2019 +0200
+++ b/pkg/imports/stsh.go	Tue Sep 03 19:01:51 2019 +0200
@@ -24,6 +24,7 @@
 	"path"
 	"path/filepath"
 	"strings"
+	"time"
 
 	shp "github.com/jonas-p/go-shp"
 
@@ -53,6 +54,27 @@
 	}
 }
 
+const (
+	stshInsertSQL = `
+INSERT INTO waterway.stretches (
+  name,
+  stretch,
+  area,
+  objnam,
+  nobjnam,
+  date_info,
+  source_organization
+) VALUES (
+  $1,
+  isrsrange(isrs_fromText($2), isrs_fromText($3)),
+  ST_GeomFromWKB($4, 4326),
+  $5,
+  $6,
+  $7,
+  $8)
+RETURNING id`
+)
+
 func (stshJobCreator) StageDone(
 	ctx context.Context,
 	tx *sql.Tx,
@@ -66,6 +88,10 @@
 	return os.RemoveAll(stsh.Dir)
 }
 
+func fixAttribute(s string) string {
+	return strings.TrimRight(s, "\x00")
+}
+
 func (stsh *StretchShape) Do(
 	ctx context.Context,
 	importID int64,
@@ -73,7 +99,12 @@
 	feedback Feedback,
 ) (interface{}, error) {
 
-	//start := time.Now()
+	start := time.Now()
+	defer func() {
+		feedback.Info("Storing stretches from shape file took %v.",
+			time.Since(start))
+	}()
+
 	zpath := filepath.Join(stsh.Dir, "stretch.zip")
 
 	z, err := zip.OpenReader(zpath)
@@ -107,6 +138,81 @@
 
 	fields := sr.Fields()
 
+	// Map the attribute column indices.
+
+	var (
+		nameIdx      = -1
+		objnamIdx    = -1
+		nobjnamIdx   = -1
+		lowerIdx     = -1
+		upperIdx     = -1
+		sourceIdx    = -1
+		dateInfoIdx  = -1
+		countriesIdx = -1
+	)
+
+	type index struct {
+		name string
+		idx  *int
+	}
+
+	indices := []index{
+		{"name", &nameIdx},
+		{"objnam", &objnamIdx},
+		{"nobjnam", &nobjnamIdx},
+		{"lower", &lowerIdx},
+		{"upper", &upperIdx},
+		{"source", &sourceIdx},
+		{"source", &sourceIdx},
+		{"dateinfo", &dateInfoIdx},
+		{"countries", &countriesIdx},
+	}
+
+nextField:
+	for i := range fields {
+		name := strings.ToLower(fields[i].String())
+		for j := range indices {
+			if name == indices[j].name {
+				*indices[j].idx = i
+				continue nextField
+			}
+		}
+	}
+
+	var missingFields []string
+
+	for i := range indices {
+		if *indices[i].idx == -1 {
+			missingFields = append(missingFields, indices[i].name)
+		}
+	}
+
+	if len(missingFields) > 0 {
+		return nil, fmt.Errorf("missing fields in attributes: %s",
+			strings.Join(missingFields, ", "))
+	}
+
+	// Now we have ensured that all columns are in place
+	// so start extracting data from the shape file.
+
+	tx, err := conn.BeginTx(ctx, nil)
+	if err != nil {
+		return nil, err
+	}
+	defer tx.Rollback()
+
+	insStmt, err := tx.PrepareContext(ctx, stshInsertSQL)
+	if err != nil {
+		return nil, err
+	}
+	defer insStmt.Close()
+
+	insCountryStmt, err := tx.PrepareContext(ctx, stInsertCountrySQL)
+	if err != nil {
+		return nil, err
+	}
+	defer insCountryStmt.Close()
+
 	for sr.Next() {
 
 		_, p := sr.Shape()
@@ -120,17 +226,69 @@
 			continue
 		}
 
-		// Convert to a multi polygon.
-		mp := poly.MultiPolygonGeom()
+		var (
+			name      = fixAttribute(sr.Attribute(nameIdx))
+			objnam    = fixAttribute(sr.Attribute(objnamIdx))
+			nobjnam   = fixAttribute(sr.Attribute(nobjnamIdx))
+			lower     = fixAttribute(sr.Attribute(lowerIdx))
+			upper     = fixAttribute(sr.Attribute(upperIdx))
+			dateInfo  = fixAttribute(sr.Attribute(dateInfoIdx))
+			source    = fixAttribute(sr.Attribute(sourceIdx))
+			countries = fixAttribute(sr.Attribute(countriesIdx))
+		)
 
-		wkb := mp.AsWKB()
+		log.Printf("name     : %+q\n", name)
+		log.Printf("objnam   : %+q\n", objnam)
+		log.Printf("nobjnam  : %+q\n", nobjnam)
+		log.Printf("lower    : %+q\n", lower)
+		log.Printf("upper    : %+q\n", upper)
+		log.Printf("dateinfo : %+q\n", dateInfo)
+		log.Printf("source   : %+q\n", source)
+		log.Printf("countries: %+q\n", countries)
+
+		date, err := common.ParseTime(dateInfo)
+		if err != nil {
+			feedback.Warn("Invalid time value: %v.", err)
+			continue
+		}
 
-		_ = wkb
+		var nobjnamNull sql.NullString
+		if nobjnam != "" {
+			nobjnamNull = sql.NullString{
+				String: nobjnam,
+				Valid:  true,
+			}
+		}
+
+		// Convert to a multi polygon.
+		area := poly.MultiPolygonGeom().AsWKB()
+
+		log.Printf("len geom: %d\n", len(area))
+
+		var id int64
 
-		for k, f := range fields {
-			name := f.String()
-			val := sr.Attribute(k)
-			log.Printf("info: \t%s =  %v\n", name, val)
+		if err := insStmt.QueryRowContext(
+			ctx,
+			name,
+			lower, upper,
+			area,
+			objnam,
+			nobjnamNull,
+			date,
+			source,
+		).Scan(&id); err != nil {
+			return nil, err
+		}
+
+		log.Println("after insert")
+
+		for _, country := range strings.Split(countries, ",") {
+			if country = strings.TrimSpace(country); country == "" {
+				continue
+			}
+			if _, err := insCountryStmt.ExecContext(ctx, country); err != nil {
+				return nil, err
+			}
 		}
 
 		// TODO: Implement me!
@@ -140,5 +298,5 @@
 		return nil, err
 	}
 
-	return nil, nil
+	return nil, errors.New("Not implemented, yet!")
 }
--- a/pkg/wkb/data.go	Tue Sep 03 17:47:57 2019 +0200
+++ b/pkg/wkb/data.go	Tue Sep 03 19:01:51 2019 +0200
@@ -48,7 +48,7 @@
 
 	for _, pg := range mpg {
 		binary.Write(buf, binary.LittleEndian, NDR)
-		binary.Write(buf, binary.LittleEndian, uint32(len(mpg)))
+		binary.Write(buf, binary.LittleEndian, uint32(len(pg)))
 
 		for _, r := range pg {
 			binary.Write(buf, binary.LittleEndian, NDR)