1 # SPDX-License-Identifier: GPL-3.0-or-later
3 # This file is part of Nominatim. (https://nominatim.org)
5 # Copyright (C) 2023 by the Nominatim developer community.
6 # For a full list of authors see the git log.
8 SQLAlchemy definitions for all tables used by the frontend.
10 from typing import Any
12 import sqlalchemy as sa
13 from geoalchemy2 import Geometry
14 from sqlalchemy.dialects.postgresql import HSTORE, ARRAY, JSONB
15 from sqlalchemy.dialects.sqlite import JSON as sqlite_json
18 """ Type definitions for complex types as used in Postgres variants.
22 IntArray = ARRAY(sa.Integer()) #pylint: disable=invalid-name
26 """ Type definitions for complex types as used in Postgres variants.
28 Composite = sqlite_json
30 IntArray = sqlite_json
33 #pylint: disable=too-many-instance-attributes
35 """ Data class that holds the tables of the Nominatim database.
38 def __init__(self, meta: sa.MetaData, engine_name: str) -> None:
39 if engine_name == 'postgresql':
40 self.types: Any = PostgresTypes
41 elif engine_name == 'sqlite':
42 self.types = SqliteTypes
44 raise ValueError("Only 'postgresql' and 'sqlite' engines are supported.")
48 self.import_status = sa.Table('import_status', meta,
49 sa.Column('lastimportdate', sa.DateTime(True), nullable=False),
50 sa.Column('sequence_id', sa.Integer),
51 sa.Column('indexed', sa.Boolean))
53 self.properties = sa.Table('nominatim_properties', meta,
54 sa.Column('property', sa.Text, nullable=False),
55 sa.Column('value', sa.Text))
57 self.placex = sa.Table('placex', meta,
58 sa.Column('place_id', sa.BigInteger, nullable=False, unique=True),
59 sa.Column('parent_place_id', sa.BigInteger),
60 sa.Column('linked_place_id', sa.BigInteger),
61 sa.Column('importance', sa.Float),
62 sa.Column('indexed_date', sa.DateTime),
63 sa.Column('rank_address', sa.SmallInteger),
64 sa.Column('rank_search', sa.SmallInteger),
65 sa.Column('partition', sa.SmallInteger),
66 sa.Column('indexed_status', sa.SmallInteger),
67 sa.Column('osm_type', sa.String(1), nullable=False),
68 sa.Column('osm_id', sa.BigInteger, nullable=False),
69 sa.Column('class', sa.Text, nullable=False, key='class_'),
70 sa.Column('type', sa.Text, nullable=False),
71 sa.Column('admin_level', sa.SmallInteger),
72 sa.Column('name', self.types.Composite),
73 sa.Column('address', self.types.Composite),
74 sa.Column('extratags', self.types.Composite),
75 sa.Column('geometry', Geometry(srid=4326), nullable=False),
76 sa.Column('wikipedia', sa.Text),
77 sa.Column('country_code', sa.String(2)),
78 sa.Column('housenumber', sa.Text),
79 sa.Column('postcode', sa.Text),
80 sa.Column('centroid', Geometry(srid=4326, spatial_index=False)))
82 self.addressline = sa.Table('place_addressline', meta,
83 sa.Column('place_id', sa.BigInteger, index=True),
84 sa.Column('address_place_id', sa.BigInteger, index=True),
85 sa.Column('distance', sa.Float),
86 sa.Column('cached_rank_address', sa.SmallInteger),
87 sa.Column('fromarea', sa.Boolean),
88 sa.Column('isaddress', sa.Boolean))
90 self.postcode = sa.Table('location_postcode', meta,
91 sa.Column('place_id', sa.BigInteger, unique=True),
92 sa.Column('parent_place_id', sa.BigInteger),
93 sa.Column('rank_search', sa.SmallInteger),
94 sa.Column('rank_address', sa.SmallInteger),
95 sa.Column('indexed_status', sa.SmallInteger),
96 sa.Column('indexed_date', sa.DateTime),
97 sa.Column('country_code', sa.String(2)),
98 sa.Column('postcode', sa.Text, index=True),
99 sa.Column('geometry', Geometry(srid=4326)))
101 self.osmline = sa.Table('location_property_osmline', meta,
102 sa.Column('place_id', sa.BigInteger, nullable=False, unique=True),
103 sa.Column('osm_id', sa.BigInteger),
104 sa.Column('parent_place_id', sa.BigInteger),
105 sa.Column('indexed_date', sa.DateTime),
106 sa.Column('startnumber', sa.Integer),
107 sa.Column('endnumber', sa.Integer),
108 sa.Column('step', sa.SmallInteger),
109 sa.Column('partition', sa.SmallInteger),
110 sa.Column('indexed_status', sa.SmallInteger),
111 sa.Column('linegeo', Geometry(srid=4326)),
112 sa.Column('address', self.types.Composite),
113 sa.Column('postcode', sa.Text),
114 sa.Column('country_code', sa.String(2)))
116 self.country_name = sa.Table('country_name', meta,
117 sa.Column('country_code', sa.String(2)),
118 sa.Column('name', self.types.Composite),
119 sa.Column('derived_name', self.types.Composite),
120 sa.Column('country_default_language_code', sa.Text),
121 sa.Column('partition', sa.Integer))
123 self.country_grid = sa.Table('country_osm_grid', meta,
124 sa.Column('country_code', sa.String(2)),
125 sa.Column('area', sa.Float),
126 sa.Column('geometry', Geometry(srid=4326)))
128 # The following tables are not necessarily present.
129 self.search_name = sa.Table('search_name', meta,
130 sa.Column('place_id', sa.BigInteger, index=True),
131 sa.Column('importance', sa.Float),
132 sa.Column('search_rank', sa.SmallInteger),
133 sa.Column('address_rank', sa.SmallInteger),
134 sa.Column('name_vector', self.types.IntArray, index=True),
135 sa.Column('nameaddress_vector', self.types.IntArray, index=True),
136 sa.Column('country_code', sa.String(2)),
137 sa.Column('centroid', Geometry(srid=4326)))
139 self.tiger = sa.Table('location_property_tiger', meta,
140 sa.Column('place_id', sa.BigInteger),
141 sa.Column('parent_place_id', sa.BigInteger),
142 sa.Column('startnumber', sa.Integer),
143 sa.Column('endnumber', sa.Integer),
144 sa.Column('step', sa.SmallInteger),
145 sa.Column('partition', sa.SmallInteger),
146 sa.Column('linegeo', Geometry(srid=4326, spatial_index=False)),
147 sa.Column('postcode', sa.Text))