mapcomplete/scripts/osm2pgsql/generateBuildDbScript.ts

178 lines
5.7 KiB
TypeScript
Raw Normal View History

import { TagsFilter } from "../../src/Logic/Tags/TagsFilter"
import { Tag } from "../../src/Logic/Tags/Tag"
import { And } from "../../src/Logic/Tags/And"
import Script from "../Script"
import fs from "fs"
import { Or } from "../../src/Logic/Tags/Or"
import { RegexTag } from "../../src/Logic/Tags/RegexTag"
import { Utils } from "../../src/Utils"
import { ValidateThemeEnsemble } from "../../src/Models/ThemeConfig/Conversion/Validation"
import { AllKnownLayouts } from "../../src/Customizations/AllKnownLayouts"
2024-01-23 22:03:02 +01:00
class LuaSnippets {
/**
* The main piece of code that calls `process_poi`
*/
static tail = [
"function osm2pgsql.process_node(object)",
" process_poi(object, object:as_point())",
"end",
"",
"function osm2pgsql.process_way(object)",
" if object.is_closed then",
" process_poi(object, object:as_polygon():centroid())",
" end",
"end",
""].join("\n")
2024-01-23 22:03:02 +01:00
public static combine(calls: string[]): string {
return [
`function process_poi(object, geom)`,
2024-01-23 22:03:02 +01:00
...calls.map(c => " " + c + "(object, geom)"),
`end`,
].join("\n")
}
}
2024-01-23 22:03:02 +01:00
class GenerateLayerLua {
private readonly _id: string
private readonly _tags: TagsFilter
private readonly _foundInThemes: string[]
constructor(id: string, tags: TagsFilter, foundInThemes: string[] = []) {
this._tags = tags
this._id = id
this._foundInThemes = foundInThemes
}
2024-01-23 22:03:02 +01:00
public functionName() {
if (!this._tags) {
return undefined
}
return `process_poi_${this._id}`
}
public generateFunction(): string {
if (!this._tags) {
return undefined
}
return [
`local pois_${this._id} = osm2pgsql.define_table({`,
this._foundInThemes ? "-- used in themes: " + this._foundInThemes.join(", ") : "",
` name = '${this._id}',`,
" ids = { type = 'any', type_column = 'osm_type', id_column = 'osm_id' },",
" columns = {",
" { column = 'tags', type = 'jsonb' },",
" { column = 'geom', type = 'point', projection = 4326, not_null = true },",
" }" +
"})",
"",
"",
`function ${this.functionName()}(object, geom)`,
" local matches_filter = " + this.toLuaFilter(this._tags),
" if( not matches_filter) then",
" return",
" end",
" local a = {",
" geom = geom,",
" tags = object.tags",
" }",
" ",
` pois_${this._id}:insert(a)`,
"end",
2024-01-23 22:03:02 +01:00
"",
].join("\n")
}
2024-01-23 22:03:02 +01:00
private regexTagToLua(tag: RegexTag) {
if (typeof tag.value === "string" && tag.invert) {
return `object.tags["${tag.key}"] ~= "${tag.value}"`
}
const v = (<RegExp> tag.value).source.replace(/\\\//g, "/")
2024-01-23 22:03:02 +01:00
if ("" + tag.value === "/.+/is" && !tag.invert) {
return `object.tags["${tag.key}"] ~= nil`
}
if ("" + tag.value === "/.+/is" && tag.invert) {
return `object.tags["${tag.key}"] == nil`
}
if (tag.matchesEmpty && !tag.invert) {
return `object.tags["${tag.key}"] == nil or object.tags["${tag.key}"] == ""`
}
if (tag.matchesEmpty && tag.invert) {
return `object.tags["${tag.key}"] ~= nil or object.tags["${tag.key}"] ~= ""`
}
if (tag.invert) {
return `object.tags["${tag.key}"] == nil or not string.find(object.tags["${tag.key}"], "${v}")`
2024-01-23 22:03:02 +01:00
}
return `(object.tags["${tag.key}"] ~= nil and string.find(object.tags["${tag.key}"], "${v}"))`
2024-01-23 22:03:02 +01:00
}
private toLuaFilter(tag: TagsFilter, useParens: boolean = false): string {
if (tag instanceof Tag) {
return `object.tags["${tag.key}"] == "${tag.value}"`
}
if (tag instanceof And) {
const expr = tag.and.map(t => this.toLuaFilter(t, true)).join(" and ")
if (useParens) {
return "(" + expr + ")"
}
return expr
}
if (tag instanceof Or) {
const expr = tag.or.map(t => this.toLuaFilter(t, true)).join(" or ")
if (useParens) {
return "(" + expr + ")"
}
return expr
}
if (tag instanceof RegexTag) {
2024-01-23 22:03:02 +01:00
let expr = this.regexTagToLua(tag)
if (useParens) {
expr = "(" + expr + ")"
}
return expr
}
let msg = "Could not handle" + tag.asHumanString(false, false, {})
console.error(msg)
throw msg
}
}
class GenerateBuildDbScript extends Script {
constructor() {
super("Generates a .lua-file to use with osm2pgsql")
}
async main(args: string[]) {
const allNeededLayers = new ValidateThemeEnsemble().convertStrict(
AllKnownLayouts.allKnownLayouts.values(),
)
const generators: GenerateLayerLua[] = []
allNeededLayers.forEach(({ tags, foundInTheme }, layerId) => {
generators.push(new GenerateLayerLua(layerId, tags, foundInTheme))
})
const script = [
...generators.map(g => g.generateFunction()),
LuaSnippets.combine(Utils.NoNull(generators.map(g => g.functionName()))),
2024-01-23 22:03:02 +01:00
LuaSnippets.tail,
].join("\n\n\n")
const path = "build_db.lua"
2024-01-23 22:03:02 +01:00
fs.writeFileSync(path, script, "utf-8")
console.log("Written", path)
console.log(allNeededLayers.size+" layers will be created. Make sure to set 'max_connections' to at least "+(10 + allNeededLayers.size) )
}
}
new GenerateBuildDbScript().run()