beerds/scripts/filldb.py

176 lines
6.8 KiB
Python
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from uuid import uuid4
"""
import_beerds_sql.py
Скрипт читает файлы из каталогов:
- server/modules/descriptions/repository/breed_descriptions
- server/modules/descriptions/repository/breed_signs
и вместо непосредственной вставки генерирует PostgreSQLSQLфайл, который
можно применить через `psql -f <имя_файла.sql>`:
CREATE TABLE beerds.beerds (
id varchar NOT NULL,
name text NOT NULL,
descriptions text NOT NULL,
signs json NOT NULL,
alias text NOT NULL,
CONSTRAINT beerds_pkey PRIMARY KEY (id)
);
"""
import sys
import json
import hashlib
import pathlib
# ------------------------------------------------------------------
# 2⃣ Путь к каталогам (можно изменить под свой проект)
# ------------------------------------------------------------------
BASE_DIR = pathlib.Path(__file__).resolve().parent.parent
DESC_DIR = BASE_DIR / "server/modules/descriptions/repository/breed_descriptions"
SIGN_DIR = BASE_DIR / "server/modules/descriptions/repository/breed_signs"
print(f"DESC_DIR = {DESC_DIR}")
# ------------------------------------------------------------------
# 3⃣ Функции чтения файлов
# ------------------------------------------------------------------
def read_text_file(path: pathlib.Path) -> str:
"""Возвращает содержимое текстового файла (unicode)."""
with path.open("r", encoding="utf-8") as f:
return f.read().strip()
def read_json_file(path: pathlib.Path) -> dict:
"""Возвращает JSONобъект из файла."""
with path.open("r", encoding="utf-8") as f:
return json.load(f)
# ------------------------------------------------------------------
# 4⃣ Формируем словарь: имя → (описание, сигналы)
# ------------------------------------------------------------------
def build_breed_map(desc_dir: pathlib.Path, sign_dir: pathlib.Path) -> dict:
"""Возвращает dict: stem → (description, signs)"""
desc_files = {p.stem: p for p in desc_dir.glob("*.txt")}
sign_files = {p.stem: p for p in sign_dir.glob("*.txt")}
for key in desc_files:
if key in sign_files:
continue
sign_files[key] = None
common_keys = desc_files.keys() & sign_files.keys()
if not common_keys:
print("⚠️ Нет общих файлов между каталогами описаний и сигналов.")
return {}
breeds = {}
for key in sorted(common_keys):
desc_path = desc_files[key]
sign_path = sign_files[key]
try:
description = read_text_file(desc_path)
except Exception as e:
print(f"Не удалось прочитать описание {desc_path}: {e}")
continue
try:
if sign_path is not None:
signs = read_json_file(sign_path)
else:
signs = {}
except Exception as e:
print(f"Не удалось прочитать сигналы {sign_path}: {e}")
continue
breeds[key] = (description, signs)
return breeds
# ------------------------------------------------------------------
# 5⃣ Генерация id (если нужно уникальное)
# ------------------------------------------------------------------
def generate_id(name: str, alias: str) -> str:
"""Генерирует MD5hash из `name:alias`."""
key = f"{name}:{alias}"
return hashlib.md5(key.encode("utf-8")).hexdigest()
# ------------------------------------------------------------------
# 6⃣ Генерация SQLфайла
# ------------------------------------------------------------------
def write_sql_file(breeds: dict, out_path: pathlib.Path):
"""Создаёт один .sqlфайл, содержащий INSERTоперации для всех пород."""
if not breeds:
print("⚠️ Нет данных для генерации SQL.")
return
lines = []
header = (
"-- Автоматически сгенерированный скрипт вставки пород\n"
"-- Запустить: psql -f beerds_insert.sql\n\n"
"BEGIN;\n"
)
lines.append(header)
# Формируем один блок INSERT с несколькими строками VALUES
# 1. Столбцы
cols = "(id, name, descriptions, signs, alias)"
# 2. Генерируем строки VALUES
value_lines = []
for name, (description, signs) in breeds.items():
alias = name # можно изменить при необходимости
breed_id = generate_id(name, alias)
# Подготовка значений: экранирование апострофов и JSON
escaped_name = name.replace("_", " ").replace("'", "''")
escaped_alias = alias.replace("'", "''")
escaped_desc = description.replace("'", "''")
# JSON как строка (в PostgreSQL json можно передавать как текст)
json_str = json.dumps(signs, ensure_ascii=False).replace("'", "''")
value_line = f"('{breed_id}', '{escaped_name}', '{escaped_desc}', '{json_str}', '{escaped_alias}')"
value_lines.append(value_line)
# Объединяем VALUES через запятую
values_section = ",\n".join(value_lines)
insert_stmt = (
f"INSERT INTO beerds.beerds {cols}\n"
f"VALUES\n{values_section}\n"
f"ON CONFLICT (id) DO UPDATE\n"
f" SET name = EXCLUDED.name,\n"
f" descriptions = EXCLUDED.descriptions,\n"
f" signs = EXCLUDED.signs,\n"
f" alias = EXCLUDED.alias;\n"
)
lines.append(insert_stmt)
lines.append("\nCOMMIT;")
# Записываем в файл
out_path.write_text("\n".join(lines), encoding="utf-8")
print(f"✅ SQLфайл успешно сгенерирован: {out_path}")
# ------------------------------------------------------------------
# 7⃣ Основная точка входа
# ------------------------------------------------------------------
def main():
print("🔍 Читаем файлы…")
breeds_map = build_breed_map(DESC_DIR, SIGN_DIR)
if not breeds_map:
print("❌ Ничего не найдено. Завершение.")
sys.exit(1)
# Путь для вывода SQLфайла
sql_file_path = BASE_DIR / "beerds_insert.sql"
print(f"📝 Записываем INSERTоперации в файл: {sql_file_path}")
write_sql_file(breeds_map, sql_file_path)
print("🎉 Готово!")
if __name__ == "__main__":
main()