Update db_manager.py
This commit is contained in:
207
db_manager.py
207
db_manager.py
@@ -1,111 +1,170 @@
|
|||||||
import sqlite3
|
import sqlite3
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
from pathlib import Path
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
DB_FILE = "app_data.db"
|
class DatabaseManager:
|
||||||
JSON_BACKUP = "settings.json" # The old file you want to import from
|
def __init__(self, db_path="app_data.db"):
|
||||||
|
self.db_path = db_path
|
||||||
|
self.conn = None
|
||||||
|
self.connect()
|
||||||
|
self.init_tables()
|
||||||
|
|
||||||
def get_db_connection():
|
def connect(self):
|
||||||
conn = sqlite3.connect(DB_FILE)
|
self.conn = sqlite3.connect(self.db_path, check_same_thread=False)
|
||||||
conn.row_factory = sqlite3.Row # Allows accessing columns by name
|
self.conn.row_factory = sqlite3.Row
|
||||||
return conn
|
|
||||||
|
|
||||||
def init_db():
|
def init_tables(self):
|
||||||
"""Creates tables and imports JSON if DB is new."""
|
"""Create tables for App Config, Project Settings, and Snippets."""
|
||||||
conn = get_db_connection()
|
cursor = self.conn.cursor()
|
||||||
cursor = conn.cursor()
|
|
||||||
|
|
||||||
# 1. Create Settings Table (Keyed by Path)
|
# 1. Project Settings (Replaces your per-file JSONs)
|
||||||
cursor.execute('''
|
cursor.execute('''
|
||||||
CREATE TABLE IF NOT EXISTS settings (
|
CREATE TABLE IF NOT EXISTS projects (
|
||||||
path TEXT PRIMARY KEY,
|
path TEXT PRIMARY KEY,
|
||||||
params TEXT,
|
parent_dir TEXT,
|
||||||
|
filename TEXT,
|
||||||
|
data TEXT,
|
||||||
|
is_batch INTEGER,
|
||||||
updated_at TIMESTAMP
|
updated_at TIMESTAMP
|
||||||
)
|
)
|
||||||
''')
|
''')
|
||||||
|
|
||||||
# 2. Create Batch History Table
|
# 2. Global App Config (Replaces config.json)
|
||||||
cursor.execute('''
|
cursor.execute('''
|
||||||
CREATE TABLE IF NOT EXISTS batch_log (
|
CREATE TABLE IF NOT EXISTS app_config (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
key TEXT PRIMARY KEY,
|
||||||
timestamp TEXT,
|
value TEXT
|
||||||
path TEXT,
|
|
||||||
status TEXT,
|
|
||||||
details TEXT
|
|
||||||
)
|
)
|
||||||
''')
|
''')
|
||||||
|
|
||||||
# 3. Check for Migration (If DB is empty but JSON exists)
|
# 3. Snippets (Replaces snippets.json)
|
||||||
cursor.execute('SELECT count(*) FROM settings')
|
cursor.execute('''
|
||||||
count = cursor.fetchone()[0]
|
CREATE TABLE IF NOT EXISTS snippets (
|
||||||
|
name TEXT PRIMARY KEY,
|
||||||
if count == 0 and os.path.exists(JSON_BACKUP):
|
content TEXT
|
||||||
print(f"Migration: Database empty. Importing from {JSON_BACKUP}...")
|
|
||||||
try:
|
|
||||||
with open(JSON_BACKUP, 'r') as f:
|
|
||||||
data = json.load(f)
|
|
||||||
# Assumes JSON structure: {"/path/to/img1": {config}, "/path/to/img2": {config}}
|
|
||||||
for path, config in data.items():
|
|
||||||
cursor.execute(
|
|
||||||
'INSERT OR REPLACE INTO settings (path, params, updated_at) VALUES (?, ?, ?)',
|
|
||||||
(path, json.dumps(config), datetime.now())
|
|
||||||
)
|
)
|
||||||
conn.commit()
|
''')
|
||||||
print("Migration successful.")
|
self.conn.commit()
|
||||||
|
|
||||||
|
# --- MIGRATION LOGIC ---
|
||||||
|
def is_empty(self):
|
||||||
|
cursor = self.conn.cursor()
|
||||||
|
cursor.execute("SELECT COUNT(*) FROM projects")
|
||||||
|
return cursor.fetchone()[0] == 0
|
||||||
|
|
||||||
|
def migrate_from_json(self, root_dir):
|
||||||
|
"""Scans folder for .json files and imports them if DB is empty."""
|
||||||
|
print("Starting Migration from JSON...")
|
||||||
|
root = Path(root_dir)
|
||||||
|
count = 0
|
||||||
|
|
||||||
|
# 1. Migrate Projects
|
||||||
|
for json_file in root.glob("*.json"):
|
||||||
|
if json_file.name in [".editor_config.json", ".editor_snippets.json"]:
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(json_file, 'r', encoding='utf-8') as f:
|
||||||
|
data = json.load(f)
|
||||||
|
|
||||||
|
is_batch = 1 if "batch_data" in data or isinstance(data, list) else 0
|
||||||
|
self.save_project(json_file, data, is_batch)
|
||||||
|
count += 1
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Migration failed: {e}")
|
print(f"Failed to migrate {json_file}: {e}")
|
||||||
|
|
||||||
conn.commit()
|
# 2. Migrate Config
|
||||||
conn.close()
|
config_path = root / ".editor_config.json"
|
||||||
|
if config_path.exists():
|
||||||
|
with open(config_path, 'r') as f:
|
||||||
|
self.save_app_config(json.load(f))
|
||||||
|
|
||||||
# --- SETTINGS FUNCTIONS ---
|
# 3. Migrate Snippets
|
||||||
|
snip_path = root / ".editor_snippets.json"
|
||||||
|
if snip_path.exists():
|
||||||
|
with open(snip_path, 'r') as f:
|
||||||
|
snippets = json.load(f)
|
||||||
|
for k, v in snippets.items():
|
||||||
|
self.save_snippet(k, v)
|
||||||
|
|
||||||
def load_settings_for_path(path):
|
print(f"Migration complete. Imported {count} files.")
|
||||||
"""Returns a dict of settings for the specific path, or None."""
|
|
||||||
conn = get_db_connection()
|
# --- PROJECT OPERATIONS ---
|
||||||
cursor = conn.cursor()
|
def get_projects_in_dir(self, directory):
|
||||||
cursor.execute("SELECT params FROM settings WHERE path = ?", (path,))
|
"""Returns list of filenames for a specific directory."""
|
||||||
|
cursor = self.conn.cursor()
|
||||||
|
# Ensure directory path format matches how we save it
|
||||||
|
dir_str = str(Path(directory).absolute())
|
||||||
|
|
||||||
|
cursor.execute("SELECT filename FROM projects WHERE parent_dir = ?", (dir_str,))
|
||||||
|
return [row['filename'] for row in cursor.fetchall()]
|
||||||
|
|
||||||
|
def load_project(self, full_path):
|
||||||
|
cursor = self.conn.cursor()
|
||||||
|
cursor.execute("SELECT data FROM projects WHERE path = ?", (str(full_path),))
|
||||||
row = cursor.fetchone()
|
row = cursor.fetchone()
|
||||||
conn.close()
|
|
||||||
|
|
||||||
if row:
|
if row:
|
||||||
return json.loads(row['params'])
|
return json.loads(row['data'])
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def save_settings_for_path(path, settings_dict):
|
def save_project(self, full_path, data, is_batch=False):
|
||||||
"""Saves the settings dict into the DB associated with the path."""
|
path_obj = Path(full_path)
|
||||||
conn = get_db_connection()
|
path_str = str(path_obj.absolute())
|
||||||
cursor = conn.cursor()
|
parent_str = str(path_obj.parent.absolute())
|
||||||
|
filename = path_obj.name
|
||||||
json_str = json.dumps(settings_dict)
|
|
||||||
timestamp = datetime.now()
|
|
||||||
|
|
||||||
|
cursor = self.conn.cursor()
|
||||||
cursor.execute('''
|
cursor.execute('''
|
||||||
INSERT INTO settings (path, params, updated_at)
|
INSERT INTO projects (path, parent_dir, filename, data, is_batch, updated_at)
|
||||||
VALUES (?, ?, ?)
|
VALUES (?, ?, ?, ?, ?, ?)
|
||||||
ON CONFLICT(path) DO UPDATE SET
|
ON CONFLICT(path) DO UPDATE SET
|
||||||
params=excluded.params,
|
data=excluded.data,
|
||||||
|
is_batch=excluded.is_batch,
|
||||||
updated_at=excluded.updated_at
|
updated_at=excluded.updated_at
|
||||||
''', (path, json_str, timestamp))
|
''', (path_str, parent_str, filename, json.dumps(data), int(is_batch), datetime.now()))
|
||||||
|
self.conn.commit()
|
||||||
|
|
||||||
conn.commit()
|
def delete_project(self, full_path):
|
||||||
conn.close()
|
cursor = self.conn.cursor()
|
||||||
return f"Saved settings for: {path}"
|
cursor.execute("SELECT count(*) FROM projects WHERE path = ?", (str(full_path),)) # Check existence
|
||||||
|
cursor.execute("DELETE FROM projects WHERE path = ?", (str(full_path),))
|
||||||
|
self.conn.commit()
|
||||||
|
|
||||||
# --- BATCH FUNCTIONS ---
|
# --- CONFIG OPERATIONS ---
|
||||||
|
def load_app_config(self):
|
||||||
def log_batch_run(path, status, details_dict):
|
cursor = self.conn.cursor()
|
||||||
conn = get_db_connection()
|
cursor.execute("SELECT value FROM app_config WHERE key = 'main_config'")
|
||||||
cursor = conn.cursor()
|
row = cursor.fetchone()
|
||||||
|
if row:
|
||||||
|
return json.loads(row['value'])
|
||||||
|
# Default Config
|
||||||
|
return {"last_dir": str(Path.cwd()), "favorites": []}
|
||||||
|
|
||||||
|
def save_app_config(self, config_dict):
|
||||||
|
cursor = self.conn.cursor()
|
||||||
cursor.execute('''
|
cursor.execute('''
|
||||||
INSERT INTO batch_log (timestamp, path, status, details)
|
INSERT INTO app_config (key, value) VALUES ('main_config', ?)
|
||||||
VALUES (?, ?, ?, ?)
|
ON CONFLICT(key) DO UPDATE SET value=excluded.value
|
||||||
''', (datetime.now(), path, status, json.dumps(details_dict)))
|
''', (json.dumps(config_dict),))
|
||||||
|
self.conn.commit()
|
||||||
|
|
||||||
conn.commit()
|
# --- SNIPPET OPERATIONS ---
|
||||||
conn.close()
|
def load_snippets(self):
|
||||||
|
cursor = self.conn.cursor()
|
||||||
|
cursor.execute("SELECT * FROM snippets")
|
||||||
|
return {row['name']: row['content'] for row in cursor.fetchall()}
|
||||||
|
|
||||||
# Initialize DB immediately when this module is imported
|
def save_snippet(self, name, content):
|
||||||
init_db()
|
cursor = self.conn.cursor()
|
||||||
|
cursor.execute('''
|
||||||
|
INSERT INTO snippets (name, content) VALUES (?, ?)
|
||||||
|
ON CONFLICT(name) DO UPDATE SET content=excluded.content
|
||||||
|
''', (name, content))
|
||||||
|
self.conn.commit()
|
||||||
|
|
||||||
|
def delete_snippet(self, name):
|
||||||
|
cursor = self.conn.cursor()
|
||||||
|
cursor.execute("DELETE FROM snippets WHERE name = ?", (name,))
|
||||||
|
self.conn.commit()
|
||||||
|
|||||||
Reference in New Issue
Block a user