Skip to content

Commit

Permalink
Merge pull request #45 from PDOK/oas-collections
Browse files Browse the repository at this point in the history
Oas collections
  • Loading branch information
WouterVisscher committed Jun 25, 2021
2 parents e333ca2 + d93bdf7 commit a9c79db
Show file tree
Hide file tree
Showing 12 changed files with 154 additions and 131 deletions.
1 change: 1 addition & 0 deletions go.mod
Expand Up @@ -4,6 +4,7 @@ require (
github.com/getkin/kin-openapi v0.63.0
github.com/go-openapi/swag v0.19.15 // indirect
github.com/go-spatial/geom v0.0.0-20210315165355-0e06498b3362
github.com/imdario/mergo v0.3.12
github.com/jmoiron/sqlx v1.3.4
github.com/lib/pq v1.10.2
github.com/mailru/easyjson v0.7.7 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Expand Up @@ -21,6 +21,8 @@ github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LB
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/jmoiron/sqlx v1.3.4 h1:wv+0IJZfL5z0uZoUjlpKgHkgaFSYD+r9CfrXjEXsO7w=
github.com/jmoiron/sqlx v1.3.4/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXLBMCQ=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
Expand Down
2 changes: 1 addition & 1 deletion gpkg/describecollectionprovider.go
Expand Up @@ -25,7 +25,7 @@ func (gp *GeoPackageProvider) NewDescribeCollectionProvider(r *http.Request) (co
}
p.contenttype = ct

for _, cn := range gp.GeoPackage.Layers {
for _, cn := range gp.GeoPackage.Collections {
// maybe convert to map, but not thread safe!
if cn.Identifier != collectionId {
continue
Expand Down
2 changes: 1 addition & 1 deletion gpkg/getapiprovider.go
Expand Up @@ -28,7 +28,7 @@ func (gp *GeoPackageProvider) NewGetApiProvider(r *http.Request) (codegen.Provid
return p, err
}

p.data = gp.Api
p.data = gp.ApiProcessed
return p, nil
}

Expand Down
4 changes: 2 additions & 2 deletions gpkg/getcollectionsprovider.go
Expand Up @@ -29,12 +29,12 @@ func (gp *GeoPackageProvider) NewGetCollectionsProvider(r *http.Request) (codege
hrefBase := fmt.Sprintf("%s%s", gp.Config.Service.Url, path) // /collections
links, _ := provider.CreateLinks("collections", p.String(), hrefBase, "self", ct)
csInfo.Links = append(csInfo.Links, links...)
for _, cn := range gp.GeoPackage.Layers {
for _, cn := range gp.GeoPackage.Collections {
clinks, _ := provider.CreateLinks("collection "+cn.Identifier, p.String(), fmt.Sprintf("%s/%s", hrefBase, cn.Identifier), "item", ct)
csInfo.Links = append(csInfo.Links, clinks...)
}

for _, cn := range gp.GeoPackage.Layers {
for _, cn := range gp.GeoPackage.Collections {

crss := make([]string, 0)
for _, v := range gp.CrsMap {
Expand Down
4 changes: 2 additions & 2 deletions gpkg/getfeatureprovider.go
Expand Up @@ -20,7 +20,7 @@ func (gp *GeoPackageProvider) NewGetFeatureProvider(r *http.Request) (codegen.Pr
featureIdParam := featureId
bboxParam := gp.GeoPackage.DefaultBBox

p := &GetFeatureProvider{srsid: fmt.Sprintf("EPSG:%d", gp.GeoPackage.SrsId)}
p := &GetFeatureProvider{srsid: fmt.Sprintf("EPSG:%d", gp.GeoPackage.Srid)}

path := r.URL.Path

Expand All @@ -31,7 +31,7 @@ func (gp *GeoPackageProvider) NewGetFeatureProvider(r *http.Request) (codegen.Pr

p.contenttype = ct

for _, cn := range gp.GeoPackage.Layers {
for _, cn := range gp.GeoPackage.Collections {
// maybe convert to map, but not thread safe!
if cn.Identifier != collectionId {
continue
Expand Down
8 changes: 4 additions & 4 deletions gpkg/getfeaturesprovider.go
Expand Up @@ -26,7 +26,7 @@ func (gp *GeoPackageProvider) NewGetFeaturesProvider(r *http.Request) (codegen.P
}

path := r.URL.Path // collections/{{collectionId}}/items
p := &GetFeaturesProvider{srsid: fmt.Sprintf("EPSG:%d", gp.GeoPackage.SrsId)}
p := &GetFeaturesProvider{srsid: fmt.Sprintf("EPSG:%d", gp.GeoPackage.Srid)}

ct, err := provider.GetContentType(r, p.String())
if err != nil {
Expand All @@ -35,7 +35,7 @@ func (gp *GeoPackageProvider) NewGetFeaturesProvider(r *http.Request) (codegen.P

p.contenttype = ct

for _, cn := range gp.GeoPackage.Layers {
for _, cn := range gp.GeoPackage.Collections {
// maybe convert to map, but not thread safe!
if cn.Identifier != collectionId {
continue
Expand Down Expand Up @@ -82,9 +82,9 @@ func (gp *GeoPackageProvider) NewGetFeaturesProvider(r *http.Request) (codegen.P

fcGeoJSON.Links = links

crsUri, ok := gp.CrsMap[fmt.Sprintf("%d", cn.SrsId)]
crsUri, ok := gp.CrsMap[fmt.Sprintf("%d", cn.Srid)]
if !ok {
log.Printf("SRS ID: %s, not found", fmt.Sprintf("%d", cn.SrsId))
log.Printf("SRS ID: %s, not found", fmt.Sprintf("%d", cn.Srid))
crsUri = ""
}
fcGeoJSON.Crs = crsUri
Expand Down
73 changes: 36 additions & 37 deletions gpkg/gpkg.go
Expand Up @@ -6,7 +6,7 @@ import (
"errors"
"fmt"
"log"
pc "oaf-server/provider"
"oaf-server/provider"
"os"
"regexp"
"time"
Expand Down Expand Up @@ -38,9 +38,9 @@ type GeoPackage struct {
UserVersion int64
DB *sqlx.DB
FeatureIdKey string
Layers []GeoPackageLayer
Collections []provider.Collection
DefaultBBox [4]float64
SrsId int64
Srid int64
}

func NewGeoPackage(filepath string, featureIdKey string) (GeoPackage, error) {
Expand Down Expand Up @@ -69,37 +69,25 @@ func NewGeoPackage(filepath string, featureIdKey string) (GeoPackage, error) {
applicationId, _ := gpkg.GetApplicationID(ctx, db)
version, _ := gpkg.GetVersion(ctx, db)

layers, _ := gpkg.GetLayers(ctx, db)
collections, _ := gpkg.GetCollections(ctx, db)

log.Printf("| GEOPACKAGE DETAILS \n")
log.Printf("|\n")
log.Printf("| FILE: %s, APPLICATION: %s, VERSION: %d", filepath, applicationId, version)
log.Printf("|\n")
log.Printf("| NUMBER OF LAYERS: %d", len(layers))
log.Printf("| NUMBER OF LAYERS: %d", len(collections))
log.Printf("|\n")
// determine query bbox
for i, layer := range layers {
log.Printf("| LAYER: %d. ID: %s, SRS_ID: %d, TABLE: %s PK: %s, FEATURES : %v\n", i+1, layer.Identifier, layer.SrsId, layer.Features[0], layer.Features[1], layer.Features[2:])
for i, collection := range collections {
log.Printf("| LAYER: %d. ID: %s, SRID: %d, TABLE: %s PK: %s, FEATURES : %v\n", i+1, collection.Identifier, collection.Srid, collection.Properties[0], collection.Properties[1], collection.Properties[2:])

if i == 0 {
gpkg.DefaultBBox = [4]float64{layer.MinX, layer.MinY, layer.MaxX, layer.MaxY}
gpkg.SrsId = layer.SrsId
}
if layer.MinX < gpkg.DefaultBBox[0] {
gpkg.DefaultBBox[0] = layer.MinX
}
if layer.MinY < gpkg.DefaultBBox[1] {
gpkg.DefaultBBox[1] = layer.MinY
}
if layer.MaxX > gpkg.DefaultBBox[2] {
gpkg.DefaultBBox[2] = layer.MaxX
}
if layer.MaxY > gpkg.DefaultBBox[3] {
gpkg.DefaultBBox[3] = layer.MaxY
gpkg.DefaultBBox = collection.BBox
gpkg.Srid = int64(collection.Srid)
}
}
log.Printf("| \n")
log.Printf("| BBOX: [%f,%f,%f,%f], SRS_ID:%d", gpkg.DefaultBBox[0], gpkg.DefaultBBox[1], gpkg.DefaultBBox[2], gpkg.DefaultBBox[3], gpkg.SrsId)
log.Printf("| BBOX: [%f,%f,%f,%f], SRS_ID:%d", gpkg.DefaultBBox[0], gpkg.DefaultBBox[1], gpkg.DefaultBBox[2], gpkg.DefaultBBox[3], gpkg.Srid)

return *gpkg, nil
}
Expand All @@ -108,10 +96,10 @@ func (gpkg *GeoPackage) Close() error {
return gpkg.DB.Close()
}

func (gpkg *GeoPackage) GetLayers(ctx context.Context, db *sqlx.DB) (result []GeoPackageLayer, err error) {
func (gpkg *GeoPackage) GetCollections(ctx context.Context, db *sqlx.DB) (result []provider.Collection, err error) {

if gpkg.Layers != nil {
result = gpkg.Layers
if gpkg.Collections != nil {
result = gpkg.Collections
err = nil
return
}
Expand All @@ -132,7 +120,7 @@ func (gpkg *GeoPackage) GetLayers(ctx context.Context, db *sqlx.DB) (result []Ge
}
defer rowsClose(query, rows)

gpkg.Layers = make([]GeoPackageLayer, 0)
gpkg.Collections = make([]provider.Collection, 0)

for rows.Next() {
if err = ctx.Err(); err != nil {
Expand All @@ -150,15 +138,26 @@ func (gpkg *GeoPackage) GetLayers(ctx context.Context, db *sqlx.DB) (result []Ge
row.Features = append(row.Features, match[1])
}

gpkg.Layers = append(gpkg.Layers, row)
collection := provider.Collection{
Tablename: row.TableName,
Identifier: row.Identifier,
Description: row.Description,
Columns: &provider.Columns{Geometry: row.ColumnName},
Geometrytype: row.GeometryType,
BBox: [4]float64{row.MinX, row.MinY, row.MaxX, row.MaxY},
Srid: int(row.SrsId),
Properties: row.Features,
}

gpkg.Collections = append(gpkg.Collections, collection)
}

result = gpkg.Layers
result = gpkg.Collections

return
}

func (gpkg GeoPackage) GetFeatures(ctx context.Context, db *sqlx.DB, layer GeoPackageLayer, collectionId string, offset uint64, limit uint64, featureId interface{}, bbox [4]float64) (result *FeatureCollectionGeoJSON, err error) {
func (gpkg GeoPackage) GetFeatures(ctx context.Context, db *sqlx.DB, collection provider.Collection, collectionId string, offset uint64, limit uint64, featureId interface{}, bbox [4]float64) (result *FeatureCollectionGeoJSON, err error) {
// Features bit of a hack // layer.Features => tablename, PK, ...FEATURES, assuming create table in sql statement first is PK
result = &FeatureCollectionGeoJSON{}
if len(bbox) > 4 {
Expand All @@ -169,16 +168,16 @@ func (gpkg GeoPackage) GetFeatures(ctx context.Context, db *sqlx.DB, layer GeoPa
var featureIdKey string

if gpkg.FeatureIdKey == "" {
featureIdKey = layer.Features[1]
featureIdKey = collection.Properties[1]
} else {
featureIdKey = gpkg.FeatureIdKey
}

rtreeTablenName := fmt.Sprintf("rtree_%s_%s", layer.TableName, layer.ColumnName)
selectClause := fmt.Sprintf("l.`%s`, l.`%s`", featureIdKey, layer.ColumnName)
rtreeTablenName := fmt.Sprintf("rtree_%s_%s", collection.Tablename, collection.Columns.Geometry)
selectClause := fmt.Sprintf("l.`%s`, l.`%s`", featureIdKey, collection.Columns.Geometry)

for _, tf := range layer.Features[1:] { // [2:] skip tablename and PK
if tf == layer.ColumnName || tf == featureIdKey {
for _, tf := range collection.Properties[1:] { // [2:] skip tablename and PK
if tf == collection.Columns.Geometry || tf == featureIdKey {
continue
}
selectClause += fmt.Sprintf(", l.`%v`", tf)
Expand All @@ -191,7 +190,7 @@ func (gpkg GeoPackage) GetFeatures(ctx context.Context, db *sqlx.DB, layer GeoPa
}

query := fmt.Sprintf("SELECT %s FROM `%s` l INNER JOIN `%s` g ON g.`id` = l.`fid` WHERE %s minx <= $2 AND maxx >= $3 AND miny <= $4 AND maxy >= $5 ORDER BY l.`%s` LIMIT $6 OFFSET $7;",
selectClause, layer.TableName, rtreeTablenName, additionalWhere, featureIdKey)
selectClause, collection.Tablename, rtreeTablenName, additionalWhere, featureIdKey)

var rows *sqlx.Rows
if featureId != nil {
Expand Down Expand Up @@ -249,7 +248,7 @@ func (gpkg GeoPackage) GetFeatures(ctx context.Context, db *sqlx.DB, layer GeoPa

switch colName {
case featureIdKey:
ID, err := pc.ConvertFeatureID(vals[i])
ID, err := provider.ConvertFeatureID(vals[i])
if err != nil {
return result, err
}
Expand All @@ -260,7 +259,7 @@ func (gpkg GeoPackage) GetFeatures(ctx context.Context, db *sqlx.DB, layer GeoPa
feature.ID = identifier
}

case layer.ColumnName:
case collection.Columns.Geometry:

geomData, ok := vals[i].([]byte)
if !ok {
Expand Down
24 changes: 23 additions & 1 deletion gpkg/initprovider.go
@@ -1,17 +1,20 @@
package gpkg

import (
"log"
"oaf-server/provider"

"github.com/getkin/kin-openapi/openapi3"
"github.com/imdario/mergo"
)

type GeoPackageProvider struct {
CommonProvider provider.CommonProvider
GeoPackage GeoPackage
CrsMap map[string]string
Api *openapi3.T
Config provider.Config
Api *openapi3.T
ApiProcessed *openapi3.T
}

func NewGeopackageWithCommonProvider(api *openapi3.T, commonProvider provider.CommonProvider, crsMap map[string]string, config provider.Config) *GeoPackageProvider {
Expand All @@ -25,5 +28,24 @@ func NewGeopackageWithCommonProvider(api *openapi3.T, commonProvider provider.Co

func (gp *GeoPackageProvider) Init() (err error) {
gp.GeoPackage, err = NewGeoPackage(gp.Config.Datasource.Geopackage.File, gp.Config.Datasource.Geopackage.Fid)

collections := gp.Config.Datasource.Collections

if len(collections) != 0 {
for _, gpkgc := range gp.GeoPackage.Collections {
for _, configc := range collections {
if gpkgc.Identifier == configc.Identifier {
err = mergo.Merge(&configc, gpkgc)
if err != nil {
log.Fatalln(err)
}
}
}
}
} else {
collections = gp.GeoPackage.Collections
}

gp.ApiProcessed = provider.CreateProvidesSpecificParameters(gp.Api, &collections)
return
}

0 comments on commit a9c79db

Please sign in to comment.