108 lines
4.1 KiB
Python
108 lines
4.1 KiB
Python
|
|
from sqlalchemy import text
|
||
|
|
from datetime import datetime
|
||
|
|
|
||
|
|
class StationProfile:
|
||
|
|
def __init__(self):
|
||
|
|
pass
|
||
|
|
|
||
|
|
async def backfill_address_if_missing(self, session, station_hash, station_name, address):
|
||
|
|
sql = """
|
||
|
|
UPDATE t_station_profile_scd
|
||
|
|
SET address = :address,
|
||
|
|
station_name = :station_name
|
||
|
|
WHERE station_hash = :station_hash
|
||
|
|
AND (address IS NULL OR address = '')
|
||
|
|
"""
|
||
|
|
result = await session.execute(text(sql), {
|
||
|
|
"station_hash": station_hash,
|
||
|
|
"station_name": station_name,
|
||
|
|
"address": address
|
||
|
|
})
|
||
|
|
try:
|
||
|
|
return int(result.rowcount or 0)
|
||
|
|
except Exception:
|
||
|
|
return 0
|
||
|
|
|
||
|
|
async def save(self, session, id, station_hash, operator, station_name, address=None, coord_x=None, coord_y=None, valid_start_time=None):
|
||
|
|
if valid_start_time is None:
|
||
|
|
valid_start_time = datetime.now()
|
||
|
|
|
||
|
|
# 1. Check current record
|
||
|
|
select_sql = """
|
||
|
|
SELECT operator, station_name, address, coord_x, coord_y
|
||
|
|
FROM t_station_profile_scd
|
||
|
|
WHERE station_hash = :station_hash AND is_current = 1
|
||
|
|
"""
|
||
|
|
result = await session.execute(text(select_sql), {"station_hash": station_hash})
|
||
|
|
current_row = result.fetchone()
|
||
|
|
|
||
|
|
if current_row:
|
||
|
|
if address is not None and address != "" and (current_row.address is None or current_row.address == ""):
|
||
|
|
await self.backfill_address_if_missing(
|
||
|
|
session=session,
|
||
|
|
station_hash=station_hash,
|
||
|
|
station_name=station_name,
|
||
|
|
address=address
|
||
|
|
)
|
||
|
|
return
|
||
|
|
|
||
|
|
# Merge logic: if new value is None, use old value
|
||
|
|
# But we must respect if new value is explicitly provided (even empty string?)
|
||
|
|
# Usually for crawler:
|
||
|
|
# - station_name: always updated
|
||
|
|
# - address: if new is None, use old.
|
||
|
|
# - coord: if new is None, use old.
|
||
|
|
|
||
|
|
merged_address = address if address is not None else current_row.address
|
||
|
|
merged_coord_x = coord_x if coord_x is not None else current_row.coord_x
|
||
|
|
merged_coord_y = coord_y if coord_y is not None else current_row.coord_y
|
||
|
|
|
||
|
|
# Use merged values for comparison and insertion
|
||
|
|
address = merged_address
|
||
|
|
coord_x = merged_coord_x
|
||
|
|
coord_y = merged_coord_y
|
||
|
|
|
||
|
|
# Check if changed
|
||
|
|
# Need to handle potential float/decimal diffs for coords if needed,
|
||
|
|
# but usually they are float in DB and float in python.
|
||
|
|
|
||
|
|
is_same = (
|
||
|
|
current_row.operator == operator and
|
||
|
|
current_row.station_name == station_name and
|
||
|
|
current_row.address == address and
|
||
|
|
current_row.coord_x == coord_x and
|
||
|
|
current_row.coord_y == coord_y
|
||
|
|
)
|
||
|
|
|
||
|
|
if is_same:
|
||
|
|
return
|
||
|
|
|
||
|
|
# Expire old record
|
||
|
|
update_sql = """
|
||
|
|
UPDATE t_station_profile_scd
|
||
|
|
SET is_current = 0, valid_end_time = :valid_start_time
|
||
|
|
WHERE station_hash = :station_hash AND is_current = 1
|
||
|
|
"""
|
||
|
|
await session.execute(text(update_sql), {
|
||
|
|
"valid_start_time": valid_start_time,
|
||
|
|
"station_hash": station_hash
|
||
|
|
})
|
||
|
|
|
||
|
|
# 2. Insert new record (with potentially merged values)
|
||
|
|
sql = """
|
||
|
|
INSERT INTO t_station_profile_scd
|
||
|
|
(id, station_hash, operator, station_name, address, coord_x, coord_y, valid_start_time, is_current)
|
||
|
|
VALUES
|
||
|
|
(:id, :station_hash, :operator, :station_name, :address, :coord_x, :coord_y, :valid_start_time, 1)
|
||
|
|
"""
|
||
|
|
await session.execute(text(sql), {
|
||
|
|
"id": id,
|
||
|
|
"station_hash": station_hash,
|
||
|
|
"operator": operator,
|
||
|
|
"station_name": station_name,
|
||
|
|
"address": address,
|
||
|
|
"coord_x": coord_x,
|
||
|
|
"coord_y": coord_y,
|
||
|
|
"valid_start_time": valid_start_time
|
||
|
|
})
|