]> git.openstreetmap.org Git - nominatim.git/blob - nominatim/db/sqlalchemy_schema.py
Merge remote-tracking branch 'upstream/master'
[nominatim.git] / nominatim / db / sqlalchemy_schema.py
1 # SPDX-License-Identifier: GPL-3.0-or-later
2 #
3 # This file is part of Nominatim. (https://nominatim.org)
4 #
5 # Copyright (C) 2023 by the Nominatim developer community.
6 # For a full list of authors see the git log.
7 """
8 SQLAlchemy definitions for all tables used by the frontend.
9 """
10 from typing import Any
11
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
15
16 import nominatim.db.sqlalchemy_functions #pylint: disable=unused-import
17 from nominatim.db.sqlalchemy_types import Geometry
18
19 class PostgresTypes:
20     """ Type definitions for complex types as used in Postgres variants.
21     """
22     Composite = HSTORE
23     Json = JSONB
24     IntArray = ARRAY(sa.Integer()) #pylint: disable=invalid-name
25     to_array = array
26
27
28 class SqliteTypes:
29     """ Type definitions for complex types as used in Postgres variants.
30     """
31     Composite = sqlite_json
32     Json = sqlite_json
33     IntArray = sqlite_json
34
35     @staticmethod
36     def to_array(arr: Any) -> Any:
37         """ Sqlite has no special conversion for arrays.
38         """
39         return arr
40
41
42 #pylint: disable=too-many-instance-attributes
43 class SearchTables:
44     """ Data class that holds the tables of the Nominatim database.
45
46         This schema strictly reflects the read-access view of the database.
47         Any data used for updates only will not be visible.
48     """
49
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
55         else:
56             raise ValueError("Only 'postgresql' and 'sqlite' engines are supported.")
57
58         self.meta = meta
59
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))
64
65         self.properties = sa.Table('nominatim_properties', meta,
66             sa.Column('property', sa.Text, nullable=False),
67             sa.Column('value', sa.Text))
68
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))
92
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))
99
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))
110
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)))
124
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))
130
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))
135
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))
146
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))