Add new relation_members table type

master
Oliver Tonnhofer 2016-01-04 11:19:28 +01:00
parent 1aff01cc9e
commit 423390ea71
16 changed files with 626 additions and 52 deletions

View File

@ -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

View File

@ -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 {

View File

@ -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 {

View File

@ -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)

View File

@ -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 {

View File

@ -182,6 +182,8 @@ func Import() {
relations,
db, progress,
tagmapping.PolygonMatcher(),
tagmapping.RelationMatcher(),
tagmapping.RelationMemberMatcher(),
config.BaseOptions.Srid)
relWriter.SetLimiter(geometryLimiter)
relWriter.EnableConcurrent()

View File

@ -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) {

View File

@ -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

View File

@ -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)
}

View File

@ -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))

3
test/route_relation.osc Normal file
View File

@ -0,0 +1,3 @@
<?xml version='1.0' encoding='UTF-8'?>
<osmChange version="0.6" generator="Osmosis 0.41">
</osmChange>

113
test/route_relation.osm Normal file
View File

@ -0,0 +1,113 @@
<?xml version="1.0" encoding="UTF-8"?>
<osm version="0.6" generator="CGImap 0.4.0 (2097 thorn-01.openstreetmap.org)" copyright="OpenStreetMap and contributors" attribution="http://www.openstreetmap.org/copyright" license="http://opendatacommons.org/licenses/odbl/1-0/">
<node id="100101" version="1" timestamp="2015-12-31T23:59:99Z" lat="53.0" lon="8.200"/>
<node id="100102" version="1" timestamp="2015-12-31T23:59:99Z" lat="53.0" lon="8.201"/>
<node id="100103" version="1" timestamp="2015-12-31T23:59:99Z" lat="53.0" lon="8.202"/>
<node id="100104" version="1" timestamp="2015-12-31T23:59:99Z" lat="53.0" lon="8.203"/>
<node id="100201" version="1" timestamp="2015-12-31T23:59:99Z" lat="53.0001" lon="8.2000"/>
<node id="100211" version="1" timestamp="2015-12-31T23:59:99Z" lat="53.0001" lon="8.2001"/>
<node id="100202" version="1" timestamp="2015-12-31T23:59:99Z" lat="53.0001" lon="8.2010"/>
<node id="100212" version="1" timestamp="2015-12-31T23:59:99Z" lat="53.0001" lon="8.2011"/>
<node id="100203" version="1" timestamp="2015-12-31T23:59:99Z" lat="53.0001" lon="8.2020"/>
<node id="100213" version="1" timestamp="2015-12-31T23:59:99Z" lat="53.0001" lon="8.2021"/>
<node id="100204" version="1" timestamp="2015-12-31T23:59:99Z" lat="53.0001" lon="8.2030"/>
<node id="100214" version="1" timestamp="2015-12-31T23:59:99Z" lat="53.0001" lon="8.2031"/>
<way id="100501" version="1" timestamp="2015-12-31T23:59:99Z">
<nd ref="100101"/>
<nd ref="100102"/>
<tag k="highway" v="residential"/>
<tag k="name" v="Residential Street"/>
</way>
<way id="100502" version="1" timestamp="2015-12-31T23:59:99Z">
<nd ref="100102"/>
<nd ref="100103"/>
<tag k="highway" v="residential"/>
<tag k="name" v="Residential Street"/>
</way>
<way id="100503" version="1" timestamp="2015-12-31T23:59:99Z">
<nd ref="100103"/>
<nd ref="100104"/>
<!-- untagged -->
</way>
<way id="100511" version="1" timestamp="2015-12-31T23:59:99Z">
<nd ref="100201"/>
<nd ref="100211"/>
</way>
<way id="100512" version="1" timestamp="2015-12-31T23:59:99Z">
<nd ref="100202"/>
<nd ref="100212"/>
</way>
<way id="100513" version="1" timestamp="2015-12-31T23:59:99Z">
<nd ref="100203"/>
<nd ref="100213"/>
</way>
<way id="100514" version="1" timestamp="2015-12-31T23:59:99Z">
<nd ref="100204"/>
<nd ref="100214"/>
</way>
<relation id="100901" version="23" timestamp="2015-06-02T04:13:19Z">
<member type="node" ref="100101" role="stop_entry_only"/>
<member type="way" ref="100511" role="platform_entry_only"/>
<member type="node" ref="100102" role="stop"/>
<member type="way" ref="100512" role="platform"/>
<member type="node" ref="100103" role="stop"/>
<member type="way" ref="100513" role="platform"/>
<member type="node" ref="100104" role="stop_exit_only"/>
<member type="way" ref="100514" role="platform_exit_only"/>
<member type="way" ref="100501" role=""/>
<member type="way" ref="100502" role=""/>
<member type="way" ref="100503" role=""/>
<tag k="colour" v="#F5A9E1"/>
<tag k="from" v="A"/>
<tag k="name" v="Bus 301: A =&gt; B"/>
<tag k="network" v="ABC"/>
<tag k="ref" v="301"/>
<tag k="route" v="bus"/>
<tag k="to" v="B"/>
<tag k="type" v="route"/>
</relation>
<relation id="100902" version="23" timestamp="2015-06-02T04:13:19Z">
<member type="node" ref="100104" role="stop_entry_only"/>
<member type="way" ref="100514" role="platform_entry_only"/>
<member type="node" ref="100103" role="stop"/>
<member type="way" ref="100513" role="platform"/>
<member type="node" ref="100102" role="stop"/>
<member type="way" ref="100512" role="platform"/>
<member type="node" ref="100101" role="stop_exit_only"/>
<member type="way" ref="100511" role="platform_exit_only"/>
<member type="way" ref="100503" role=""/>
<member type="way" ref="100502" role=""/>
<member type="way" ref="100501" role=""/>
<tag k="colour" v="#F5A9E1"/>
<tag k="from" v="B"/>
<tag k="name" v="Bus 301: B =&gt; A"/>
<tag k="network" v="ABC"/>
<tag k="ref" v="301"/>
<tag k="route" v="bus"/>
<tag k="to" v="A"/>
<tag k="type" v="route"/>
</relation>
<relation id="100903" version="23" timestamp="2015-06-02T04:13:19Z">
<member type="relation" ref="100901" role=""/>
<member type="relation" ref="100902" role=""/>
<tag k="colour" v="#F5A9E1"/>
<tag k="name" v="Bus 301"/>
<tag k="network" v="ABC"/>
<tag k="ref" v="301"/>
<tag k="route_master" v="bus"/>
<tag k="type" v="route_master"/>
</relation>
</osm>

View File

@ -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"
]
}
}
}
}

View File

@ -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")
}

View File

@ -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)

View File

@ -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