Fix api stores

Rename in category table: geom_type to gis_type
This commit is contained in:
phil 2023-12-27 01:11:54 +05:30
parent c0c308a657
commit 956147aea8
7 changed files with 45 additions and 22 deletions

View file

@ -6,7 +6,6 @@ from fastapi import Depends, FastAPI, HTTPException, status, responses
from sqlalchemy.orm import selectinload from sqlalchemy.orm import selectinload
from fastapi.security import OAuth2PasswordRequestForm from fastapi.security import OAuth2PasswordRequestForm
from sqlmodel import select from sqlmodel import select
from sqlmodel.ext.asyncio.session import AsyncSession
from gisaf.models.authentication import ( from gisaf.models.authentication import (
User, UserRead, User, UserRead,
@ -105,7 +104,8 @@ async def get_categories_p(
@api.get("/stores") @api.get("/stores")
async def get_stores() -> list[Store]: async def get_stores() -> list[Store]:
df = registry.stores.reset_index().drop(columns=['model', 'raw_model']) df = registry.stores.reset_index().\
drop(columns=['model', 'raw_model', 'base_gis_type'])
return df.to_dict(orient="records") return df.to_dict(orient="records")

View file

@ -205,7 +205,7 @@ class RawSurveyImporter(Importer):
gdf['geom'] = gdf.to_crs(conf.srid).geometry.apply(lambda g: dumps_wkb(g, srid=conf.srid, hex=True)) gdf['geom'] = gdf.to_crs(conf.srid).geometry.apply(lambda g: dumps_wkb(g, srid=conf.srid, hex=True))
for category_name, category_gdf in gdf.groupby('category'): for category_name, category_gdf in gdf.groupby('category'):
category = registry.categories.loc[category_name] category = registry.categories.loc[category_name]
if category.auto_import and category.geom_type == 'Point': if category.auto_import and category.gis_type == 'Point':
if not dry_run: if not dry_run:
await upsert_df(category_gdf, category.model) await upsert_df(category_gdf, category.model)
@ -451,7 +451,7 @@ class GeoDataImporter(Importer):
await upsert_df(new_tags, Tags) await upsert_df(new_tags, Tags)
## Publish on Gisaf live ## Publish on Gisaf live
gis_type = gdf_file.geom_type.iloc[0] gis_type = gdf_file.gis_type.iloc[0]
mapbox_type = SHAPELY_TYPE_TO_MAPBOX_TYPE.get(gis_type, None) mapbox_type = SHAPELY_TYPE_TO_MAPBOX_TYPE.get(gis_type, None)
mapbox_paint = DEFAULT_MAPBOX_PAINT.get(mapbox_type, {}).copy() mapbox_paint = DEFAULT_MAPBOX_PAINT.get(mapbox_type, {}).copy()
mapbox_layout = DEFAULT_MAPBOX_LAYOUT.get(mapbox_type, {}).copy() mapbox_layout = DEFAULT_MAPBOX_LAYOUT.get(mapbox_type, {}).copy()

View file

@ -60,9 +60,9 @@ class CategoryBase(BaseModel):
status: str = Field(min_length=1, max_length=1) status: str = Field(min_length=1, max_length=1)
custom: bool | None custom: bool | None
auto_import: bool = True auto_import: bool = True
geom_type: str = Field(max_length=50, gis_type: str = Field(max_length=50,
foreign_key='category_model_type.name', foreign_key='category_model_type.name',
default='Point') default='Point')
long_name: str | None = Field(max_length=50) long_name: str | None = Field(max_length=50)
style: str | None = Field(sa_type=TEXT) style: str | None = Field(sa_type=TEXT)
symbol: str | None = Field(max_length=1) symbol: str | None = Field(max_length=1)
@ -108,7 +108,7 @@ class CategoryBase(BaseModel):
@computed_field @computed_field
@property @property
def mapbox_type(self) -> str: def mapbox_type(self) -> str:
return self.mapbox_type_custom or mapbox_type_mapping[self.geom_type] return self.mapbox_type_custom or mapbox_type_mapping[self.gis_type]
class Category(CategoryBase, table=True): class Category(CategoryBase, table=True):

View file

@ -287,6 +287,9 @@ class GeoModel(Model):
Base class for all geo models Base class for all geo models
""" """
#__abstract__ = True #__abstract__ = True
id: int | None = Field(default=None, primary_key=True)
description: ClassVar[str] = '' description: ClassVar[str] = ''
attribution: ClassVar[str | None] = None attribution: ClassVar[str | None] = None

View file

@ -8,7 +8,7 @@ class MapLibreStyle(BaseModel):
class Store(BaseModel): class Store(BaseModel):
auto_import: bool auto_import: bool
base_gis_type: str # base_gis_type: str
count: int count: int
custom: bool custom: bool
description: str description: str
@ -23,12 +23,12 @@ class Store(BaseModel):
#mapbox_layout: dict[str, Any] | None #mapbox_layout: dict[str, Any] | None
#mapbox_paint: dict[str, Any] | None #mapbox_paint: dict[str, Any] | None
#mapbox_type: str #mapbox_type: str
mapbox_type_custom: str | None # mapbox_type_custom: str | None
#mapbox_type_default: str #mapbox_type_default: str
minor_group_1: str minor_group_1: str | None
minor_group_2: str minor_group_2: str | None
#model: GeoModel #model: GeoModel
geom_type: str gis_type: str
name: str name: str
#name_letter: str #name_letter: str
#name_number: int #name_number: int

View file

@ -190,7 +190,7 @@ class Store:
gdf['popup'] = 'Live: ' + live_name + ' #' + gdf.index.astype('U') gdf['popup'] = 'Live: ' + live_name + ' #' + gdf.index.astype('U')
if len(gdf) > 0: if len(gdf) > 0:
gdf = gdf.to_crs(conf.crs.geojson) gdf = gdf.to_crs(conf.crs.geojson)
gis_type = gdf.geom_type.iloc[0] gis_type = gdf.gis_type.iloc[0]
else: else:
gis_type = 'Point' ## FIXME: cannot be inferred from the gdf? gis_type = 'Point' ## FIXME: cannot be inferred from the gdf?
mapbox_type = SHAPELY_TYPE_TO_MAPBOX_TYPE.get(gis_type, None) mapbox_type = SHAPELY_TYPE_TO_MAPBOX_TYPE.get(gis_type, None)

View file

@ -14,6 +14,7 @@ from sqlalchemy import text
from sqlalchemy.orm import selectinload from sqlalchemy.orm import selectinload
from sqlmodel import SQLModel, select, inspect from sqlmodel import SQLModel, select, inspect
import pandas as pd import pandas as pd
import numpy as np
from gisaf.config import conf from gisaf.config import conf
from gisaf.models import (misc, category as category_module, from gisaf.models import (misc, category as category_module,
@ -166,7 +167,7 @@ class ModelRegistry:
else: else:
logger.debug('Discovered {:s}'.format(category.raw_survey_table_name)) logger.debug('Discovered {:s}'.format(category.raw_survey_table_name))
model_class = category_model_mapper.get(category.geom_type) model_class = category_model_mapper.get(category.gis_type)
## Final geometries ## Final geometries
try: try:
if model_class: if model_class:
@ -213,13 +214,13 @@ class ModelRegistry:
obj = getattr(module, name) obj = getattr(module, name)
if hasattr(obj, '__module__') and obj.__module__.startswith(module.__name__)\ if hasattr(obj, '__module__') and obj.__module__.startswith(module.__name__)\
and hasattr(obj, '__tablename__') and hasattr(obj, 'get_store_name'): and hasattr(obj, '__tablename__') and hasattr(obj, 'get_store_name'):
geom_type = self.add_model(obj) gis_type = self.add_model(obj)
logger.debug(f'Model {obj.get_store_name()} added in the registry from gisaf source tree as {geom_type}') logger.debug(f'Model {obj.get_store_name()} added in the registry from gisaf source tree as {gis_type}')
## Scan the models defined in plugins (setuptools' entry points) ## Scan the models defined in plugins (setuptools' entry points)
for module_name, model in self.scan_entry_points(name='gisaf_extras.models').items(): for module_name, model in self.scan_entry_points(name='gisaf_extras.models').items():
geom_type = self.add_model(model) gis_type = self.add_model(model)
logger.debug(f'Model {model.get_store_name()} added in the registry from {module_name} entry point as {geom_type}') logger.debug(f'Model {model.get_store_name()} added in the registry from {module_name} entry point as {gis_type}')
for module_name, store in self.scan_entry_points(name='gisaf_extras.stores').items(): for module_name, store in self.scan_entry_points(name='gisaf_extras.stores').items():
self.add_store(store) self.add_store(store)
@ -362,11 +363,15 @@ class ModelRegistry:
Used in GraphQl queries. Used in GraphQl queries.
""" """
## Utility functions used with apply method (dataframes) ## Utility functions used with apply method (dataframes)
def fill_columns_from_custom_models(row) -> tuple[str, str, str]: def fill_columns_from_custom_models(row) -> tuple[str, str, str, str, str, str, str]:
return ( return (
row.model.__name__,
row.model.__name__, row.model.__name__,
row.model.description, row.model.description,
row.model.metadata.schema row.model.metadata.schema,
row.model.base_gis_type,
row.model.style,
row.model.symbol,
) )
def fill_columns_from_custom_stores(row) -> tuple[str, str, None]: def fill_columns_from_custom_stores(row) -> tuple[str, str, None]:
@ -430,7 +435,9 @@ class ModelRegistry:
self.categories['is_line_work'] = None self.categories['is_line_work'] = None
self.categories['raw_survey_model'] = None self.categories['raw_survey_model'] = None
## --------------------
## Custom models (Misc) ## Custom models (Misc)
## --------------------
self.custom_models = pd.DataFrame( self.custom_models = pd.DataFrame(
self.geom_custom.items(), self.geom_custom.items(),
columns=['store', 'model'] columns=['store', 'model']
@ -446,17 +453,27 @@ class ModelRegistry:
self.custom_models = self.custom_models.loc[self.custom_models.in_menu] self.custom_models = self.custom_models.loc[self.custom_models.in_menu]
self.custom_models['auto_import'] = False self.custom_models['auto_import'] = False
self.custom_models['is_line_work'] = False self.custom_models['is_line_work'] = False
self.custom_models['minor_group_1'] = None
self.custom_models['minor_group_2'] = None
if len(self.custom_models) > 0: if len(self.custom_models) > 0:
self.custom_models['name'],\
self.custom_models['long_name'],\ self.custom_models['long_name'],\
self.custom_models['custom_description'],\ self.custom_models['custom_description'],\
self.custom_models['db_schema'],\ self.custom_models['db_schema'],\
self.custom_models['gis_type'],\
self.custom_models['style'],\
self.custom_models['symbol'],\
= zip(*self.custom_models.apply(fill_columns_from_custom_models, axis=1)) = zip(*self.custom_models.apply(fill_columns_from_custom_models, axis=1))
## Try to give a meaningful description, eg. including the source (db_schema) ## Try to give a meaningful description, eg. including the source (db_schema)
self.custom_models['description'] = self.custom_models['custom_description'].fillna(self.custom_models['long_name'] + '-' + self.custom_models['db_schema']) self.custom_models['description'] = self.custom_models['custom_description'].fillna(self.custom_models['long_name'] + '-' + self.custom_models['db_schema'])
self.custom_models['title'] = self.custom_models['long_name'] self.custom_models['title'] = self.custom_models['long_name']
self.custom_models.fillna(np.nan, inplace=True)
self.custom_models.replace([np.nan], [None], inplace=True)
## -------------------------
## Custom stores (Community) ## Custom stores (Community)
## -------------------------
self.custom_stores = pd.DataFrame( self.custom_stores = pd.DataFrame(
self.geom_custom_store.items(), self.geom_custom_store.items(),
columns=['store', 'model'] columns=['store', 'model']
@ -481,6 +498,8 @@ class ModelRegistry:
self.custom_stores['db_schema'],\ self.custom_stores['db_schema'],\
= zip(*self.custom_stores.apply(fill_columns_from_custom_stores, axis=1)) = zip(*self.custom_stores.apply(fill_columns_from_custom_stores, axis=1))
self.custom_stores['title'] = self.custom_stores['long_name'] self.custom_stores['title'] = self.custom_stores['long_name']
self.custom_stores.fillna(np.nan, inplace=True)
self.custom_stores.replace([np.nan], [None], inplace=True)
## Combine Misc (custom) and survey (auto) stores ## Combine Misc (custom) and survey (auto) stores
## Retain only one status per category (defaultStatus, 'E'/existing by default) ## Retain only one status per category (defaultStatus, 'E'/existing by default)
@ -490,6 +509,7 @@ class ModelRegistry:
self.custom_stores self.custom_stores
])#.drop(columns=['store_name']) ])#.drop(columns=['store_name'])
self.stores['in_menu'] = self.stores['in_menu'].astype(bool) self.stores['in_menu'] = self.stores['in_menu'].astype(bool)
self.stores['status'].fillna('E', inplace=True)
## Set in the stores dataframe some useful properties, from the model class ## Set in the stores dataframe some useful properties, from the model class
## Maybe at some point it makes sense to get away from class-based definitions ## Maybe at some point it makes sense to get away from class-based definitions
@ -621,7 +641,7 @@ class ModelRegistry:
columns={ columns={
'live': 'is_live', 'live': 'is_live',
'zIndex': 'z_index', 'zIndex': 'z_index',
'gisType': 'geom_type', 'gisType': 'gis_type',
# 'type': 'mapbox_type', # 'type': 'mapbox_type',
'viewableRole': 'viewable_role', 'viewableRole': 'viewable_role',
}, inplace=True }, inplace=True