view pkg/imports/fm_boycar.go @ 4931:e41d42be0e13 fairway-marks-import

One more callback to avoid code duplication more consequently
author Tom Gottfried <tom@intevation.de>
date Fri, 14 Feb 2020 19:34:08 +0100
parents b86ce7fc4da3
children 9f9d72a1d398
line wrap: on
line source

// This is Free Software under GNU Affero General Public License v >= 3.0
// without warranty, see README.md and license for details.
//
// SPDX-License-Identifier: AGPL-3.0-or-later
// License-Filename: LICENSES/AGPL-3.0.txt
//
// Copyright (C) 2020 by via donau
//   – Österreichische Wasserstraßen-Gesellschaft mbH
// Software engineering by Intevation GmbH
//
// Author(s):
//  * Tom Gottfried <tom.gottfried@intevation.de>

package imports

import (
	"context"
	"database/sql"

	"gemma.intevation.de/gemma/pkg/pgxutils"
)

// Boycar is an import job to import
// fairway marks of type BOYCAR in form of point geometries
// and attribute data from a WFS service.
type Boycar struct {
	FairwayMarks
}

// Description gives a short info about relevant facts of this import.
func (boycar *Boycar) Description() (string, error) {
	return boycar.URL + "|" + boycar.FeatureType, nil
}

// BOYCARJobKind is the import queue type identifier.
const BOYCARJobKind JobKind = "fm_boycar"

type boycarJobCreator struct{}

func init() {
	RegisterJobCreator(BOYCARJobKind, boycarJobCreator{})
}

func (boycarJobCreator) Description() string { return "fairway marks boycar" }

func (boycarJobCreator) AutoAccept() bool { return true }

func (boycarJobCreator) Create() Job { return new(Boycar) }

func (boycarJobCreator) Depends() [2][]string {
	return [2][]string{
		{"fairway_marks_boycar"},
		{},
	}
}

// StageDone is a NOP for fairway marks imports.
func (boycarJobCreator) StageDone(context.Context, *sql.Tx, int64) error {
	return nil
}

// CleanUp for fairway marks imports is a NOP.
func (*Boycar) CleanUp() error { return nil }

type boycarProperties struct {
	fairwayMarksProperties
	Colour *string `json:"hydro_colour"`
	Colpat *string `json:"hydro_colpat"`
	Conrad *int    `json:"hydro_conrad"`
	Marsys *int    `json:"hydro_marsys"`
	Boyshp *int    `json:"hydro_boyshp"`
	Catcam *int    `json:"hydro_catcam"`
}

type boycarFeaturetype struct {
	geom  pointSlice
	props *boycarProperties
}

const (
	insertBOYCARSQL = `
with a as (
  select users.current_user_area_utm() AS a
)
INSERT INTO waterway.fairway_marks_boycar (
  geom,
  datsta,
  datend,
  persta,
  perend,
  objnam,
  nobjnm,
  inform,
  ninfom,
  scamin,
  picrep,
  txtdsc,
  sordat,
  sorind,
  colour,
  colpat,
  conrad,
  marsys,
  boyshp,
  catcam
)
SELECT newfm, $3, $4, $5, $6, $7, $8, $9,
    $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21
  FROM ST_Transform(ST_GeomFromWKB($1, $2::integer), 4326) AS newfm (newfm)
  WHERE pg_has_role('sys_admin', 'MEMBER')
    OR ST_Intersects((select a from a),
      ST_Transform(newfm, (select ST_SRID(a) from a)))
ON CONFLICT (
  CAST((geom,
      datsta, datend, persta, perend, objnam, nobjnm, inform, ninfom,
      scamin, picrep, txtdsc, sordat, sorind,
      0, colour, colpat, conrad, marsys, boyshp, catcam
    ) AS waterway.fairway_marks_boycar)
  )
  DO NOTHING
RETURNING id
`
)

// Do executes the actual import.
func (fm *Boycar) Do(
	ctx context.Context,
	importID int64,
	conn *sql.Conn,
	feedback Feedback,
) (interface{}, error) {

	err := getFMFeatures(
		ctx,
		conn,
		feedback,
		fm.FairwayMarks,
		func() interface{} { return new(boycarProperties) },
		func(p pointSlice, props interface{}) interface{} {
			return &boycarFeaturetype{p, props.(*boycarProperties)}
		},
		func(
			tx *sql.Tx, epsg int, fms []interface{},
		) (outsideOrDup int, features int, err error) {

			feedback.Info("Store fairway marks of type BOYCAR")

			insertStmt, err := tx.PrepareContext(ctx, insertBOYCARSQL)
			if err != nil {
				return
			}
			defer insertStmt.Close()

			savepoint := Savepoint(ctx, tx, "feature")

			for _, fm := range fms {

				f := fm.(*boycarFeaturetype)

				var fmid int64
				err := savepoint(func() error {
					err := insertStmt.QueryRowContext(
						ctx,
						f.geom.asWKB(),
						epsg,
						f.props.Datsta,
						f.props.Datend,
						f.props.Persta,
						f.props.Perend,
						f.props.Objnam,
						f.props.Nobjnm,
						f.props.Inform,
						f.props.Ninfom,
						f.props.Scamin,
						f.props.Picrep,
						f.props.Txtdsc,
						f.props.Sordat,
						f.props.Sorind,
						f.props.Colour,
						f.props.Colpat,
						f.props.Conrad,
						f.props.Marsys,
						f.props.Boyshp,
						f.props.Catcam,
					).Scan(&fmid)
					return err
				})
				switch {
				case err == sql.ErrNoRows:
					outsideOrDup++
					// ignore -> filtered by responsibility_areas
				case err != nil:
					feedback.Error(pgxutils.ReadableError{Err: err}.Error())
				default:
					features++
				}
			}
			return
		})

	return nil, err
}