Correctly handle non-working optional match groups in generate build_db script

This commit is contained in:
Pieter Vander Vennet 2024-02-25 02:49:34 +01:00
parent 760276922d
commit b37ea885a5

View file

@ -10,7 +10,6 @@ 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" +
@ -21,17 +20,17 @@ class LuaSnippets {
"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",