#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ import_beerds_sql.py Скрипт читает файлы из каталогов: - server/modules/descriptions/repository/breed_descriptions - server/modules/descriptions/repository/breed_signs и вместо непосредственной вставки генерирует PostgreSQL‑SQL‑файл, который можно применить через `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")} 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: signs = read_json_file(sign_path) 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: """Генерирует MD5‑hash из `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()