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.word = sa.Table('word', meta,
117 sa.Column('word_id', sa.Integer),
118 sa.Column('word_token', sa.Text, nullable=False),
119 sa.Column('type', sa.Text, nullable=False),
120 sa.Column('word', sa.Text),
121 sa.Column('info', self.types.Json))
123 self.country_name = sa.Table('country_name', meta,
124 sa.Column('country_code', sa.String(2)),
125 sa.Column('name', self.types.Composite),
126 sa.Column('derived_name', self.types.Composite),
127 sa.Column('country_default_language_code', sa.Text),
128 sa.Column('partition', sa.Integer))
130 self.country_grid = sa.Table('country_osm_grid', meta,
131 sa.Column('country_code', sa.String(2)),
132 sa.Column('area', sa.Float),
133 sa.Column('geometry', Geometry(srid=4326)))
135 # The following tables are not necessarily present.
136 self.search_name = sa.Table('search_name', meta,
137 sa.Column('place_id', sa.BigInteger, index=True),
138 sa.Column('importance', sa.Float),
139 sa.Column('search_rank', sa.SmallInteger),
140 sa.Column('address_rank', sa.SmallInteger),
141 sa.Column('name_vector', self.types.IntArray, index=True),
142 sa.Column('nameaddress_vector', self.types.IntArray, index=True),
143 sa.Column('country_code', sa.String(2)),
144 sa.Column('centroid', Geometry(srid=4326)))
146 self.tiger = sa.Table('location_property_tiger', meta,
147 sa.Column('place_id', sa.BigInteger),
148 sa.Column('parent_place_id', sa.BigInteger),
149 sa.Column('startnumber', sa.Integer),
150 sa.Column('endnumber', sa.Integer),
151 sa.Column('step', sa.SmallInteger),
152 sa.Column('partition', sa.SmallInteger),
153 sa.Column('linegeo', Geometry(srid=4326, spatial_index=False)),
154 sa.Column('postcode', sa.Text))