feat: add import templates
This commit is contained in:
@@ -5,12 +5,20 @@ import sqlite3
|
||||
from pathlib import Path
|
||||
from typing import Iterable, Mapping, Union
|
||||
|
||||
from .import_templates import ImportTemplateError, load_tabular_rows, validate_import_rows
|
||||
|
||||
|
||||
PROJECT_ROOT = Path(__file__).resolve().parents[2]
|
||||
DEFAULT_DB_PATH = PROJECT_ROOT / "data" / "shanghai_housing.sqlite"
|
||||
SCHEMA_PATH = Path(__file__).with_name("schema.sql")
|
||||
SAMPLE_DIR = PROJECT_ROOT / "data" / "sample"
|
||||
|
||||
SQLITE_IMPORT_TABLES = {
|
||||
"area_monthly_metrics": "area_monthly_metrics",
|
||||
"neighborhood_monthly_metrics": "neighborhood_monthly_metrics",
|
||||
"policy_events": "policy_events",
|
||||
}
|
||||
|
||||
|
||||
def connect(db_path: Union[Path, str] = DEFAULT_DB_PATH) -> sqlite3.Connection:
|
||||
conn = sqlite3.connect(str(db_path))
|
||||
@@ -73,6 +81,44 @@ def load_csv(conn: sqlite3.Connection, table: str, path: Path) -> int:
|
||||
return len(rows)
|
||||
|
||||
|
||||
def import_template_file(
|
||||
db_path: Union[Path, str],
|
||||
template_name: str,
|
||||
file_path: Path,
|
||||
) -> int:
|
||||
table = SQLITE_IMPORT_TABLES.get(template_name)
|
||||
if table is None:
|
||||
supported = ", ".join(sorted(SQLITE_IMPORT_TABLES))
|
||||
raise ImportTemplateError(
|
||||
f"template '{template_name}' cannot be imported into SQLite; "
|
||||
f"supported templates: {supported}"
|
||||
)
|
||||
|
||||
rows = load_tabular_rows(file_path)
|
||||
result = validate_import_rows(template_name, rows)
|
||||
if not result.valid:
|
||||
first_error = result.errors[0]
|
||||
raise ImportTemplateError(
|
||||
f"validation failed at row {first_error.row}, "
|
||||
f"column {first_error.column}: {first_error.message}"
|
||||
)
|
||||
if not rows:
|
||||
return 0
|
||||
|
||||
init_db(db_path)
|
||||
with connect(db_path) as conn:
|
||||
columns = list(rows[0].keys())
|
||||
placeholders = ", ".join(["?"] * len(columns))
|
||||
column_sql = ", ".join(columns)
|
||||
update_sql = ", ".join([f"{column}=excluded.{column}" for column in columns])
|
||||
sql = (
|
||||
f"INSERT INTO {table} ({column_sql}) VALUES ({placeholders}) "
|
||||
f"ON CONFLICT DO UPDATE SET {update_sql}"
|
||||
)
|
||||
conn.executemany(sql, [tuple(row[column] for column in columns) for row in rows])
|
||||
return len(rows)
|
||||
|
||||
|
||||
def fetch_area_metrics(conn: sqlite3.Connection, month: str) -> list[sqlite3.Row]:
|
||||
return conn.execute(
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user