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
14 from sqlalchemy.dialects.sqlite import JSON as sqlite_json
16 from nominatim.db.sqlalchemy_types import Geometry
19 """ Type definitions for complex types as used in Postgres variants.
23 IntArray = ARRAY(sa.Integer()) #pylint: disable=invalid-name
27 """ Type definitions for complex types as used in Postgres variants.
29 Composite = sqlite_json
31 IntArray = sqlite_json
34 #pylint: disable=too-many-instance-attributes
36 """ Data class that holds the tables of the Nominatim database.
39 def __init__(self, meta: sa.MetaData, engine_name: str) -> None:
40 if engine_name == 'postgresql':
41 self.types: Any = PostgresTypes
42 elif engine_name == 'sqlite':
43 self.types = SqliteTypes
45 raise ValueError("Only 'postgresql' and 'sqlite' engines are supported.")
49 self.import_status = sa.Table('import_status', meta,
50 sa.Column('lastimportdate', sa.DateTime(True), nullable=False),
51 sa.Column('sequence_id', sa.Integer),
52 sa.Column('indexed', sa.Boolean))
54 self.properties = sa.Table('nominatim_properties', meta,
55 sa.Column('property', sa.Text, nullable=False),
56 sa.Column('value', sa.Text))
58 self.placex = sa.Table('placex', meta,
59 sa.Column('place_id', sa.BigInteger, nullable=False, unique=True),
60 sa.Column('parent_place_id', sa.BigInteger),
61 sa.Column('linked_place_id', sa.BigInteger),
62 sa.Column('importance', sa.Float),
63 sa.Column('indexed_date', sa.DateTime),
64 sa.Column('rank_address', sa.SmallInteger),
65 sa.Column('rank_search', sa.SmallInteger),
66 sa.Column('partition', sa.SmallInteger),
67 sa.Column('indexed_status', sa.SmallInteger),
68 sa.Column('osm_type', sa.String(1), nullable=False),
69 sa.Column('osm_id', sa.BigInteger, nullable=False),
70 sa.Column('class', sa.Text, nullable=False, key='class_'),
71 sa.Column('type', sa.Text, nullable=False),
72 sa.Column('admin_level', sa.SmallInteger),
73 sa.Column('name', self.types.Composite),
74 sa.Column('address', self.types.Composite),
75 sa.Column('extratags', self.types.Composite),
76 sa.Column('geometry', Geometry, nullable=False),
77 sa.Column('wikipedia', sa.Text),
78 sa.Column('country_code', sa.String(2)),
79 sa.Column('housenumber', sa.Text),
80 sa.Column('postcode', sa.Text),
81 sa.Column('centroid', Geometry))
83 self.addressline = sa.Table('place_addressline', meta,
84 sa.Column('place_id', sa.BigInteger, index=True),
85 sa.Column('address_place_id', sa.BigInteger, index=True),
86 sa.Column('distance', sa.Float),
87 sa.Column('cached_rank_address', sa.SmallInteger),
88 sa.Column('fromarea', sa.Boolean),
89 sa.Column('isaddress', sa.Boolean))
91 self.postcode = sa.Table('location_postcode', meta,
92 sa.Column('place_id', sa.BigInteger, unique=True),
93 sa.Column('parent_place_id', sa.BigInteger),
94 sa.Column('rank_search', sa.SmallInteger),
95 sa.Column('rank_address', sa.SmallInteger),
96 sa.Column('indexed_status', sa.SmallInteger),
97 sa.Column('indexed_date', sa.DateTime),
98 sa.Column('country_code', sa.String(2)),
99 sa.Column('postcode', sa.Text, index=True),
100 sa.Column('geometry', Geometry))
102 self.osmline = sa.Table('location_property_osmline', meta,
103 sa.Column('place_id', sa.BigInteger, nullable=False, unique=True),
104 sa.Column('osm_id', sa.BigInteger),
105 sa.Column('parent_place_id', sa.BigInteger),
106 sa.Column('indexed_date', sa.DateTime),
107 sa.Column('startnumber', sa.Integer),
108 sa.Column('endnumber', sa.Integer),
109 sa.Column('step', sa.SmallInteger),
110 sa.Column('partition', sa.SmallInteger),
111 sa.Column('indexed_status', sa.SmallInteger),
112 sa.Column('linegeo', Geometry),
113 sa.Column('address', self.types.Composite),
114 sa.Column('postcode', sa.Text),
115 sa.Column('country_code', sa.String(2)))
117 self.country_name = sa.Table('country_name', meta,
118 sa.Column('country_code', sa.String(2)),
119 sa.Column('name', self.types.Composite),
120 sa.Column('derived_name', self.types.Composite),
121 sa.Column('country_default_language_code', sa.Text),
122 sa.Column('partition', sa.Integer))
124 self.country_grid = sa.Table('country_osm_grid', meta,
125 sa.Column('country_code', sa.String(2)),
126 sa.Column('area', sa.Float),
127 sa.Column('geometry', Geometry))
129 # The following tables are not necessarily present.
130 self.search_name = sa.Table('search_name', meta,
131 sa.Column('place_id', sa.BigInteger, index=True),
132 sa.Column('importance', sa.Float),
133 sa.Column('search_rank', sa.SmallInteger),
134 sa.Column('address_rank', sa.SmallInteger),
135 sa.Column('name_vector', self.types.IntArray, index=True),
136 sa.Column('nameaddress_vector', self.types.IntArray, index=True),
137 sa.Column('country_code', sa.String(2)),
138 sa.Column('centroid', Geometry))
140 self.tiger = sa.Table('location_property_tiger', meta,
141 sa.Column('place_id', sa.BigInteger),
142 sa.Column('parent_place_id', sa.BigInteger),
143 sa.Column('startnumber', sa.Integer),
144 sa.Column('endnumber', sa.Integer),
145 sa.Column('step', sa.SmallInteger),
146 sa.Column('partition', sa.SmallInteger),
147 sa.Column('linegeo', Geometry),
148 sa.Column('postcode', sa.Text))