Files
Cloud-Tour-to-Libo/app/data_platform/registry.py

365 lines
15 KiB
Python

from __future__ import annotations
from dataclasses import dataclass
from typing import Any
@dataclass(frozen=True)
class FieldDefinition:
code: str
label: str
sql_type: str
data_type: str = "text"
required: bool = False
searchable: bool = False
sortable: bool = True
editable: bool = True
visible_in_list: bool = True
default_sql: str | None = None
options: tuple[str, ...] = ()
def as_dict(self) -> dict[str, Any]:
return {
"code": self.code,
"label": self.label,
"data_type": self.data_type,
"required": self.required,
"searchable": self.searchable,
"sortable": self.sortable,
"editable": self.editable,
"visible_in_list": self.visible_in_list,
"options": list(self.options),
}
@dataclass(frozen=True)
class TableDefinition:
code: str
label: str
group: str
description: str
fields: tuple[FieldDefinition, ...]
allow_create: bool = True
allow_update: bool = True
allow_delete: bool = True
@property
def primary_key(self) -> str:
return "id"
@property
def title_field(self) -> str:
for candidate in ("name", "room_name", "facility_name", "deal_name", "route_name", "tag_name"):
if any(field.code == candidate for field in self.fields):
return candidate
return "id"
def as_dict(self) -> dict[str, Any]:
system_fields = (
FieldDefinition("id", "记录 ID", "UUID", editable=False),
FieldDefinition("created_at", "创建时间", "TIMESTAMPTZ", "datetime", editable=False),
FieldDefinition("updated_at", "更新时间", "TIMESTAMPTZ", "datetime", editable=False),
)
return {
"code": self.code,
"label": self.label,
"group": self.group,
"description": self.description,
"primary_key": self.primary_key,
"title_field": self.title_field,
"allow_create": self.allow_create,
"allow_update": self.allow_update,
"allow_delete": self.allow_delete,
"fields": [field.as_dict() for field in (*system_fields, *self.fields)],
}
def field(
code: str,
label: str,
sql_type: str = "TEXT",
data_type: str = "text",
*,
required: bool = False,
searchable: bool = False,
visible: bool = True,
default_sql: str | None = None,
options: tuple[str, ...] = (),
) -> FieldDefinition:
return FieldDefinition(
code=code,
label=label,
sql_type=sql_type,
data_type=data_type,
required=required,
searchable=searchable,
visible_in_list=visible,
default_sql=default_sql,
options=options,
)
TABLE_DEFINITIONS: tuple[TableDefinition, ...] = (
TableDefinition(
"poi_entities",
"地点实体",
"正式实体",
"酒店、美食、景区、交通和公交站统一基础信息。",
(
field("entity_type", "实体类型", required=True, searchable=True, options=("hotel", "restaurant", "scenic", "transport", "bus_stop")),
field("name", "名称", required=True, searchable=True),
field("category_l1", "一级分类", searchable=True),
field("category_l2", "二级分类", searchable=True),
field("category_l3", "细分类", searchable=True),
field("address", "地址", searchable=True),
field("district", "行政区", searchable=True),
field("adcode", "行政区划代码"),
field("phone", "商家电话"),
field("longitude", "经度", "DOUBLE PRECISION", "number"),
field("latitude", "纬度", "DOUBLE PRECISION", "number"),
field("h3_r9", "片区 R9"),
field("h3_r10", "片区 R10"),
field("status", "状态", default_sql="'active'", options=("active", "disabled")),
field("version", "版本", "INTEGER", "number", default_sql="1"),
field("extra_data", "扩展数据", "JSONB", "json", visible=False, default_sql="'{}'::jsonb"),
),
),
TableDefinition(
"entity_external_links",
"外部平台标识",
"公共明细",
"高德、携程、大众点评等已确认的平台 ID 与详情链接。",
(
field("entity_id", "实体 ID", "UUID", required=True, searchable=True),
field("platform", "平台", required=True, searchable=True, options=("amap", "ctrip", "dianping", "other")),
field("external_id", "平台 ID", required=True, searchable=True),
field("external_name", "平台名称", searchable=True),
field("external_url", "平台链接", "TEXT", "url"),
),
),
TableDefinition(
"entity_images",
"实体图片",
"公共明细",
"实体、房型、团购套餐等图片及来源。",
(
field("entity_id", "实体 ID", "UUID", required=True, searchable=True),
field("owner_type", "归属类型", default_sql="'entity'", options=("entity", "room", "deal")),
field("owner_id", "归属记录 ID", "UUID"),
field("image_url", "图片 URL", "TEXT", "url", required=True),
field("caption", "图片说明", searchable=True),
field("display_order", "排序", "INTEGER", "number", default_sql="0"),
),
),
TableDefinition(
"entity_relations",
"实体关系",
"公共明细",
"已经确认的包含、附近、分类和空间关系。",
(
field("source_entity_id", "源实体 ID", "UUID", required=True, searchable=True),
field("relation_type", "关系类型", required=True, searchable=True),
field("target_entity_id", "目标实体 ID", "UUID", required=True, searchable=True),
field("properties", "关系属性", "JSONB", "json", visible=False, default_sql="'{}'::jsonb"),
field("status", "状态", default_sql="'active'", options=("active", "disabled")),
),
),
TableDefinition(
"reviews",
"真实评论",
"公共明细",
"酒店、美食等实体的真实用户评论。",
(
field("entity_id", "实体 ID", "UUID", required=True, searchable=True),
field("platform", "评论平台", searchable=True),
field("external_review_id", "平台评论 ID", searchable=True),
field("rating", "评分", "DOUBLE PRECISION", "number"),
field("reviewer_name", "用户名称", searchable=True),
field("content", "评论内容", "TEXT", "long_text", required=True, searchable=True, visible=False),
field("reviewed_at", "评论时间", "TIMESTAMPTZ", "datetime"),
),
),
TableDefinition(
"review_tags",
"评价标签",
"公共明细",
"用于评价摘要展示的标签及出现次数。",
(
field("entity_id", "实体 ID", "UUID", required=True, searchable=True),
field("tag_name", "标签", required=True, searchable=True),
field("mention_count", "出现次数", "INTEGER", "number", default_sql="0"),
field("sentiment", "倾向", options=("positive", "neutral", "negative")),
),
),
TableDefinition(
"hotel_profiles",
"酒店详情",
"酒店",
"酒店的携程名称、开业时间、客房数量、钻级和评分。",
(
field("entity_id", "实体 ID", "UUID", required=True, searchable=True),
field("ctrip_name", "携程酒店名", searchable=True),
field("opened_year", "开业年份", "INTEGER", "number"),
field("room_count", "客房数量", "INTEGER", "number"),
field("diamond_level", "酒店钻级", "INTEGER", "number"),
field("ctrip_rating", "携程评分", "DOUBLE PRECISION", "number"),
field("review_count", "用户点评数", "INTEGER", "number"),
field("reference_price", "参考起价", "NUMERIC(12,2)", "number"),
field("introduction", "酒店简介", "TEXT", "long_text", visible=False),
),
),
TableDefinition(
"hotel_room_types",
"酒店房型",
"酒店",
"一个房型一条记录,不保存实时库存文案。",
(
field("entity_id", "酒店实体 ID", "UUID", required=True, searchable=True),
field("room_name", "房型名称", required=True, searchable=True),
field("image_url", "房型图片", "TEXT", "url"),
field("bed_type", "床型", searchable=True),
field("area_text", "面积"),
field("floor_text", "楼层"),
field("window_text", "窗户"),
field("max_guests", "可住人数", "INTEGER", "number"),
field("breakfast", "早餐"),
field("cancellation_policy", "取消政策", "TEXT", "long_text", visible=False),
field("payment_method", "支付方式"),
field("reference_price", "参考价格", "NUMERIC(12,2)", "number"),
),
),
TableDefinition(
"hotel_facilities",
"酒店设施",
"酒店",
"酒店设施分类、是否免费、收费说明和来源链接。",
(
field("entity_id", "酒店实体 ID", "UUID", required=True, searchable=True),
field("facility_category", "设施分类", required=True, searchable=True),
field("facility_name", "设施名称", required=True, searchable=True),
field("is_free", "是否免费", "BOOLEAN", "boolean"),
field("charge_note", "收费说明"),
field("source_url", "来源 URL", "TEXT", "url"),
),
),
TableDefinition(
"hotel_policies",
"酒店政策",
"酒店",
"入住、退房、宠物、儿童及其他酒店政策。",
(
field("entity_id", "酒店实体 ID", "UUID", required=True, searchable=True),
field("policy_type", "政策类型", required=True, searchable=True),
field("policy_name", "政策名称", required=True, searchable=True),
field("policy_content", "政策内容", "TEXT", "long_text", required=True, visible=False),
),
),
TableDefinition(
"restaurant_profiles",
"美食详情",
"美食",
"大众点评店名、分类、评分、人均消费和营业信息。",
(
field("entity_id", "实体 ID", "UUID", required=True, searchable=True),
field("dianping_name", "大众点评店名", searchable=True),
field("dianping_category", "点评分类", searchable=True),
field("ranking_text", "榜单排名"),
field("business_status", "营业状态", options=("open", "closed", "unknown")),
field("business_hours", "营业时间"),
field("rating", "点评评分", "DOUBLE PRECISION", "number"),
field("review_count", "用户点评数", "INTEGER", "number"),
field("average_price", "人均消费", "NUMERIC(12,2)", "number"),
),
),
TableDefinition(
"restaurant_deals",
"美食团购",
"美食",
"团购套餐名称、图片、价格、折扣和使用规则。",
(
field("entity_id", "实体 ID", "UUID", required=True, searchable=True),
field("deal_name", "套餐名称", required=True, searchable=True),
field("image_url", "套餐图片", "TEXT", "url"),
field("current_price", "当前价格", "NUMERIC(12,2)", "number"),
field("original_price", "原价", "NUMERIC(12,2)", "number"),
field("discount_text", "折扣"),
field("usage_rules", "使用规则", "TEXT", "long_text", visible=False),
field("validity_text", "有效期"),
),
),
TableDefinition(
"scenic_profiles",
"景区详情",
"景区",
"景区等级、游客价值分类、开放时间和门票说明。",
(
field("entity_id", "实体 ID", "UUID", required=True, searchable=True),
field("scenic_type", "景区类型", searchable=True),
field("scenic_level", "景区等级", searchable=True),
field("is_national", "是否国家级", "BOOLEAN", "boolean"),
field("visitor_value_type", "游客价值分类", searchable=True),
field("opening_hours", "开放时间"),
field("ticket_note", "门票说明", "TEXT", "long_text", visible=False),
field("official_intro", "官方简介", "TEXT", "long_text", visible=False),
),
),
TableDefinition(
"scenic_children",
"景区子景点",
"景区",
"景区内部子景点、类型、坐标及游览说明。",
(
field("parent_entity_id", "所属景区实体 ID", "UUID", required=True, searchable=True),
field("name", "子景点名称", required=True, searchable=True),
field("child_type", "子景点类型", searchable=True),
field("longitude", "经度", "DOUBLE PRECISION", "number"),
field("latitude", "纬度", "DOUBLE PRECISION", "number"),
field("visit_note", "游览说明", "TEXT", "long_text", visible=False),
),
),
TableDefinition(
"transport_profiles",
"交通设施详情",
"交通",
"汽车站、客运站、火车站等交通设施信息。",
(
field("entity_id", "实体 ID", "UUID", required=True, searchable=True),
field("transport_type", "交通类型", required=True, searchable=True),
field("service_hours", "服务时间"),
field("route_note", "交通说明", "TEXT", "long_text", visible=False),
),
),
TableDefinition(
"bus_routes",
"公交线路",
"交通",
"公交线路名称、方向、运营时间及线路颜色。",
(
field("route_name", "线路名称", required=True, searchable=True),
field("direction_name", "方向", searchable=True),
field("start_stop_name", "起点站", searchable=True),
field("end_stop_name", "终点站", searchable=True),
field("service_hours", "运营时间"),
field("route_color", "线路颜色"),
field("geometry", "线路坐标", "JSONB", "json", visible=False, default_sql="'[]'::jsonb"),
),
),
TableDefinition(
"bus_route_stops",
"公交站序",
"交通",
"公交线路方向下的站点顺序。",
(
field("route_id", "线路 ID", "UUID", required=True, searchable=True),
field("stop_entity_id", "站点实体 ID", "UUID", required=True, searchable=True),
field("stop_name", "站点名称", required=True, searchable=True),
field("stop_order", "站序", "INTEGER", "number", required=True),
field("longitude", "经度", "DOUBLE PRECISION", "number"),
field("latitude", "纬度", "DOUBLE PRECISION", "number"),
),
),
)
TABLE_REGISTRY: dict[str, TableDefinition] = {table.code: table for table in TABLE_DEFINITIONS}