Skip to content

Commit

Permalink
feat(oaf): Add support to return feature properties in a specific ord…
Browse files Browse the repository at this point in the history
…er + take relations into account.
  • Loading branch information
rkettelerij committed Sep 20, 2024
1 parent 66c2ea1 commit a0f274a
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 15 deletions.
7 changes: 4 additions & 3 deletions internal/ogc/features/domain/mapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,15 @@ func MapRowsToFeatures(rows *sqlx.Rows, fidColumn string, externalFidColumn stri
return result, nil, err
}

orderProps := propConfig != nil && propConfig.PropertiesInSpecificOrder
propertiesOrder := propConfig != nil && propConfig.PropertiesInSpecificOrder
firstRow := true
var prevNextID *PrevNextFID
for rows.Next() {
var values []any
if values, err = rows.SliceScan(); err != nil {
return result, nil, err
}
feature := &Feature{Properties: NewFeatureProperties(orderProps)}
feature := &Feature{Properties: NewFeatureProperties(propertiesOrder)}
np, err := mapColumnsToFeature(firstRow, feature, columns, values, fidColumn, externalFidColumn,
geomColumn, mapGeom, mapRel)
if err != nil {
Expand Down Expand Up @@ -173,7 +173,8 @@ func mapExternalFid(columns []string, values []any, externalFidColumn string, fe
// it as a relation to another feature.
newColumnName, newColumnValue := mapRel(columnName, columnValue, externalFidColumn)
if newColumnName != "" {
feature.Properties.Set(newColumnName, newColumnValue)
columnNameWithoutExternalFID := strings.ReplaceAll(columnName, externalFidColumn, "")
feature.Properties.SetRelation(newColumnName, newColumnValue, columnNameWithoutExternalFID)
feature.Properties.Delete(columnName)
}
}
Expand Down
47 changes: 35 additions & 12 deletions internal/ogc/features/domain/props.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@ package domain

import (
"slices"
"strings"

"github.com/PDOK/gokoala/internal/engine/util"
perfjson "github.com/goccy/go-json"
orderedmap "github.com/wk8/go-ordered-map/v2"
)

// FeatureProperties the properties of a GeoJSON Feature
// Either unordered (= default, and has the best performance) or in a specific order when configured as such.
// FeatureProperties the properties of a GeoJSON Feature. Properties are either unordered
// (default, and has the best performance!) or ordered in a specific way as described in the config.
type FeatureProperties struct {
unordered map[string]any
ordered orderedmap.OrderedMap[string, any]
Expand All @@ -34,20 +35,11 @@ func NewFeaturePropertiesWithData(order bool, data map[string]any) FeatureProper
func (p *FeatureProperties) MarshalJSON() ([]byte, error) {
if p.unordered != nil {
// properties are allowed to contain anything, including for example XML/GML.
b, e := perfjson.MarshalWithOption(p.unordered, perfjson.DisableHTMLEscape())
return b, e
return perfjson.MarshalWithOption(p.unordered, perfjson.DisableHTMLEscape())
}
return p.ordered.MarshalJSON()
}

func (p *FeatureProperties) Set(key string, value any) {
if p.unordered != nil {
p.unordered[key] = value
} else {
p.ordered.Set(key, value)
}
}

func (p *FeatureProperties) Value(key string) any {
if p.unordered != nil {
return p.unordered[key]
Expand All @@ -63,6 +55,37 @@ func (p *FeatureProperties) Delete(key string) {
}
}

func (p *FeatureProperties) Set(key string, value any) {
if p.unordered != nil {
p.unordered[key] = value
} else {
p.ordered.Set(key, value)
}
}

func (p *FeatureProperties) SetRelation(key string, value any, existingKeyPrefix string) {
p.Set(key, value)
p.moveKeyBeforePrefix(key, existingKeyPrefix)
}

// moveKeyBeforePrefix best-effort algorithm to place the feature relation BEFORE any similarly named keys.
// For example, places "building.href" before "building_fk" or "building_fid".
func (p *FeatureProperties) moveKeyBeforePrefix(key string, keyPrefix string) {
if p.unordered != nil {
return
}
var existingKey string
for pair := p.ordered.Oldest(); pair != nil; pair = pair.Next() {
if strings.HasPrefix(pair.Key, keyPrefix) {
existingKey = pair.Key
break
}
}
if existingKey != "" {
_ = p.ordered.MoveBefore(key, existingKey)
}
}

// Keys of the Feature properties.
//
// Note: In the future we might replace this with Go 1.23 iterators (range-over-func) however at the moment this
Expand Down

0 comments on commit a0f274a

Please sign in to comment.