forked from MapComplete/MapComplete
		
	Correctly handle non-working optional match groups in generate build_db script
This commit is contained in:
		
							parent
							
								
									760276922d
								
							
						
					
					
						commit
						b37ea885a5
					
				
					 1 changed files with 61 additions and 35 deletions
				
			
		| 
						 | 
					@ -10,28 +10,27 @@ import { AllKnownLayouts } from "../../src/Customizations/AllKnownLayouts"
 | 
				
			||||||
import { OsmObject } from "../../src/Logic/Osm/OsmObject"
 | 
					import { OsmObject } from "../../src/Logic/Osm/OsmObject"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class LuaSnippets {
 | 
					class LuaSnippets {
 | 
				
			||||||
 | 
					 | 
				
			||||||
    public static helpers = [
 | 
					    public static helpers = [
 | 
				
			||||||
        "function countTbl(tbl)\n" +
 | 
					        "function countTbl(tbl)\n" +
 | 
				
			||||||
        "  local c = 0\n" +
 | 
					            "  local c = 0\n" +
 | 
				
			||||||
        "  for n in pairs(tbl) do \n" +
 | 
					            "  for n in pairs(tbl) do \n" +
 | 
				
			||||||
        "    c = c + 1 \n" +
 | 
					            "    c = c + 1 \n" +
 | 
				
			||||||
        "  end\n" +
 | 
					            "  end\n" +
 | 
				
			||||||
        "  return c\n" +
 | 
					            "  return c\n" +
 | 
				
			||||||
        "end",
 | 
					            "end",
 | 
				
			||||||
    ].join("\n")
 | 
					    ].join("\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static isPolygonFeature(): { blacklist: TagsFilter, whitelisted: TagsFilter } {
 | 
					    public static isPolygonFeature(): { blacklist: TagsFilter; whitelisted: TagsFilter } {
 | 
				
			||||||
        const dict = OsmObject.polygonFeatures
 | 
					        const dict = OsmObject.polygonFeatures
 | 
				
			||||||
        const or: TagsFilter[] = []
 | 
					        const or: TagsFilter[] = []
 | 
				
			||||||
        const blacklisted : TagsFilter[] = []
 | 
					        const blacklisted: TagsFilter[] = []
 | 
				
			||||||
        dict.forEach(({ values, blacklist }, k) => {
 | 
					        dict.forEach(({ values, blacklist }, k) => {
 | 
				
			||||||
            if(blacklist){
 | 
					            if (blacklist) {
 | 
				
			||||||
                if(values === undefined){
 | 
					                if (values === undefined) {
 | 
				
			||||||
                    blacklisted.push(new RegexTag(k, /.+/is))
 | 
					                    blacklisted.push(new RegexTag(k, /.+/is))
 | 
				
			||||||
                    return
 | 
					                    return
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                values.forEach(v => {
 | 
					                values.forEach((v) => {
 | 
				
			||||||
                    blacklisted.push(new RegexTag(k, v))
 | 
					                    blacklisted.push(new RegexTag(k, v))
 | 
				
			||||||
                })
 | 
					                })
 | 
				
			||||||
                return
 | 
					                return
 | 
				
			||||||
| 
						 | 
					@ -40,11 +39,14 @@ class LuaSnippets {
 | 
				
			||||||
                or.push(new RegexTag(k, /.+/is))
 | 
					                or.push(new RegexTag(k, /.+/is))
 | 
				
			||||||
                return
 | 
					                return
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            values.forEach(v => {
 | 
					            values.forEach((v) => {
 | 
				
			||||||
                or.push(new RegexTag(k, v))
 | 
					                or.push(new RegexTag(k, v))
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
        console.log("Polygon features are:", or.map(t => t.asHumanString(false, false, {})))
 | 
					        console.log(
 | 
				
			||||||
 | 
					            "Polygon features are:",
 | 
				
			||||||
 | 
					            or.map((t) => t.asHumanString(false, false, {}))
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
        return { blacklist: new Or(blacklisted), whitelisted: new Or(or) }
 | 
					        return { blacklist: new Or(blacklisted), whitelisted: new Or(or) }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -53,14 +55,14 @@ class LuaSnippets {
 | 
				
			||||||
            return `object.tags["${tag.key}"] == "${tag.value}"`
 | 
					            return `object.tags["${tag.key}"] == "${tag.value}"`
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (tag instanceof And) {
 | 
					        if (tag instanceof And) {
 | 
				
			||||||
            const expr = tag.and.map(t => this.toLuaFilter(t, true)).join(" and ")
 | 
					            const expr = tag.and.map((t) => this.toLuaFilter(t, true)).join(" and ")
 | 
				
			||||||
            if (useParens) {
 | 
					            if (useParens) {
 | 
				
			||||||
                return "(" + expr + ")"
 | 
					                return "(" + expr + ")"
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            return expr
 | 
					            return expr
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (tag instanceof Or) {
 | 
					        if (tag instanceof Or) {
 | 
				
			||||||
            const expr = tag.or.map(t => this.toLuaFilter(t, true)).join(" or ")
 | 
					            const expr = tag.or.map((t) => this.toLuaFilter(t, true)).join(" or ")
 | 
				
			||||||
            if (useParens) {
 | 
					            if (useParens) {
 | 
				
			||||||
                return "(" + expr + ")"
 | 
					                return "(" + expr + ")"
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
| 
						 | 
					@ -87,7 +89,7 @@ class LuaSnippets {
 | 
				
			||||||
            return `object.tags["${tag.key}"] == "${tag.value}"`
 | 
					            return `object.tags["${tag.key}"] == "${tag.value}"`
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const v = (<RegExp>tag.value).source.replace(/\\\//g, "/")
 | 
					        let v: string = (<RegExp>tag.value).source.replace(/\\\//g, "/")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if ("" + tag.value === "/.+/is" && !tag.invert) {
 | 
					        if ("" + tag.value === "/.+/is" && !tag.invert) {
 | 
				
			||||||
            return `object.tags["${tag.key}"] ~= nil`
 | 
					            return `object.tags["${tag.key}"] ~= nil`
 | 
				
			||||||
| 
						 | 
					@ -101,18 +103,35 @@ class LuaSnippets {
 | 
				
			||||||
            return `object.tags["${tag.key}"] == nil or object.tags["${tag.key}"] == ""`
 | 
					            return `object.tags["${tag.key}"] == nil or object.tags["${tag.key}"] == ""`
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (tag.matchesEmpty && tag.invert) {
 | 
					        if (tag.matchesEmpty && tag.invert) {
 | 
				
			||||||
            return `object.tags["${tag.key}"] ~= nil or object.tags["${tag.key}"] ~= ""`
 | 
					            return `object.tags["${tag.key}"] ~= nil or object.tags["${tag.key}"] ~= ""`
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let head = "^((.*;)?"
 | 
				
			||||||
 | 
					        let tail = "(;.*)?)$"
 | 
				
			||||||
 | 
					        if (v.startsWith(head)) {
 | 
				
			||||||
 | 
					            v = "(" + v.substring(head.length)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (v.endsWith(tail)) {
 | 
				
			||||||
 | 
					            v = v.substring(0, v.length - tail.length) + ")"
 | 
				
			||||||
 | 
					            // We basically remove the optional parts at the start and the end, as object.find has this freedom anyway.
 | 
				
			||||||
 | 
					            // This might result in _some_ incorrect values that end up in the database (e.g. when matching 'friture', it might als match "abc;foo_friture_bar;xyz", but the frontend will filter this out
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (v.indexOf(")?") > 0) {
 | 
				
			||||||
 | 
					            throw (
 | 
				
			||||||
 | 
					                "LUA regexes have a bad support for (optional) capture groups, as such, " +
 | 
				
			||||||
 | 
					                v +
 | 
				
			||||||
 | 
					                " is not supported"
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (tag.invert) {
 | 
					        if (tag.invert) {
 | 
				
			||||||
            return `object.tags["${tag.key}"] == nil or not string.find(object.tags["${tag.key}"], "${v}")`
 | 
					            return `object.tags["${tag.key}"] == nil or not string.find(object.tags["${tag.key}"], "${v}")`
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return `(object.tags["${tag.key}"] ~= nil and string.find(object.tags["${tag.key}"], "${v}"))`
 | 
					        return `(object.tags["${tag.key}"] ~= nil and string.find(object.tags["${tag.key}"], "${v}"))`
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class GenerateLayerLua {
 | 
					class GenerateLayerLua {
 | 
				
			||||||
| 
						 | 
					@ -163,8 +182,6 @@ class GenerateLayerLua {
 | 
				
			||||||
            "",
 | 
					            "",
 | 
				
			||||||
        ].join("\n")
 | 
					        ].join("\n")
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class GenerateBuildDbScript extends Script {
 | 
					class GenerateBuildDbScript extends Script {
 | 
				
			||||||
| 
						 | 
					@ -174,7 +191,7 @@ class GenerateBuildDbScript extends Script {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async main(args: string[]) {
 | 
					    async main(args: string[]) {
 | 
				
			||||||
        const allNeededLayers = new ValidateThemeEnsemble().convertStrict(
 | 
					        const allNeededLayers = new ValidateThemeEnsemble().convertStrict(
 | 
				
			||||||
            AllKnownLayouts.allKnownLayouts.values(),
 | 
					            AllKnownLayouts.allKnownLayouts.values()
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const generators: GenerateLayerLua[] = []
 | 
					        const generators: GenerateLayerLua[] = []
 | 
				
			||||||
| 
						 | 
					@ -186,29 +203,30 @@ class GenerateBuildDbScript extends Script {
 | 
				
			||||||
        const script = [
 | 
					        const script = [
 | 
				
			||||||
            "local db_tables = {}",
 | 
					            "local db_tables = {}",
 | 
				
			||||||
            LuaSnippets.helpers,
 | 
					            LuaSnippets.helpers,
 | 
				
			||||||
            ...generators.map(g => g.generateTables()),
 | 
					            ...generators.map((g) => g.generateTables()),
 | 
				
			||||||
            this.generateProcessPoi(allNeededLayers),
 | 
					            this.generateProcessPoi(allNeededLayers),
 | 
				
			||||||
            this.generateProcessWay(allNeededLayers),
 | 
					            this.generateProcessWay(allNeededLayers),
 | 
				
			||||||
        ].join("\n\n\n")
 | 
					        ].join("\n\n\n")
 | 
				
			||||||
        const path = "build_db.lua"
 | 
					        const path = "build_db.lua"
 | 
				
			||||||
        fs.writeFileSync(path, script, "utf-8")
 | 
					        fs.writeFileSync(path, script, "utf-8")
 | 
				
			||||||
        console.log("Written", path)
 | 
					        console.log("Written", path)
 | 
				
			||||||
        console.log(allNeededLayers.size + " layers will be created with 3 tables each. Make sure to set 'max_connections' to at least  " + (10 + 3 * allNeededLayers.size))
 | 
					        console.log(
 | 
				
			||||||
 | 
					            allNeededLayers.size +
 | 
				
			||||||
 | 
					                " layers will be created with 3 tables each. Make sure to set 'max_connections' to at least  " +
 | 
				
			||||||
 | 
					                (10 + 3 * allNeededLayers.size)
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private earlyAbort() {
 | 
					    private earlyAbort() {
 | 
				
			||||||
        return ["  if countTbl(object.tags) == 0 then",
 | 
					        return ["  if countTbl(object.tags) == 0 then", "    return", "  end", ""].join("\n")
 | 
				
			||||||
            "    return",
 | 
					 | 
				
			||||||
            "  end",
 | 
					 | 
				
			||||||
            ""].join("\n")
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private generateProcessPoi(allNeededLayers: Map<string, { tags: TagsFilter; foundInTheme: string[] }>) {
 | 
					    private generateProcessPoi(
 | 
				
			||||||
 | 
					        allNeededLayers: Map<string, { tags: TagsFilter; foundInTheme: string[] }>
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
        const body: string[] = []
 | 
					        const body: string[] = []
 | 
				
			||||||
        allNeededLayers.forEach(({ tags }, layerId) => {
 | 
					        allNeededLayers.forEach(({ tags }, layerId) => {
 | 
				
			||||||
            body.push(
 | 
					            body.push(this.insertInto(tags, layerId, "pois_").join("\n"))
 | 
				
			||||||
                this.insertInto(tags, layerId, "pois_").join("\n"),
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return [
 | 
					        return [
 | 
				
			||||||
| 
						 | 
					@ -228,7 +246,11 @@ class GenerateBuildDbScript extends Script {
 | 
				
			||||||
     * @param tableprefix
 | 
					     * @param tableprefix
 | 
				
			||||||
     * @private
 | 
					     * @private
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    private insertInto(tags: TagsFilter, layerId: string, tableprefix: "pois_" | "lines_" | "polygons_") {
 | 
					    private insertInto(
 | 
				
			||||||
 | 
					        tags: TagsFilter,
 | 
				
			||||||
 | 
					        layerId: string,
 | 
				
			||||||
 | 
					        tableprefix: "pois_" | "lines_" | "polygons_"
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
        const filter = LuaSnippets.toLuaFilter(tags)
 | 
					        const filter = LuaSnippets.toLuaFilter(tags)
 | 
				
			||||||
        return [
 | 
					        return [
 | 
				
			||||||
            "  matches_filter = " + filter,
 | 
					            "  matches_filter = " + filter,
 | 
				
			||||||
| 
						 | 
					@ -265,8 +287,12 @@ class GenerateBuildDbScript extends Script {
 | 
				
			||||||
            "",
 | 
					            "",
 | 
				
			||||||
            "function osm2pgsql.process_way(object)",
 | 
					            "function osm2pgsql.process_way(object)",
 | 
				
			||||||
            this.earlyAbort(),
 | 
					            this.earlyAbort(),
 | 
				
			||||||
            "  local object_is_line = not object.is_closed or "+LuaSnippets.toLuaFilter(isPolygon.blacklist),
 | 
					            "  local object_is_line = not object.is_closed or " +
 | 
				
			||||||
            `  local object_is_area = object.is_closed and (object.tags["area"] == "yes" or (not object_is_line and ${LuaSnippets.toLuaFilter(isPolygon.whitelisted, true)}))`,
 | 
					                LuaSnippets.toLuaFilter(isPolygon.blacklist),
 | 
				
			||||||
 | 
					            `  local object_is_area = object.is_closed and (object.tags["area"] == "yes" or (not object_is_line and ${LuaSnippets.toLuaFilter(
 | 
				
			||||||
 | 
					                isPolygon.whitelisted,
 | 
				
			||||||
 | 
					                true
 | 
				
			||||||
 | 
					            )}))`,
 | 
				
			||||||
            "  if object_is_area then",
 | 
					            "  if object_is_area then",
 | 
				
			||||||
            "    process_polygon(object, object:as_polygon())",
 | 
					            "    process_polygon(object, object:as_polygon())",
 | 
				
			||||||
            "  else",
 | 
					            "  else",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue