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 sqlalchemy.dialects.postgresql import HSTORE, ARRAY, JSONB, array
14 from sqlalchemy.dialects.sqlite import JSON as sqlite_json
16 import nominatim.db.sqlalchemy_functions #pylint: disable=unused-import
17 from nominatim.db.sqlalchemy_types import Geometry
20 """ Type definitions for complex types as used in Postgres variants.
24 IntArray = ARRAY(sa.Integer()) #pylint: disable=invalid-name
29 """ Type definitions for complex types as used in Postgres variants.
31 Composite = sqlite_json
33 IntArray = sqlite_json
36 def to_array(arr: Any) -> Any:
37 """ Sqlite has no special conversion for arrays.
42 #pylint: disable=too-many-instance-attributes
44 """ Data class that holds the tables of the Nominatim database.
46 This schema strictly reflects the read-access view of the database.
47 Any data used for updates only will not be visible.
50 def __init__(self, meta: sa.MetaData, engine_name: str) -> None:
51 if engine_name == 'postgresql':
52 self.types: Any = PostgresTypes
53 elif engine_name == 'sqlite':
54 self.types = SqliteTypes
56 raise ValueError("Only 'postgresql' and 'sqlite' engines are supported.")
60 self.import_status = sa.Table('import_status', meta,
61 sa.Column('lastimportdate', sa.DateTime(True), nullable=False),
62 sa.Column('sequence_id', sa.Integer),
63 sa.Column('indexed', sa.Boolean))
65 self.properties = sa.Table('nominatim_properties', meta,
66 sa.Column('property', sa.Text, nullable=False),
67 sa.Column('value', sa.Text))
69 self.placex = sa.Table('placex', meta,
70 sa.Column('place_id', sa.BigInteger, nullable=False),
71 sa.Column('parent_place_id', sa.BigInteger),
72 sa.Column('linked_place_id', sa.BigInteger),
73 sa.Column('importance', sa.Float),
74 sa.Column('indexed_date', sa.DateTime),
75 sa.Column('rank_address', sa.SmallInteger),
76 sa.Column('rank_search', sa.SmallInteger),
77 sa.Column('indexed_status', sa.SmallInteger),
78 sa.Column('osm_type', sa.String(1), nullable=False),
79 sa.Column('osm_id', sa.BigInteger, nullable=False),
80 sa.Column('class', sa.Text, nullable=False, key='class_'),
81 sa.Column('type', sa.Text, nullable=False),
82 sa.Column('admin_level', sa.SmallInteger),
83 sa.Column('name', self.types.Composite),
84 sa.Column('address', self.types.Composite),
85 sa.Column('extratags', self.types.Composite),
86 sa.Column('geometry', Geometry, nullable=False),
87 sa.Column('wikipedia', sa.Text),
88 sa.Column('country_code', sa.String(2)),
89 sa.Column('housenumber', sa.Text),
90 sa.Column('postcode', sa.Text),
91 sa.Column('centroid', Geometry))
93 self.addressline = sa.Table('place_addressline', meta,
94 sa.Column('place_id', sa.BigInteger),
95 sa.Column('address_place_id', sa.BigInteger),
96 sa.Column('distance', sa.Float),
97 sa.Column('fromarea', sa.Boolean),
98 sa.Column('isaddress', sa.Boolean))
100 self.postcode = sa.Table('location_postcode', meta,
101 sa.Column('place_id', sa.BigInteger),
102 sa.Column('parent_place_id', sa.BigInteger),
103 sa.Column('rank_search', sa.SmallInteger),
104 sa.Column('rank_address', sa.SmallInteger),
105 sa.Column('indexed_status', sa.SmallInteger),
106 sa.Column('indexed_date', sa.DateTime),
107 sa.Column('country_code', sa.String(2)),
108 sa.Column('postcode', sa.Text),
109 sa.Column('geometry', Geometry))
111 self.osmline = sa.Table('location_property_osmline', meta,
112 sa.Column('place_id', sa.BigInteger, nullable=False),
113 sa.Column('osm_id', sa.BigInteger),
114 sa.Column('parent_place_id', sa.BigInteger),
115 sa.Column('indexed_date', sa.DateTime),
116 sa.Column('startnumber', sa.Integer),
117 sa.Column('endnumber', sa.Integer),
118 sa.Column('step', sa.SmallInteger),
119 sa.Column('indexed_status', sa.SmallInteger),
120 sa.Column('linegeo', Geometry),
121 sa.Column('address', self.types.Composite),
122 sa.Column('postcode', sa.Text),
123 sa.Column('country_code', sa.String(2)))
125 self.country_name = sa.Table('country_name', meta,
126 sa.Column('country_code', sa.String(2)),
127 sa.Column('name', self.types.Composite),
128 sa.Column('derived_name', self.types.Composite),
129 sa.Column('partition', sa.Integer))
131 self.country_grid = sa.Table('country_osm_grid', meta,
132 sa.Column('country_code', sa.String(2)),
133 sa.Column('area', sa.Float),
134 sa.Column('geometry', Geometry))
136 # The following tables are not necessarily present.
137 self.search_name = sa.Table('search_name', meta,
138 sa.Column('place_id', sa.BigInteger),
139 sa.Column('importance', sa.Float),
140 sa.Column('search_rank', sa.SmallInteger),
141 sa.Column('address_rank', sa.SmallInteger),
142 sa.Column('name_vector', self.types.IntArray),
143 sa.Column('nameaddress_vector', self.types.IntArray),
144 sa.Column('country_code', sa.String(2)),
145 sa.Column('centroid', Geometry))
147 self.tiger = sa.Table('location_property_tiger', meta,
148 sa.Column('place_id', sa.BigInteger),
149 sa.Column('parent_place_id', sa.BigInteger),
150 sa.Column('startnumber', sa.Integer),
151 sa.Column('endnumber', sa.Integer),
152 sa.Column('step', sa.SmallInteger),
153 sa.Column('linegeo', Geometry),
154 sa.Column('postcode', sa.Text))