feat: implement hybrid address system and premium search logic
- Added centralized, self-learning GeoService (ZIP, City, Street) - Implemented Hybrid Address Management (Centralized table + Denormalized fields) - Fixed Gamification logic (PointsLedger field names & filtering) - Added address autocomplete and two-tier (Free/Premium) search API - Synchronized UserStats and PointsLedger schemas
This commit is contained in:
66
backend/app/services/geo_service.py
Normal file
66
backend/app/services/geo_service.py
Normal file
@@ -0,0 +1,66 @@
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy import text
|
||||
from typing import Optional, List
|
||||
import uuid
|
||||
|
||||
class GeoService:
|
||||
@staticmethod
|
||||
async def get_street_suggestions(db: AsyncSession, zip_code: str, q: str) -> List[str]:
|
||||
"""Azonnali utca-kiegészítés (Autocomplete) támogatása."""
|
||||
query = text("""
|
||||
SELECT s.name
|
||||
FROM data.geo_streets s
|
||||
JOIN data.geo_postal_codes p ON s.postal_code_id = p.id
|
||||
WHERE p.zip_code = :zip AND s.name ILIKE :q
|
||||
ORDER BY s.name ASC LIMIT 10
|
||||
""")
|
||||
res = await db.execute(query, {"zip": zip_code, "q": f"{q}%"})
|
||||
return [row[0] for row in res.fetchall()]
|
||||
|
||||
@staticmethod
|
||||
async def get_or_create_full_address(
|
||||
db: AsyncSession,
|
||||
zip_code: str, city: str, street_name: str,
|
||||
street_type: str, house_number: str,
|
||||
parcel_id: Optional[str] = None
|
||||
) -> uuid.UUID:
|
||||
"""Hibrid címrögzítés: ellenőrzi a szótárakat és létrehozza a központi címet."""
|
||||
# 1. Zip/City szótár frissítése (Auto-learning)
|
||||
zip_id_res = await db.execute(text("""
|
||||
INSERT INTO data.geo_postal_codes (zip_code, city) VALUES (:z, :c)
|
||||
ON CONFLICT (country_code, zip_code, city) DO UPDATE SET city = EXCLUDED.city
|
||||
RETURNING id
|
||||
"""), {"z": zip_code, "c": city})
|
||||
zip_id = zip_id_res.scalar()
|
||||
|
||||
# 2. Utca szótár frissítése (Auto-learning)
|
||||
await db.execute(text("""
|
||||
INSERT INTO data.geo_streets (postal_code_id, name) VALUES (:zid, :n)
|
||||
ON CONFLICT (postal_code_id, name) DO NOTHING
|
||||
"""), {"zid": zip_id, "n": street_name})
|
||||
|
||||
# 3. Közterület típus (út, utca...) szótár
|
||||
await db.execute(text("""
|
||||
INSERT INTO data.geo_street_types (name) VALUES (:n) ON CONFLICT DO NOTHING
|
||||
"""), {"n": street_type.lower()})
|
||||
|
||||
# 4. Központi Address rekord rögzítése
|
||||
full_text = f"{zip_code} {city}, {street_name} {street_type} {house_number}"
|
||||
addr_res = await db.execute(text("""
|
||||
INSERT INTO data.addresses (postal_code_id, street_name, street_type, house_number, parcel_id, full_address_text)
|
||||
VALUES (:zid, :sn, :st, :hn, :pid, :txt)
|
||||
ON CONFLICT DO NOTHING
|
||||
RETURNING id
|
||||
"""), {
|
||||
"zid": zip_id, "sn": street_name, "st": street_type, "hn": house_number, "pid": parcel_id, "txt": full_text
|
||||
})
|
||||
addr_id = addr_res.scalar()
|
||||
|
||||
if not addr_id:
|
||||
# Ha már létezett, lekérjük az azonosítót
|
||||
addr_id = (await db.execute(text("""
|
||||
SELECT id FROM data.addresses
|
||||
WHERE postal_code_id = :zid AND street_name = :sn AND street_type = :st AND house_number = :hn
|
||||
"""), {"zid": zip_id, "sn": street_name, "st": street_type, "hn": house_number})).scalar()
|
||||
|
||||
return addr_id
|
||||
Reference in New Issue
Block a user