diff --git a/database/database.go b/database/database.go
index c265fbc..50a8fdf 100644
--- a/database/database.go
+++ b/database/database.go
@@ -36,6 +36,7 @@ type Inserter interface {
InsertPoint(element.OSMElem, geom.Geometry, []mapping.Match) error
InsertLineString(element.OSMElem, geom.Geometry, []mapping.Match) error
InsertPolygon(element.OSMElem, geom.Geometry, []mapping.Match) error
+ InsertRelationMember(element.Relation, element.Member, geom.Geometry, []mapping.Match) error
}
type Deployer interface {
@@ -103,6 +104,9 @@ func (n *nullDb) Abort() error
func (n *nullDb) InsertPoint(element.OSMElem, geom.Geometry, []mapping.Match) error { return nil }
func (n *nullDb) InsertLineString(element.OSMElem, geom.Geometry, []mapping.Match) error { return nil }
func (n *nullDb) InsertPolygon(element.OSMElem, geom.Geometry, []mapping.Match) error { return nil }
+func (n *nullDb) InsertRelationMember(element.Relation, element.Member, geom.Geometry, []mapping.Match) error {
+ return nil
+}
func newNullDb(conf Config, m *mapping.Mapping) (DB, error) {
return &nullDb{}, nil
diff --git a/database/postgis/postgis.go b/database/postgis/postgis.go
index 3fec077..8c710ec 100644
--- a/database/postgis/postgis.go
+++ b/database/postgis/postgis.go
@@ -58,7 +58,7 @@ func createTable(tx *sql.Tx, spec TableSpec) error {
}
func addGeometryColumn(tx *sql.Tx, tableName string, spec TableSpec) error {
- colName := "geometry"
+ colName := ""
for _, col := range spec.Columns {
if col.Type.Name() == "GEOMETRY" {
colName = col.Name
@@ -66,6 +66,10 @@ func addGeometryColumn(tx *sql.Tx, tableName string, spec TableSpec) error {
}
}
+ if colName == "" {
+ return nil
+ }
+
geomType := strings.ToUpper(spec.GeometryType)
if geomType == "POLYGON" {
geomType = "GEOMETRY" // for multipolygon support
@@ -480,6 +484,16 @@ func (pg *PostGIS) InsertPolygon(elem element.OSMElem, geom geom.Geometry, match
return nil
}
+func (pg *PostGIS) InsertRelationMember(rel element.Relation, m element.Member, geom geom.Geometry, matches []mapping.Match) error {
+ for _, match := range matches {
+ row := match.MemberRow(&rel, &m, &geom)
+ if err := pg.txRouter.Insert(match.Table.Name, row); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
func (pg *PostGIS) Delete(id int64, matches interface{}) error {
if matches, ok := matches.([]mapping.Match); ok {
for _, match := range matches {
diff --git a/database/postgis/spec.go b/database/postgis/spec.go
index e6fa7f0..8c50428 100644
--- a/database/postgis/spec.go
+++ b/database/postgis/spec.go
@@ -125,11 +125,19 @@ func (spec *TableSpec) DeleteSQL() string {
}
func NewTableSpec(pg *PostGIS, t *mapping.Table) *TableSpec {
+ var geomType string
+ switch t.Type {
+ case mapping.RelationMemberTable:
+ geomType = "geometry"
+ default:
+ geomType = string(t.Type)
+ }
+
spec := TableSpec{
Name: t.Name,
FullName: pg.Prefix + t.Name,
Schema: pg.Config.ImportSchema,
- GeometryType: string(t.Type),
+ GeometryType: geomType,
Srid: pg.Config.Srid,
}
for _, field := range t.Fields {
diff --git a/diff/process.go b/diff/process.go
index ca378fa..c15da9a 100644
--- a/diff/process.go
+++ b/diff/process.go
@@ -149,6 +149,8 @@ func Update(oscFile string, geometryLimiter *limit.Limiter, expireor expire.Expi
relations,
db, progress,
tagmapping.PolygonMatcher(),
+ tagmapping.RelationMatcher(),
+ tagmapping.RelationMemberMatcher(),
config.BaseOptions.Srid)
relWriter.SetLimiter(geometryLimiter)
relWriter.SetExpireor(expireor)
diff --git a/element/element.go b/element/element.go
index 0bc5fdf..c98f586 100644
--- a/element/element.go
+++ b/element/element.go
@@ -72,6 +72,8 @@ type Member struct {
Type MemberType `json:"type"`
Role string `json:"role"`
Way *Way `json:"-"`
+ Node *Node `json:"-"`
+ Elem *OSMElem `json:"-"`
}
type Relation struct {
diff --git a/import_/import.go b/import_/import.go
index 584e1b5..7138c4f 100644
--- a/import_/import.go
+++ b/import_/import.go
@@ -182,6 +182,8 @@ func Import() {
relations,
db, progress,
tagmapping.PolygonMatcher(),
+ tagmapping.RelationMatcher(),
+ tagmapping.RelationMemberMatcher(),
config.BaseOptions.Srid)
relWriter.SetLimiter(geometryLimiter)
relWriter.EnableConcurrent()
diff --git a/mapping/config.go b/mapping/config.go
index 78de91d..430510c 100644
--- a/mapping/config.go
+++ b/mapping/config.go
@@ -11,11 +11,12 @@ import (
)
type Field struct {
- Name string `yaml:"name"`
- Key Key `yaml:"key"`
- Keys []Key `yaml:"keys"`
- Type string `yaml:"type"`
- Args map[string]interface{} `yaml:"args"`
+ Name string `yaml:"name"`
+ Key Key `yaml:"key"`
+ Keys []Key `yaml:"keys"`
+ Type string `yaml:"type"`
+ Args map[string]interface{} `yaml:"args"`
+ FromMembers bool `yaml:"from_members"`
}
type Table struct {
@@ -133,6 +134,10 @@ func (tt *TableType) UnmarshalJSON(data []byte) error {
*tt = PolygonTable
case `"geometry"`:
*tt = GeometryTable
+ case `"relation"`:
+ *tt = RelationTable
+ case `"relation_member"`:
+ *tt = RelationMemberTable
default:
return errors.New("unknown type " + string(data))
}
@@ -140,10 +145,12 @@ func (tt *TableType) UnmarshalJSON(data []byte) error {
}
const (
- PolygonTable TableType = "polygon"
- LineStringTable TableType = "linestring"
- PointTable TableType = "point"
- GeometryTable TableType = "geometry"
+ PolygonTable TableType = "polygon"
+ LineStringTable TableType = "linestring"
+ PointTable TableType = "point"
+ GeometryTable TableType = "geometry"
+ RelationTable TableType = "relation"
+ RelationMemberTable TableType = "relation_member"
)
func NewMapping(filename string) (*Mapping, error) {
diff --git a/mapping/fields.go b/mapping/fields.go
index c899ed0..15a7900 100644
--- a/mapping/fields.go
+++ b/mapping/fields.go
@@ -17,26 +17,31 @@ var AvailableFieldTypes map[string]FieldType
func init() {
AvailableFieldTypes = map[string]FieldType{
- "bool": {"bool", "bool", Bool, nil},
- "boolint": {"boolint", "int8", BoolInt, nil},
- "id": {"id", "int64", Id, nil},
- "string": {"string", "string", String, nil},
- "direction": {"direction", "int8", Direction, nil},
- "integer": {"integer", "int32", Integer, nil},
- "mapping_key": {"mapping_key", "string", KeyName, nil},
- "mapping_value": {"mapping_value", "string", ValueName, nil},
- "geometry": {"geometry", "geometry", Geometry, nil},
- "validated_geometry": {"validated_geometry", "validated_geometry", Geometry, nil},
- "hstore_tags": {"hstore_tags", "hstore_string", HstoreString, nil},
- "wayzorder": {"wayzorder", "int32", WayZOrder, nil},
- "pseudoarea": {"pseudoarea", "float32", PseudoArea, nil},
- "zorder": {"zorder", "int32", nil, MakeZOrder},
- "enumerate": {"enumerate", "int32", nil, MakeEnumerate},
- "string_suffixreplace": {"string_suffixreplace", "string", nil, MakeSuffixReplace},
+ "bool": {"bool", "bool", Bool, nil, nil, false},
+ "boolint": {"boolint", "int8", BoolInt, nil, nil, false},
+ "id": {"id", "int64", Id, nil, nil, false},
+ "string": {"string", "string", String, nil, nil, false},
+ "direction": {"direction", "int8", Direction, nil, nil, false},
+ "integer": {"integer", "int32", Integer, nil, nil, false},
+ "mapping_key": {"mapping_key", "string", KeyName, nil, nil, false},
+ "mapping_value": {"mapping_value", "string", ValueName, nil, nil, false},
+ "relation_member_id": {"relation_member_id", "int64", nil, nil, RelationMemberID, true},
+ "relation_member_role": {"relation_member_role", "string", nil, nil, RelationMemberRole, true},
+ "relation_member_type": {"relation_member_type", "int8", nil, nil, RelationMemberType, true},
+ "relation_member_index": {"relation_member_index", "int32", nil, nil, RelationMemberIndex, true},
+ "geometry": {"geometry", "geometry", Geometry, nil, nil, false},
+ "validated_geometry": {"validated_geometry", "validated_geometry", Geometry, nil, nil, false},
+ "hstore_tags": {"hstore_tags", "hstore_string", HstoreString, nil, nil, false},
+ "wayzorder": {"wayzorder", "int32", WayZOrder, nil, nil, false},
+ "pseudoarea": {"pseudoarea", "float32", PseudoArea, nil, nil, false},
+ "zorder": {"zorder", "int32", nil, MakeZOrder, nil, false},
+ "enumerate": {"enumerate", "int32", nil, MakeEnumerate, nil, false},
+ "string_suffixreplace": {"string_suffixreplace", "string", nil, MakeSuffixReplace, nil, false},
}
}
type MakeValue func(string, *element.OSMElem, *geom.Geometry, Match) interface{}
+type MakeMemberValue func(*element.Relation, *element.Member, Match) interface{}
type MakeMakeValue func(string, FieldType, Field) (MakeValue, error)
@@ -55,6 +60,22 @@ func (f *FieldSpec) Value(elem *element.OSMElem, geom *geom.Geometry, match Matc
return nil
}
+func (f *FieldSpec) MemberValue(rel *element.Relation, member *element.Member, geom *geom.Geometry, match Match) interface{} {
+ if f.Type.Func != nil {
+ if f.Type.FromMembers {
+ if member.Elem == nil {
+ return nil
+ }
+ return f.Type.Func(member.Elem.Tags[string(f.Key)], member.Elem, geom, match)
+ }
+ return f.Type.Func(rel.Tags[string(f.Key)], &rel.OSMElem, geom, match)
+ }
+ if f.Type.MemberFunc != nil {
+ return f.Type.MemberFunc(rel, member, match)
+ }
+ return nil
+}
+
type TableFields struct {
fields []FieldSpec
}
@@ -67,6 +88,14 @@ func (t *TableFields) MakeRow(elem *element.OSMElem, geom *geom.Geometry, match
return row
}
+func (t *TableFields) MakeMemberRow(rel *element.Relation, member *element.Member, geom *geom.Geometry, match Match) []interface{} {
+ var row []interface{}
+ for _, field := range t.fields {
+ row = append(row, field.MemberValue(rel, member, geom, match))
+ }
+ return row
+}
+
func (field *Field) FieldType() *FieldType {
if fieldType, ok := AvailableFieldTypes[field.Type]; ok {
if fieldType.MakeFunc != nil {
@@ -75,8 +104,9 @@ func (field *Field) FieldType() *FieldType {
log.Print(err)
return nil
}
- fieldType = FieldType{fieldType.Name, fieldType.GoType, makeValue, nil}
+ fieldType = FieldType{fieldType.Name, fieldType.GoType, makeValue, nil, nil, fieldType.FromMembers}
}
+ fieldType.FromMembers = field.FromMembers
return &fieldType
}
return nil
@@ -101,10 +131,12 @@ func (t *Table) TableFields() *TableFields {
}
type FieldType struct {
- Name string
- GoType string
- Func MakeValue
- MakeFunc MakeMakeValue
+ Name string
+ GoType string
+ Func MakeValue
+ MakeFunc MakeMakeValue
+ MemberFunc MakeMemberValue
+ FromMembers bool
}
func Bool(val string, elem *element.OSMElem, geom *geom.Geometry, match Match) interface{} {
@@ -145,6 +177,27 @@ func ValueName(val string, elem *element.OSMElem, geom *geom.Geometry, match Mat
return match.Value
}
+func RelationMemberType(rel *element.Relation, member *element.Member, match Match) interface{} {
+ return member.Type
+}
+
+func RelationMemberRole(rel *element.Relation, member *element.Member, match Match) interface{} {
+ return member.Role
+}
+
+func RelationMemberID(rel *element.Relation, member *element.Member, match Match) interface{} {
+ return member.Id
+}
+
+func RelationMemberIndex(rel *element.Relation, member *element.Member, match Match) interface{} {
+ for i := range rel.Members {
+ if rel.Members[i].Id == member.Id {
+ return i
+ }
+ }
+ return -1
+}
+
func Direction(val string, elem *element.OSMElem, geom *geom.Geometry, match Match) interface{} {
if val == "1" || val == "yes" || val == "true" {
return 1
diff --git a/mapping/matcher.go b/mapping/matcher.go
index 38926ae..ffab4ad 100644
--- a/mapping/matcher.go
+++ b/mapping/matcher.go
@@ -1,29 +1,47 @@
package mapping
import (
+ _ "log"
+
"github.com/omniscale/imposm3/element"
"github.com/omniscale/imposm3/geom"
)
func (m *Mapping) PointMatcher() NodeMatcher {
mappings := make(TagTables)
- m.mappings("point", mappings)
+ m.mappings(PointTable, mappings)
filters := m.ElementFilters()
- return &tagMatcher{mappings, m.tables("point"), filters, false}
+ return &tagMatcher{mappings, m.tables(PointTable), filters, false}
}
func (m *Mapping) LineStringMatcher() WayMatcher {
mappings := make(TagTables)
- m.mappings("linestring", mappings)
+ m.mappings(LineStringTable, mappings)
filters := m.ElementFilters()
- return &tagMatcher{mappings, m.tables("linestring"), filters, false}
+ return &tagMatcher{mappings, m.tables(LineStringTable), filters, false}
}
func (m *Mapping) PolygonMatcher() RelWayMatcher {
mappings := make(TagTables)
- m.mappings("polygon", mappings)
+ m.mappings(PolygonTable, mappings)
filters := m.ElementFilters()
- return &tagMatcher{mappings, m.tables("polygon"), filters, true}
+ return &tagMatcher{mappings, m.tables(PolygonTable), filters, true}
+}
+
+func (m *Mapping) RelationMatcher() RelationMatcher {
+ mappings := make(TagTables)
+ m.mappings(RelationTable, mappings)
+ filters := m.ElementFilters()
+ log.Print(mappings)
+ return &tagMatcher{mappings, m.tables(RelationTable), filters, true}
+}
+
+func (m *Mapping) RelationMemberMatcher() RelationMatcher {
+ mappings := make(TagTables)
+ m.mappings(RelationMemberTable, mappings)
+ filters := m.ElementFilters()
+ log.Print(mappings)
+ return &tagMatcher{mappings, m.tables(RelationMemberTable), filters, true}
}
type Match struct {
@@ -61,6 +79,10 @@ func (m *Match) Row(elem *element.OSMElem, geom *geom.Geometry) []interface{} {
return m.tableFields.MakeRow(elem, geom, *m)
}
+func (m *Match) MemberRow(rel *element.Relation, member *element.Member, geom *geom.Geometry) []interface{} {
+ return m.tableFields.MakeMemberRow(rel, member, geom, *m)
+}
+
func (tm *tagMatcher) MatchNode(node *element.Node) []Match {
return tm.match(&node.Tags)
}
diff --git a/test/Makefile b/test/Makefile
index 516e27e..fa6e637 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -1,4 +1,4 @@
-.PHONY: all test clean
+.PHONY: all test clean files
ifdef VERBOSE
TESTOPTS = -v
@@ -16,12 +16,16 @@ OSCGZ_FILES=$(addprefix build/,$(patsubst %.osc,%.osc.gz,$(wildcard *.osc)))
build/%.pbf: %.osm
@mkdir -p build
- osmosis --read-xml $< --sort TypeThenId --write-pbf $@ omitmetadata=true
+ osmosis --read-xml $< --sort type="TypeThenId" --write-pbf $@ omitmetadata=true
build/%.osc.gz: %.osc
@mkdir -p build
gzip --stdout $< > $@
-test: $(PBF_FILES) $(OSCGZ_FILES)
+files: $(PBF_FILES) $(OSCGZ_FILES)
+
+test: files
(cd .. && godep go test ./test $(TESTOPTS))
+route_relation: files
+ (cd .. && godep go test -test.run TestRouteRelation_ ./test $(TESTOPTS))
diff --git a/test/route_relation.osc b/test/route_relation.osc
new file mode 100644
index 0000000..7f21e40
--- /dev/null
+++ b/test/route_relation.osc
@@ -0,0 +1,3 @@
+
+
+
diff --git a/test/route_relation.osm b/test/route_relation.osm
new file mode 100644
index 0000000..b1d5682
--- /dev/null
+++ b/test/route_relation.osm
@@ -0,0 +1,113 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/route_relation_mapping.json b/test/route_relation_mapping.json
new file mode 100644
index 0000000..c81fc92
--- /dev/null
+++ b/test/route_relation_mapping.json
@@ -0,0 +1,128 @@
+{
+ "tags": {
+ "load_all": true,
+ "exclude": [
+ "created_by",
+ "source"
+ ]
+ },
+ "tables": {
+ "route_members": {
+ "fields": [
+ {
+ "type": "id",
+ "name": "osm_id"
+ },
+ {
+ "type": "string",
+ "name": "ref",
+ "key": "ref"
+ },
+ {
+ "type": "relation_member_id",
+ "name": "member"
+ },
+ {
+ "type": "relation_member_index",
+ "name": "index"
+ },
+ {
+ "type": "relation_member_role",
+ "name": "role"
+ },
+ {
+ "type": "relation_member_type",
+ "name": "type"
+ },
+ {
+ "type": "geometry",
+ "name": "geometry"
+ },
+ {
+ "type": "string",
+ "name": "name",
+ "key": "name",
+ "from_members": true
+ }
+ ],
+ "type": "relation_member",
+ "mapping": {
+ "route": [
+ "bus",
+ "tram",
+ "rail"
+ ]
+ }
+ },
+ "routes": {
+ "fields": [
+ {
+ "type": "id",
+ "name": "osm_id"
+ },
+ {
+ "type": "string",
+ "name": "ref",
+ "key": "ref"
+ },
+ {
+ "type": "hstore_tags",
+ "name": "tags"
+ }
+ ],
+ "type": "relation",
+ "mapping": {
+ "route": [
+ "bus",
+ "tram",
+ "rail"
+ ]
+ }
+ },
+ "master_routes": {
+ "fields": [
+ {
+ "type": "id",
+ "name": "osm_id"
+ },
+ {
+ "type": "relation_member_id",
+ "name": "member"
+ },
+ {
+ "type": "relation_member_index",
+ "name": "index"
+ },
+ {
+ "type": "relation_member_role",
+ "name": "role"
+ },
+ {
+ "type": "relation_member_type",
+ "name": "type"
+ },
+ {
+ "type": "geometry",
+ "name": "geometry"
+ },
+ {
+ "type": "string",
+ "name": "subname",
+ "key": "name",
+ "from_members": true
+ },
+ {
+ "type": "string",
+ "name": "name",
+ "key": "name"
+ }
+ ],
+ "type": "relation_member",
+ "mapping": {
+ "route_master": [
+ "bus"
+ ]
+ }
+ }
+ }
+}
diff --git a/test/route_relation_test.go b/test/route_relation_test.go
new file mode 100644
index 0000000..f71c0af
--- /dev/null
+++ b/test/route_relation_test.go
@@ -0,0 +1,53 @@
+package test
+
+import (
+ "database/sql"
+
+ "testing"
+
+ "github.com/omniscale/imposm3/geom/geos"
+)
+
+func TestRouteRelation_Prepare(t *testing.T) {
+ ts.dir = "/tmp/imposm3test"
+ ts.config = importConfig{
+ connection: "postgis://",
+ cacheDir: ts.dir,
+ osmFileName: "build/route_relation.pbf",
+ mappingFileName: "route_relation_mapping.json",
+ }
+ ts.g = geos.NewGeos()
+
+ var err error
+ ts.db, err = sql.Open("postgres", "sslmode=disable")
+ if err != nil {
+ t.Fatal(err)
+ }
+ ts.dropSchemas()
+}
+
+func TestRouteRelation_Import(t *testing.T) {
+ if ts.tableExists(t, dbschemaImport, "osm_routes") != false {
+ t.Fatalf("table osm_routes exists in schema %s", dbschemaImport)
+ }
+ ts.importOsm(t)
+ if ts.tableExists(t, dbschemaImport, "osm_routes") != true {
+ t.Fatalf("table osm_routes does not exists in schema %s", dbschemaImport)
+ }
+}
+
+func TestRouteRelation_Deploy(t *testing.T) {
+ ts.deployOsm(t)
+ if ts.tableExists(t, dbschemaImport, "osm_routes") != false {
+ t.Fatalf("table osm_routes exists in schema %s", dbschemaImport)
+ }
+ if ts.tableExists(t, dbschemaProduction, "osm_routes") != true {
+ t.Fatalf("table osm_routes does not exists in schema %s", dbschemaProduction)
+ }
+}
+
+// #######################################################################
+
+func TestRouteRelation_Update(t *testing.T) {
+ ts.updateOsm(t, "./build/route_relation.osc.gz")
+}
diff --git a/test/route_relation_test.py b/test/route_relation_test.py
new file mode 100644
index 0000000..eb20330
--- /dev/null
+++ b/test/route_relation_test.py
@@ -0,0 +1,83 @@
+import psycopg2
+import psycopg2.extras
+
+import helper as t
+
+psycopg2.extras.register_hstore(psycopg2.connect(**t.db_conf), globally=True)
+
+mapping_file = 'route_relation_mapping.json'
+
+def setup():
+ t.setup()
+
+def teardown():
+ t.teardown()
+
+RELOFFSET = int(-1e17)
+
+#######################################################################
+def test_import():
+ """Import succeeds"""
+ t.drop_schemas()
+ assert not t.table_exists('osm_routes', schema=t.TEST_SCHEMA_IMPORT)
+ t.imposm3_import(t.db_conf, './build/route_relation.pbf', mapping_file)
+ assert t.table_exists('osm_routes', schema=t.TEST_SCHEMA_IMPORT)
+
+def test_deploy():
+ """Deploy succeeds"""
+ assert not t.table_exists('osm_routes', schema=t.TEST_SCHEMA_PRODUCTION)
+ t.imposm3_deploy(t.db_conf, mapping_file)
+ assert t.table_exists('osm_routes', schema=t.TEST_SCHEMA_PRODUCTION)
+ assert not t.table_exists('osm_routes', schema=t.TEST_SCHEMA_IMPORT)
+
+#######################################################################
+
+
+#######################################################################
+
+def test_update():
+ """Diff import applies"""
+ t.imposm3_update(t.db_conf, './build/route_relation.osc.gz', mapping_file)
+
+#######################################################################
+
+
+#######################################################################
+def test_deploy_and_revert_deploy():
+ """Revert deploy succeeds"""
+ assert not t.table_exists('osm_routes', schema=t.TEST_SCHEMA_IMPORT)
+ assert t.table_exists('osm_routes', schema=t.TEST_SCHEMA_PRODUCTION)
+ assert not t.table_exists('osm_routes', schema=t.TEST_SCHEMA_BACKUP)
+
+ # import again to have a new import schema
+ t.imposm3_import(t.db_conf, './build/route_relation.pbf', mapping_file)
+ assert t.table_exists('osm_routes', schema=t.TEST_SCHEMA_IMPORT)
+
+ t.imposm3_deploy(t.db_conf, mapping_file)
+ assert not t.table_exists('osm_routes', schema=t.TEST_SCHEMA_IMPORT)
+ assert t.table_exists('osm_routes', schema=t.TEST_SCHEMA_PRODUCTION)
+ assert t.table_exists('osm_routes', schema=t.TEST_SCHEMA_BACKUP)
+
+ t.imposm3_revert_deploy(t.db_conf, mapping_file)
+ assert t.table_exists('osm_routes', schema=t.TEST_SCHEMA_IMPORT)
+ assert t.table_exists('osm_routes', schema=t.TEST_SCHEMA_PRODUCTION)
+ assert not t.table_exists('osm_routes', schema=t.TEST_SCHEMA_BACKUP)
+
+def test_remove_backup():
+ """Remove backup succeeds"""
+ assert t.table_exists('osm_routes', schema=t.TEST_SCHEMA_IMPORT)
+ assert t.table_exists('osm_routes', schema=t.TEST_SCHEMA_PRODUCTION)
+ assert not t.table_exists('osm_routes', schema=t.TEST_SCHEMA_BACKUP)
+
+ t.imposm3_deploy(t.db_conf, mapping_file)
+
+ assert not t.table_exists('osm_routes', schema=t.TEST_SCHEMA_IMPORT)
+ assert t.table_exists('osm_routes', schema=t.TEST_SCHEMA_PRODUCTION)
+ assert t.table_exists('osm_routes', schema=t.TEST_SCHEMA_BACKUP)
+
+ t.imposm3_remove_backups(t.db_conf, mapping_file)
+
+ assert not t.table_exists('osm_routes', schema=t.TEST_SCHEMA_IMPORT)
+ assert t.table_exists('osm_routes', schema=t.TEST_SCHEMA_PRODUCTION)
+ assert not t.table_exists('osm_routes', schema=t.TEST_SCHEMA_BACKUP)
+
diff --git a/writer/relations.go b/writer/relations.go
index 5fad3b7..8351456 100644
--- a/writer/relations.go
+++ b/writer/relations.go
@@ -9,17 +9,19 @@ import (
"github.com/omniscale/imposm3/element"
"github.com/omniscale/imposm3/expire"
geomp "github.com/omniscale/imposm3/geom"
- "github.com/omniscale/imposm3/geom/geos"
+ geosp "github.com/omniscale/imposm3/geom/geos"
"github.com/omniscale/imposm3/mapping"
"github.com/omniscale/imposm3/stats"
)
type RelationWriter struct {
OsmElemWriter
- singleIdSpace bool
- rel chan *element.Relation
- polygonMatcher mapping.RelWayMatcher
- maxGap float64
+ singleIdSpace bool
+ rel chan *element.Relation
+ polygonMatcher mapping.RelWayMatcher
+ relationMatcher mapping.RelationMatcher
+ relationMemberMatcher mapping.RelationMatcher
+ maxGap float64
}
func NewRelationWriter(
@@ -30,6 +32,8 @@ func NewRelationWriter(
inserter database.Inserter,
progress *stats.Statistics,
matcher mapping.RelWayMatcher,
+ relMatcher mapping.RelationMatcher,
+ relMemberMatcher mapping.RelationMatcher,
srid int,
) *OsmElemWriter {
maxGap := 1e-1 // 0.1m
@@ -45,10 +49,12 @@ func NewRelationWriter(
inserter: inserter,
srid: srid,
},
- singleIdSpace: singleIdSpace,
- polygonMatcher: matcher,
- rel: rel,
- maxGap: maxGap,
+ singleIdSpace: singleIdSpace,
+ polygonMatcher: matcher,
+ relationMatcher: relMatcher,
+ relationMemberMatcher: relMemberMatcher,
+ rel: rel,
+ maxGap: maxGap,
}
rw.OsmElemWriter.writer = &rw
return &rw.OsmElemWriter
@@ -62,7 +68,7 @@ func (rw *RelationWriter) relId(id int64) int64 {
}
func (rw *RelationWriter) loop() {
- geos := geos.NewGeos()
+ geos := geosp.NewGeos()
geos.SetHandleSrid(rw.srid)
defer geos.Finish()
@@ -76,7 +82,7 @@ NextRel:
}
continue NextRel
}
- for _, m := range r.Members {
+ for i, m := range r.Members {
if m.Way == nil {
continue
}
@@ -88,6 +94,76 @@ NextRel:
continue NextRel
}
rw.NodesToSrid(m.Way.Nodes)
+ r.Members[i].Elem = &m.Way.OSMElem
+ }
+
+ relMemberMatches := rw.relationMemberMatcher.MatchRelation(r)
+ if len(relMemberMatches) > 0 {
+ for i, m := range r.Members {
+ if m.Type == element.RELATION {
+ mrel, err := rw.osmCache.Relations.GetRelation(m.Id)
+ if err != nil {
+ if err == cache.NotFound {
+ log.Warn(err)
+ continue NextRel
+ }
+ }
+ r.Members[i].Elem = &mrel.OSMElem
+ } else if m.Type == element.NODE {
+ nd, err := rw.osmCache.Nodes.GetNode(m.Id)
+ if err != nil {
+ if err == cache.NotFound {
+ nd, err = rw.osmCache.Coords.GetCoord(m.Id)
+ if err != nil {
+ if err != cache.NotFound {
+ log.Warn(err)
+ }
+ continue NextRel
+ }
+ } else {
+ log.Warn(err)
+ continue NextRel
+ }
+ }
+ rw.NodeToSrid(nd)
+ r.Members[i].Node = nd
+ r.Members[i].Elem = &nd.OSMElem
+ }
+ }
+
+ for _, m := range r.Members {
+ var g *geosp.Geom
+ var err error
+ if m.Node != nil {
+ g, err = geomp.Point(geos, *m.Node)
+ } else if m.Way != nil {
+ g, err = geomp.LineString(geos, m.Way.Nodes)
+ }
+
+ if err != nil {
+ log.Warn(err)
+ continue
+ }
+
+ var gelem geomp.Geometry
+ if g == nil {
+ g = geos.FromWkt("POLYGON EMPTY")
+ gelem = geomp.Geometry{Geom: g, Wkb: geos.AsEwkbHex(g)}
+ } else {
+ gelem, err = geomp.AsGeomElement(geos, g)
+ if err != nil {
+ log.Warn(err)
+ continue
+ }
+ }
+
+ rw.inserter.InsertRelationMember(*r, m, gelem, relMemberMatches)
+ }
+ }
+
+ relMatches := rw.relationMatcher.MatchRelation(r)
+ if len(relMatches) > 0 {
+ rw.inserter.InsertPolygon(r.OSMElem, geomp.Geometry{}, relMatches)
}
// BuildRelation updates r.Members but we need all of them