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 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
 
  28     """ Type definitions for complex types as used in Postgres variants.
 
  30     Composite = sqlite_json
 
  32     IntArray = sqlite_json
 
  35     def to_array(arr: Any) -> Any:
 
  36         """ Sqlite has no special conversion for arrays.
 
  41 #pylint: disable=too-many-instance-attributes
 
  43     """ Data class that holds the tables of the Nominatim database.
 
  46     def __init__(self, meta: sa.MetaData, engine_name: str) -> None:
 
  47         if engine_name == 'postgresql':
 
  48             self.types: Any = PostgresTypes
 
  49         elif engine_name == 'sqlite':
 
  50             self.types = SqliteTypes
 
  52             raise ValueError("Only 'postgresql' and 'sqlite' engines are supported.")
 
  56         self.import_status = sa.Table('import_status', meta,
 
  57             sa.Column('lastimportdate', sa.DateTime(True), nullable=False),
 
  58             sa.Column('sequence_id', sa.Integer),
 
  59             sa.Column('indexed', sa.Boolean))
 
  61         self.properties = sa.Table('nominatim_properties', meta,
 
  62             sa.Column('property', sa.Text, nullable=False),
 
  63             sa.Column('value', sa.Text))
 
  65         self.placex = sa.Table('placex', meta,
 
  66             sa.Column('place_id', sa.BigInteger, nullable=False, unique=True),
 
  67             sa.Column('parent_place_id', sa.BigInteger),
 
  68             sa.Column('linked_place_id', sa.BigInteger),
 
  69             sa.Column('importance', sa.Float),
 
  70             sa.Column('indexed_date', sa.DateTime),
 
  71             sa.Column('rank_address', sa.SmallInteger),
 
  72             sa.Column('rank_search', sa.SmallInteger),
 
  73             sa.Column('partition', sa.SmallInteger),
 
  74             sa.Column('indexed_status', sa.SmallInteger),
 
  75             sa.Column('osm_type', sa.String(1), nullable=False),
 
  76             sa.Column('osm_id', sa.BigInteger, nullable=False),
 
  77             sa.Column('class', sa.Text, nullable=False, key='class_'),
 
  78             sa.Column('type', sa.Text, nullable=False),
 
  79             sa.Column('admin_level', sa.SmallInteger),
 
  80             sa.Column('name', self.types.Composite),
 
  81             sa.Column('address', self.types.Composite),
 
  82             sa.Column('extratags', self.types.Composite),
 
  83             sa.Column('geometry', Geometry, nullable=False),
 
  84             sa.Column('wikipedia', sa.Text),
 
  85             sa.Column('country_code', sa.String(2)),
 
  86             sa.Column('housenumber', sa.Text),
 
  87             sa.Column('postcode', sa.Text),
 
  88             sa.Column('centroid', Geometry))
 
  90         self.addressline = sa.Table('place_addressline', meta,
 
  91             sa.Column('place_id', sa.BigInteger, index=True),
 
  92             sa.Column('address_place_id', sa.BigInteger, index=True),
 
  93             sa.Column('distance', sa.Float),
 
  94             sa.Column('cached_rank_address', sa.SmallInteger),
 
  95             sa.Column('fromarea', sa.Boolean),
 
  96             sa.Column('isaddress', sa.Boolean))
 
  98         self.postcode = sa.Table('location_postcode', meta,
 
  99             sa.Column('place_id', sa.BigInteger, unique=True),
 
 100             sa.Column('parent_place_id', sa.BigInteger),
 
 101             sa.Column('rank_search', sa.SmallInteger),
 
 102             sa.Column('rank_address', sa.SmallInteger),
 
 103             sa.Column('indexed_status', sa.SmallInteger),
 
 104             sa.Column('indexed_date', sa.DateTime),
 
 105             sa.Column('country_code', sa.String(2)),
 
 106             sa.Column('postcode', sa.Text, index=True),
 
 107             sa.Column('geometry', Geometry))
 
 109         self.osmline = sa.Table('location_property_osmline', meta,
 
 110             sa.Column('place_id', sa.BigInteger, nullable=False, unique=True),
 
 111             sa.Column('osm_id', sa.BigInteger),
 
 112             sa.Column('parent_place_id', sa.BigInteger),
 
 113             sa.Column('indexed_date', sa.DateTime),
 
 114             sa.Column('startnumber', sa.Integer),
 
 115             sa.Column('endnumber', sa.Integer),
 
 116             sa.Column('step', sa.SmallInteger),
 
 117             sa.Column('partition', sa.SmallInteger),
 
 118             sa.Column('indexed_status', sa.SmallInteger),
 
 119             sa.Column('linegeo', Geometry),
 
 120             sa.Column('address', self.types.Composite),
 
 121             sa.Column('postcode', sa.Text),
 
 122             sa.Column('country_code', sa.String(2)))
 
 124         self.country_name = sa.Table('country_name', meta,
 
 125             sa.Column('country_code', sa.String(2)),
 
 126             sa.Column('name', self.types.Composite),
 
 127             sa.Column('derived_name', self.types.Composite),
 
 128             sa.Column('country_default_language_code', sa.Text),
 
 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, index=True),
 
 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, index=True),
 
 143             sa.Column('nameaddress_vector', self.types.IntArray, index=True),
 
 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('partition', sa.SmallInteger),
 
 154             sa.Column('linegeo', Geometry),
 
 155             sa.Column('postcode', sa.Text))