feat(22begh): schema extension — flats+6 / objects+30 / developers+4 / metro_top3
SQL migration 112: ADD COLUMN IF NOT EXISTS для trёх таблиц (idempotent). Scraper: _norm_flat section_no, _norm_object metro/freeFlatsInfo/dev_group_name, UPSERT SQL расширены с COALESCE ON CONFLICT для всех новых полей. CAST(:metro_top3 AS jsonb) — canonical psycopg3 bind для jsonb. Поля catalog scraper 22d проставлены NULL-заглушками для будущего COALESCE. Closes #297
This commit is contained in:
parent
16e3d5c86d
commit
c67de26cd0
2 changed files with 377 additions and 8 deletions
|
|
@ -186,15 +186,25 @@ def _extract_list(payload: dict[str, Any]) -> list[dict[str, Any]]:
|
|||
def _norm_object(row: dict[str, Any], region_cd: int | None = None) -> dict[str, Any]:
|
||||
"""Map naш.дом.рф /kn/object row → domrf_kn_objects column dict.
|
||||
|
||||
Real API field names:
|
||||
Real API field names (confirmed via payload audit 2026-05-17, obj=65136):
|
||||
objId, hobjId, developer{devId, shortName, fullName, groupName, companyGroup, devInn},
|
||||
rpdRegionCd, objAddr, shortAddr, objCommercNm, objFloorMin, objFloorMax,
|
||||
objElemLivingCnt, objSquareLiving, objReady100PercDt, objClass, latitude, longitude,
|
||||
objProblemFlg, problemFlag, siteStatus, objGreenHouseFlg, objGuarantyEscrowFlg,
|
||||
objStatus, aiDescription, freeFlatsInfo{priceMin, numberFlats}.
|
||||
objStatus, aiDescription, freeFlatsInfo{priceMin, numberFlats},
|
||||
residentialBuildings (section_count), rpdNum (project_declaration_num),
|
||||
objPublDt (project_published_at), metro{name, time, line, color, colors, isWalk, id}.
|
||||
|
||||
Note: DOM.РФ /kn/object list endpoint never populates `objClass` in API responses
|
||||
(field absent from payload). Class is extracted from `aiDescription` text as fallback.
|
||||
|
||||
22e fields NOT in kn-API list payload (remain NULL until catalog scraper 22d):
|
||||
first_floor_type, elevators_passenger/cargo_count, parking_total_slots,
|
||||
guest_parking_inside/outside_count, ceiling_height_m, finishing_variants_count,
|
||||
has_free_planning, playground_kids/sport_count, has_bike_paths, trash_areas_count,
|
||||
has_ramp, has_low_platforms, has_wheelchair_lift, flat_area_min/max,
|
||||
price_max_rub, price_per_m2_min/max, parking_provision_pct, avg_flat_area_m2,
|
||||
domrf_score_location/transport/infrastructure.
|
||||
"""
|
||||
dev = row.get("developer") if isinstance(row.get("developer"), dict) else {}
|
||||
company_group = _g(dev, "companyGroup") if dev else None
|
||||
|
|
@ -210,6 +220,34 @@ def _norm_object(row: dict[str, Any], region_cd: int | None = None) -> dict[str,
|
|||
obj_id,
|
||||
)
|
||||
|
||||
# Metro: kn-API returns a single metro object (nearest station).
|
||||
# Stored as metro_top3 JSON array (single element) for future multi-station extension.
|
||||
metro_raw = row.get("metro")
|
||||
metro_nearest_name: str | None = None
|
||||
metro_nearest_walk_minutes: int | None = None
|
||||
metro_top3: list[dict[str, Any]] | None = None
|
||||
if isinstance(metro_raw, dict) and metro_raw.get("name"):
|
||||
metro_nearest_name = metro_raw.get("name")
|
||||
raw_time = metro_raw.get("time")
|
||||
if raw_time is not None:
|
||||
try:
|
||||
metro_nearest_walk_minutes = round(float(raw_time))
|
||||
except (TypeError, ValueError):
|
||||
pass
|
||||
metro_top3 = [
|
||||
{
|
||||
"name": metro_raw.get("name"),
|
||||
"time": raw_time,
|
||||
"line": metro_raw.get("line"),
|
||||
"color": metro_raw.get("color"),
|
||||
"isWalk": metro_raw.get("isWalk"),
|
||||
}
|
||||
]
|
||||
|
||||
# freeFlatsInfo.priceMin — price of cheapest available flat in the object
|
||||
free_info = row.get("freeFlatsInfo") if isinstance(row.get("freeFlatsInfo"), dict) else {}
|
||||
price_min_rub = _g(free_info, "priceMin") if free_info else None
|
||||
|
||||
return {
|
||||
"obj_id": _g(row, "objId", "obj_id", "id"),
|
||||
"hobj_id": _g(row, "hobjId", "hobj_id"),
|
||||
|
|
@ -235,6 +273,43 @@ def _norm_object(row: dict[str, Any], region_cd: int | None = None) -> dict[str,
|
|||
"latitude": _g(row, "latitude"),
|
||||
"longitude": _g(row, "longitude"),
|
||||
"obj_status": _g(row, "objStatus"),
|
||||
# 22e: fields mappable from kn-API list payload
|
||||
"section_count": _g(row, "residentialBuildings"),
|
||||
"project_declaration_num": _g(row, "rpdNum"),
|
||||
"project_published_at": _to_date(_g(row, "objPublDt")),
|
||||
"price_min_rub": price_min_rub,
|
||||
"dev_group_name": _g(dev, "groupName"),
|
||||
# 22e + 22h: metro (nearest station from kn-API, single object)
|
||||
"metro_nearest_name": metro_nearest_name,
|
||||
"metro_nearest_walk_minutes": metro_nearest_walk_minutes,
|
||||
"metro_top3": json.dumps(metro_top3, ensure_ascii=False) if metro_top3 else None,
|
||||
# 22e: fields NOT in kn-API list payload — filled by catalog scraper (22d)
|
||||
"first_floor_type": None,
|
||||
"elevators_passenger_count": None,
|
||||
"elevators_cargo_count": None,
|
||||
"parking_total_slots": None,
|
||||
"guest_parking_inside_count": None,
|
||||
"guest_parking_outside_count": None,
|
||||
"ceiling_height_m": None,
|
||||
"finishing_variants_count": None,
|
||||
"has_free_planning": None,
|
||||
"avg_flat_area_m2": None,
|
||||
"playground_kids_count": None,
|
||||
"playground_sport_count": None,
|
||||
"has_bike_paths": None,
|
||||
"trash_areas_count": None,
|
||||
"has_ramp": None,
|
||||
"has_low_platforms": None,
|
||||
"has_wheelchair_lift": None,
|
||||
"flat_area_min": None,
|
||||
"flat_area_max": None,
|
||||
"price_max_rub": None,
|
||||
"price_per_m2_min": None,
|
||||
"price_per_m2_max": None,
|
||||
"parking_provision_pct": None,
|
||||
"domrf_score_location": None,
|
||||
"domrf_score_transport": None,
|
||||
"domrf_score_infrastructure": None,
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -308,6 +383,13 @@ def _norm_flat(row: dict[str, Any], region_cd: int | None) -> dict[str, Any]:
|
|||
"city": _g(row, "city"),
|
||||
"region_cd": region_cd,
|
||||
"obj_name": _g(row, "objName") or _g(row.get("objInfo") or {}, "objCommercNm"),
|
||||
# 22b: новые поля квартиры
|
||||
"section_no": _g(row, "_entrance"), # entranceNumber injected by _flatten_table
|
||||
"finishing_type": None, # заполнит catalog scraper 22d
|
||||
"ceiling_height_m": None, # заполнит catalog scraper 22d
|
||||
"key_handover_dt": None, # заполнит catalog scraper 22d
|
||||
"catalog_updated_at": None, # заполнит catalog scraper 22d
|
||||
"catalog_url_hash": None, # заполнит catalog scraper 22d
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -321,14 +403,38 @@ UPSERT_OBJECT_SQL = text(
|
|||
floor_min, floor_max, flat_count, square_living, ready_dt,
|
||||
problem_flag, site_status, green_house, escrow,
|
||||
obj_class, wall_type, energy_eff,
|
||||
latitude, longitude, obj_status, snapshot_date
|
||||
latitude, longitude, obj_status,
|
||||
section_count, project_declaration_num, project_published_at,
|
||||
price_min_rub, dev_group_name,
|
||||
metro_nearest_name, metro_nearest_walk_minutes, metro_top3,
|
||||
first_floor_type, elevators_passenger_count, elevators_cargo_count,
|
||||
parking_total_slots, guest_parking_inside_count, guest_parking_outside_count,
|
||||
ceiling_height_m, finishing_variants_count, has_free_planning, avg_flat_area_m2,
|
||||
playground_kids_count, playground_sport_count, has_bike_paths, trash_areas_count,
|
||||
has_ramp, has_low_platforms, has_wheelchair_lift,
|
||||
flat_area_min, flat_area_max, price_max_rub, price_per_m2_min, price_per_m2_max,
|
||||
parking_provision_pct, domrf_score_location, domrf_score_transport,
|
||||
domrf_score_infrastructure,
|
||||
snapshot_date
|
||||
) VALUES (
|
||||
:obj_id, :hobj_id, :comm_name, :addr, :short_addr, :region_cd,
|
||||
:dev_id, :dev_name, :dev_inn,
|
||||
:floor_min, :floor_max, :flat_count, :square_living, :ready_dt,
|
||||
:problem_flag, :site_status, :green_house, :escrow,
|
||||
:obj_class, :wall_type, :energy_eff,
|
||||
:latitude, :longitude, :obj_status, :snapshot_date
|
||||
:latitude, :longitude, :obj_status,
|
||||
:section_count, :project_declaration_num, :project_published_at,
|
||||
:price_min_rub, :dev_group_name,
|
||||
:metro_nearest_name, :metro_nearest_walk_minutes, CAST(:metro_top3 AS jsonb),
|
||||
:first_floor_type, :elevators_passenger_count, :elevators_cargo_count,
|
||||
:parking_total_slots, :guest_parking_inside_count, :guest_parking_outside_count,
|
||||
:ceiling_height_m, :finishing_variants_count, :has_free_planning, :avg_flat_area_m2,
|
||||
:playground_kids_count, :playground_sport_count, :has_bike_paths, :trash_areas_count,
|
||||
:has_ramp, :has_low_platforms, :has_wheelchair_lift,
|
||||
:flat_area_min, :flat_area_max, :price_max_rub, :price_per_m2_min, :price_per_m2_max,
|
||||
:parking_provision_pct, :domrf_score_location, :domrf_score_transport,
|
||||
:domrf_score_infrastructure,
|
||||
:snapshot_date
|
||||
)
|
||||
ON CONFLICT (obj_id, snapshot_date) DO UPDATE SET
|
||||
comm_name = EXCLUDED.comm_name,
|
||||
|
|
@ -345,7 +451,91 @@ UPSERT_OBJECT_SQL = text(
|
|||
energy_eff = COALESCE(EXCLUDED.energy_eff, domrf_kn_objects.energy_eff),
|
||||
latitude = EXCLUDED.latitude,
|
||||
longitude = EXCLUDED.longitude,
|
||||
obj_status = EXCLUDED.obj_status
|
||||
obj_status = EXCLUDED.obj_status,
|
||||
section_count = COALESCE(EXCLUDED.section_count, domrf_kn_objects.section_count),
|
||||
project_declaration_num = COALESCE(
|
||||
EXCLUDED.project_declaration_num, domrf_kn_objects.project_declaration_num
|
||||
),
|
||||
project_published_at = COALESCE(
|
||||
EXCLUDED.project_published_at, domrf_kn_objects.project_published_at
|
||||
),
|
||||
price_min_rub = EXCLUDED.price_min_rub,
|
||||
dev_group_name = COALESCE(EXCLUDED.dev_group_name, domrf_kn_objects.dev_group_name),
|
||||
metro_nearest_name = COALESCE(
|
||||
EXCLUDED.metro_nearest_name, domrf_kn_objects.metro_nearest_name
|
||||
),
|
||||
metro_nearest_walk_minutes = COALESCE(
|
||||
EXCLUDED.metro_nearest_walk_minutes, domrf_kn_objects.metro_nearest_walk_minutes
|
||||
),
|
||||
metro_top3 = COALESCE(EXCLUDED.metro_top3, domrf_kn_objects.metro_top3),
|
||||
first_floor_type = COALESCE(
|
||||
EXCLUDED.first_floor_type, domrf_kn_objects.first_floor_type
|
||||
),
|
||||
elevators_passenger_count = COALESCE(
|
||||
EXCLUDED.elevators_passenger_count, domrf_kn_objects.elevators_passenger_count
|
||||
),
|
||||
elevators_cargo_count = COALESCE(
|
||||
EXCLUDED.elevators_cargo_count, domrf_kn_objects.elevators_cargo_count
|
||||
),
|
||||
parking_total_slots = COALESCE(
|
||||
EXCLUDED.parking_total_slots, domrf_kn_objects.parking_total_slots
|
||||
),
|
||||
guest_parking_inside_count = COALESCE(
|
||||
EXCLUDED.guest_parking_inside_count, domrf_kn_objects.guest_parking_inside_count
|
||||
),
|
||||
guest_parking_outside_count = COALESCE(
|
||||
EXCLUDED.guest_parking_outside_count, domrf_kn_objects.guest_parking_outside_count
|
||||
),
|
||||
ceiling_height_m = COALESCE(
|
||||
EXCLUDED.ceiling_height_m, domrf_kn_objects.ceiling_height_m
|
||||
),
|
||||
finishing_variants_count = COALESCE(
|
||||
EXCLUDED.finishing_variants_count, domrf_kn_objects.finishing_variants_count
|
||||
),
|
||||
has_free_planning = COALESCE(
|
||||
EXCLUDED.has_free_planning, domrf_kn_objects.has_free_planning
|
||||
),
|
||||
avg_flat_area_m2 = COALESCE(
|
||||
EXCLUDED.avg_flat_area_m2, domrf_kn_objects.avg_flat_area_m2
|
||||
),
|
||||
playground_kids_count = COALESCE(
|
||||
EXCLUDED.playground_kids_count, domrf_kn_objects.playground_kids_count
|
||||
),
|
||||
playground_sport_count = COALESCE(
|
||||
EXCLUDED.playground_sport_count, domrf_kn_objects.playground_sport_count
|
||||
),
|
||||
has_bike_paths = COALESCE(EXCLUDED.has_bike_paths, domrf_kn_objects.has_bike_paths),
|
||||
trash_areas_count = COALESCE(
|
||||
EXCLUDED.trash_areas_count, domrf_kn_objects.trash_areas_count
|
||||
),
|
||||
has_ramp = COALESCE(EXCLUDED.has_ramp, domrf_kn_objects.has_ramp),
|
||||
has_low_platforms = COALESCE(
|
||||
EXCLUDED.has_low_platforms, domrf_kn_objects.has_low_platforms
|
||||
),
|
||||
has_wheelchair_lift = COALESCE(
|
||||
EXCLUDED.has_wheelchair_lift, domrf_kn_objects.has_wheelchair_lift
|
||||
),
|
||||
flat_area_min = COALESCE(EXCLUDED.flat_area_min, domrf_kn_objects.flat_area_min),
|
||||
flat_area_max = COALESCE(EXCLUDED.flat_area_max, domrf_kn_objects.flat_area_max),
|
||||
price_max_rub = COALESCE(EXCLUDED.price_max_rub, domrf_kn_objects.price_max_rub),
|
||||
price_per_m2_min = COALESCE(
|
||||
EXCLUDED.price_per_m2_min, domrf_kn_objects.price_per_m2_min
|
||||
),
|
||||
price_per_m2_max = COALESCE(
|
||||
EXCLUDED.price_per_m2_max, domrf_kn_objects.price_per_m2_max
|
||||
),
|
||||
parking_provision_pct = COALESCE(
|
||||
EXCLUDED.parking_provision_pct, domrf_kn_objects.parking_provision_pct
|
||||
),
|
||||
domrf_score_location = COALESCE(
|
||||
EXCLUDED.domrf_score_location, domrf_kn_objects.domrf_score_location
|
||||
),
|
||||
domrf_score_transport = COALESCE(
|
||||
EXCLUDED.domrf_score_transport, domrf_kn_objects.domrf_score_transport
|
||||
),
|
||||
domrf_score_infrastructure = COALESCE(
|
||||
EXCLUDED.domrf_score_infrastructure, domrf_kn_objects.domrf_score_infrastructure
|
||||
)
|
||||
"""
|
||||
)
|
||||
|
||||
|
|
@ -354,11 +544,17 @@ UPSERT_FLAT_SQL = text(
|
|||
INSERT INTO domrf_kn_flats (
|
||||
id, ods_id, flat_type, flat_number, is_studio, total_area, living_area,
|
||||
rooms, status, price_rub, price_per_m2, floor, num_floors, obj_id,
|
||||
city, region_cd, obj_name, snapshot_date
|
||||
city, region_cd, obj_name,
|
||||
section_no, finishing_type, ceiling_height_m,
|
||||
key_handover_dt, catalog_updated_at, catalog_url_hash,
|
||||
snapshot_date
|
||||
) VALUES (
|
||||
:id, :ods_id, :flat_type, :flat_number, :is_studio, :total_area, :living_area,
|
||||
:rooms, :status, :price_rub, :price_per_m2, :floor, :num_floors, :obj_id,
|
||||
:city, :region_cd, :obj_name, :snapshot_date
|
||||
:city, :region_cd, :obj_name,
|
||||
:section_no, :finishing_type, :ceiling_height_m,
|
||||
:key_handover_dt, :catalog_updated_at, :catalog_url_hash,
|
||||
:snapshot_date
|
||||
)
|
||||
ON CONFLICT (id, snapshot_date) DO UPDATE SET
|
||||
status = EXCLUDED.status,
|
||||
|
|
@ -373,7 +569,19 @@ UPSERT_FLAT_SQL = text(
|
|||
total_area = COALESCE(EXCLUDED.total_area, domrf_kn_flats.total_area),
|
||||
rooms = COALESCE(EXCLUDED.rooms, domrf_kn_flats.rooms),
|
||||
floor = COALESCE(EXCLUDED.floor, domrf_kn_flats.floor),
|
||||
num_floors = COALESCE(EXCLUDED.num_floors, domrf_kn_flats.num_floors)
|
||||
num_floors = COALESCE(EXCLUDED.num_floors, domrf_kn_flats.num_floors),
|
||||
section_no = COALESCE(EXCLUDED.section_no, domrf_kn_flats.section_no),
|
||||
finishing_type = COALESCE(EXCLUDED.finishing_type, domrf_kn_flats.finishing_type),
|
||||
ceiling_height_m = COALESCE(
|
||||
EXCLUDED.ceiling_height_m, domrf_kn_flats.ceiling_height_m
|
||||
),
|
||||
key_handover_dt = COALESCE(EXCLUDED.key_handover_dt, domrf_kn_flats.key_handover_dt),
|
||||
catalog_updated_at = COALESCE(
|
||||
EXCLUDED.catalog_updated_at, domrf_kn_flats.catalog_updated_at
|
||||
),
|
||||
catalog_url_hash = COALESCE(
|
||||
EXCLUDED.catalog_url_hash, domrf_kn_flats.catalog_url_hash
|
||||
)
|
||||
"""
|
||||
)
|
||||
|
||||
|
|
|
|||
161
data/sql/112_22begh_kn_schema_extension.sql
Normal file
161
data/sql/112_22begh_kn_schema_extension.sql
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
-- Migration 112: schema extension for issues #297 sub-tasks 22b + 22e + 22g + 22h
|
||||
-- Adds 6 flat-level cols, 30 object-level cols (incl. metro_top3), 4 developer metrics.
|
||||
--
|
||||
-- Payload audit (obj=65136, 2026-05-17):
|
||||
-- kn_api payload keys: objId, hobjId, objCommercNm, objAddr, shortAddr, rpdRegionCd,
|
||||
-- developer{devId,devInn,orgForm,fullName,groupName,shortName,companyGroup},
|
||||
-- rpdNum, objPublDt, objStatus, siteStatus, objFloorMax, objFloorMin, objPriceAVG,
|
||||
-- problemFlag, rpdRegionCd, objSquareLiving, objElemLivingCnt, objGreenHouseFlg,
|
||||
-- objGuarantyEscrowFlg, objReady100PercDt, hobjRenderPhotoUrl, aiDescription,
|
||||
-- freeFlatsInfo{priceMin, numberFlats}, residentialBuildings,
|
||||
-- metro{id, line, name, time, color, colors, isWalk}, latitude, longitude, pdId, buildType.
|
||||
--
|
||||
-- flat-level (portal/table): flatId, odsId, elemId, type, number, isStudio,
|
||||
-- totalArea, livingArea, rooms, status, price, pricePerSquareMeter, numberFloors,
|
||||
-- _objId(injected), _floor(injected), _entrance(injected as entranceNumber).
|
||||
--
|
||||
-- Fields that map NOW (from existing kn-API payload):
|
||||
-- 22b: section_no (from _entrance/entranceNumber injected by _flatten_table)
|
||||
-- 22e: section_count (residentialBuildings), project_declaration_num (rpdNum),
|
||||
-- project_published_at (objPublDt), metro_nearest_name + metro_nearest_walk_minutes
|
||||
-- (metro.name + metro.time), metro_top3 (metro wrapped as single-element array),
|
||||
-- dev_group_name (developer.groupName), price_min_rub (freeFlatsInfo.priceMin)
|
||||
--
|
||||
-- Fields remaining NULL until catalog scraper 22d:
|
||||
-- finishing_type, ceiling_height_m (flat), key_handover_dt, catalog_updated_at,
|
||||
-- catalog_url_hash, first_floor_type, elevators_passenger_count, elevators_cargo_count,
|
||||
-- parking_total_slots, guest_parking_inside_count, guest_parking_outside_count,
|
||||
-- ceiling_height_m (obj), finishing_variants_count, has_free_planning,
|
||||
-- playground_kids_count, playground_sport_count, has_bike_paths, trash_areas_count,
|
||||
-- has_ramp, has_low_platforms, has_wheelchair_lift, flat_area_min, flat_area_max,
|
||||
-- price_max_rub, price_per_m2_min, price_per_m2_max, parking_provision_pct,
|
||||
-- avg_flat_area_m2, domrf_score_location, domrf_score_transport,
|
||||
-- domrf_score_infrastructure, houses_building, houses_building_delayed,
|
||||
-- houses_delivered, houses_delivered_delayed.
|
||||
|
||||
BEGIN;
|
||||
|
||||
-- ─────────────────────────────────────────────────────────────────────────────
|
||||
-- 22b — domrf_kn_flats +6 columns
|
||||
-- ─────────────────────────────────────────────────────────────────────────────
|
||||
COMMENT ON TABLE domrf_kn_flats IS 'Per-flat catalogue from DOM.RF kn-API portal/table endpoint';
|
||||
|
||||
ALTER TABLE domrf_kn_flats
|
||||
ADD COLUMN IF NOT EXISTS section_no int,
|
||||
ADD COLUMN IF NOT EXISTS finishing_type text,
|
||||
ADD COLUMN IF NOT EXISTS ceiling_height_m numeric(3,2),
|
||||
ADD COLUMN IF NOT EXISTS key_handover_dt date,
|
||||
ADD COLUMN IF NOT EXISTS catalog_updated_at date,
|
||||
ADD COLUMN IF NOT EXISTS catalog_url_hash text;
|
||||
|
||||
COMMENT ON COLUMN domrf_kn_flats.section_no IS '22b: подъезд из entrance.entranceNumber (portal/table)';
|
||||
COMMENT ON COLUMN domrf_kn_flats.finishing_type IS '22b/22d: тип отделки — заполнит catalog scraper (22d)';
|
||||
COMMENT ON COLUMN domrf_kn_flats.ceiling_height_m IS '22b/22d: высота потолков — заполнит catalog scraper (22d)';
|
||||
COMMENT ON COLUMN domrf_kn_flats.key_handover_dt IS '22b/22d: дата выдачи ключей — заполнит catalog scraper (22d)';
|
||||
COMMENT ON COLUMN domrf_kn_flats.catalog_updated_at IS '22b/22d: дата обновления инфо на catalog-странице (22d)';
|
||||
COMMENT ON COLUMN domrf_kn_flats.catalog_url_hash IS '22b/22d: hash-часть URL квартиры на каталоге dom.rf (22d)';
|
||||
|
||||
-- ─────────────────────────────────────────────────────────────────────────────
|
||||
-- 22e + 22h — domrf_kn_objects +30 columns (incl. metro_top3)
|
||||
-- ─────────────────────────────────────────────────────────────────────────────
|
||||
COMMENT ON TABLE domrf_kn_objects IS 'Per-object (ЖК) catalogue from DOM.RF kn-API list endpoint';
|
||||
|
||||
-- Building specs (8)
|
||||
ALTER TABLE domrf_kn_objects
|
||||
ADD COLUMN IF NOT EXISTS first_floor_type text,
|
||||
ADD COLUMN IF NOT EXISTS section_count int,
|
||||
ADD COLUMN IF NOT EXISTS elevators_passenger_count int,
|
||||
ADD COLUMN IF NOT EXISTS elevators_cargo_count int,
|
||||
ADD COLUMN IF NOT EXISTS parking_total_slots int,
|
||||
ADD COLUMN IF NOT EXISTS guest_parking_inside_count int,
|
||||
ADD COLUMN IF NOT EXISTS guest_parking_outside_count int,
|
||||
ADD COLUMN IF NOT EXISTS ceiling_height_m numeric(3,2);
|
||||
|
||||
-- Apartment summary (3)
|
||||
ALTER TABLE domrf_kn_objects
|
||||
ADD COLUMN IF NOT EXISTS finishing_variants_count int,
|
||||
ADD COLUMN IF NOT EXISTS has_free_planning bool,
|
||||
ADD COLUMN IF NOT EXISTS avg_flat_area_m2 numeric(5,1);
|
||||
|
||||
-- Yard infrastructure (4)
|
||||
ALTER TABLE domrf_kn_objects
|
||||
ADD COLUMN IF NOT EXISTS playground_kids_count int,
|
||||
ADD COLUMN IF NOT EXISTS playground_sport_count int,
|
||||
ADD COLUMN IF NOT EXISTS has_bike_paths bool,
|
||||
ADD COLUMN IF NOT EXISTS trash_areas_count int;
|
||||
|
||||
-- Accessibility / OVZ (3)
|
||||
ALTER TABLE domrf_kn_objects
|
||||
ADD COLUMN IF NOT EXISTS has_ramp bool,
|
||||
ADD COLUMN IF NOT EXISTS has_low_platforms bool,
|
||||
ADD COLUMN IF NOT EXISTS has_wheelchair_lift bool;
|
||||
|
||||
-- Catalog / UI (9)
|
||||
ALTER TABLE domrf_kn_objects
|
||||
ADD COLUMN IF NOT EXISTS flat_area_min numeric(8,2),
|
||||
ADD COLUMN IF NOT EXISTS flat_area_max numeric(8,2),
|
||||
ADD COLUMN IF NOT EXISTS price_min_rub bigint,
|
||||
ADD COLUMN IF NOT EXISTS price_max_rub bigint,
|
||||
ADD COLUMN IF NOT EXISTS price_per_m2_min numeric(12,2),
|
||||
ADD COLUMN IF NOT EXISTS price_per_m2_max numeric(12,2),
|
||||
ADD COLUMN IF NOT EXISTS parking_provision_pct numeric(5,1),
|
||||
ADD COLUMN IF NOT EXISTS project_published_at date,
|
||||
ADD COLUMN IF NOT EXISTS project_declaration_num text;
|
||||
|
||||
-- Metro & scores (5) — 22h merged into 22e
|
||||
ALTER TABLE domrf_kn_objects
|
||||
ADD COLUMN IF NOT EXISTS metro_nearest_name text,
|
||||
ADD COLUMN IF NOT EXISTS metro_nearest_walk_minutes int,
|
||||
ADD COLUMN IF NOT EXISTS metro_top3 jsonb,
|
||||
ADD COLUMN IF NOT EXISTS domrf_score_location int,
|
||||
ADD COLUMN IF NOT EXISTS domrf_score_transport int,
|
||||
ADD COLUMN IF NOT EXISTS domrf_score_infrastructure int;
|
||||
|
||||
-- Developer split (1)
|
||||
ALTER TABLE domrf_kn_objects
|
||||
ADD COLUMN IF NOT EXISTS dev_group_name text;
|
||||
|
||||
COMMENT ON COLUMN domrf_kn_objects.section_count
|
||||
IS '22e: подъезды (residentialBuildings из kn-API)';
|
||||
COMMENT ON COLUMN domrf_kn_objects.project_published_at
|
||||
IS '22e: дата публикации проекта (objPublDt из kn-API)';
|
||||
COMMENT ON COLUMN domrf_kn_objects.project_declaration_num
|
||||
IS '22e: номер проектной декларации (rpdNum из kn-API)';
|
||||
COMMENT ON COLUMN domrf_kn_objects.price_min_rub
|
||||
IS '22e: минимальная цена (freeFlatsInfo.priceMin из kn-API)';
|
||||
COMMENT ON COLUMN domrf_kn_objects.metro_nearest_name
|
||||
IS '22h: ближайшая станция метро (metro.name из kn-API)';
|
||||
COMMENT ON COLUMN domrf_kn_objects.metro_nearest_walk_minutes
|
||||
IS '22h: время пешком до метро, мин (metro.time из kn-API, rounded)';
|
||||
COMMENT ON COLUMN domrf_kn_objects.metro_top3
|
||||
IS '22h: топ-3 ближайших станций [{name,time,line,color,isWalk}], сейчас 1 элемент';
|
||||
COMMENT ON COLUMN domrf_kn_objects.dev_group_name
|
||||
IS '22e: группа компаний (developer.groupName из kn-API)';
|
||||
COMMENT ON COLUMN domrf_kn_objects.domrf_score_location
|
||||
IS '22e: оценка расположения от DOM.RF (catalog 22d)';
|
||||
COMMENT ON COLUMN domrf_kn_objects.domrf_score_transport
|
||||
IS '22e: оценка транспорта от DOM.RF (catalog 22d)';
|
||||
COMMENT ON COLUMN domrf_kn_objects.domrf_score_infrastructure
|
||||
IS '22e: оценка инфраструктуры от DOM.RF (catalog 22d)';
|
||||
|
||||
-- ─────────────────────────────────────────────────────────────────────────────
|
||||
-- 22g — domrf_developers +4 metrics
|
||||
-- ─────────────────────────────────────────────────────────────────────────────
|
||||
COMMENT ON TABLE domrf_developers IS 'Застройщики DOM.RF (companyGroup-level)';
|
||||
|
||||
ALTER TABLE domrf_developers
|
||||
ADD COLUMN IF NOT EXISTS houses_building int,
|
||||
ADD COLUMN IF NOT EXISTS houses_building_delayed int,
|
||||
ADD COLUMN IF NOT EXISTS houses_delivered int,
|
||||
ADD COLUMN IF NOT EXISTS houses_delivered_delayed int;
|
||||
|
||||
COMMENT ON COLUMN domrf_developers.houses_building
|
||||
IS '22g: домов строится (из карточки застройщика, catalog 22d)';
|
||||
COMMENT ON COLUMN domrf_developers.houses_building_delayed
|
||||
IS '22g: строится с задержкой';
|
||||
COMMENT ON COLUMN domrf_developers.houses_delivered
|
||||
IS '22g: сдано домов';
|
||||
COMMENT ON COLUMN domrf_developers.houses_delivered_delayed
|
||||
IS '22g: сдано с задержкой';
|
||||
|
||||
COMMIT;
|
||||
Loading…
Add table
Reference in a new issue