db restore with create db if not exitst
This commit is contained in:
parent
59ad6f3849
commit
c4a9a66c60
1 changed files with 82 additions and 2 deletions
|
|
@ -545,6 +545,74 @@ def _prepareImport(payload: dict) -> dict:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _ensureDatabaseExists(dbName: str) -> bool:
|
||||||
|
"""Create the PostgreSQL database if it does not yet exist.
|
||||||
|
|
||||||
|
Connects to the ``postgres`` admin database using the same credentials
|
||||||
|
as the target DB. Returns True if the database was created, False if
|
||||||
|
it already existed.
|
||||||
|
"""
|
||||||
|
registeredDbs = getRegisteredDatabases()
|
||||||
|
configPrefix = registeredDbs.get(dbName)
|
||||||
|
if configPrefix is None:
|
||||||
|
return False
|
||||||
|
|
||||||
|
hostKey = f"{configPrefix}_HOST" if configPrefix != "DB" else "DB_HOST"
|
||||||
|
portKey = f"{configPrefix}_PORT" if configPrefix != "DB" else "DB_PORT"
|
||||||
|
userKey = f"{configPrefix}_USER" if configPrefix != "DB" else "DB_USER"
|
||||||
|
passwordKey = f"{configPrefix}_PASSWORD_SECRET" if configPrefix != "DB" else "DB_PASSWORD_SECRET"
|
||||||
|
|
||||||
|
adminConn = psycopg2.connect(
|
||||||
|
host=APP_CONFIG.get(hostKey, "localhost"),
|
||||||
|
port=int(APP_CONFIG.get(portKey, 5432)),
|
||||||
|
database="postgres",
|
||||||
|
user=APP_CONFIG.get(userKey),
|
||||||
|
password=APP_CONFIG.get(passwordKey),
|
||||||
|
client_encoding="utf8",
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
adminConn.autocommit = True
|
||||||
|
with adminConn.cursor() as cur:
|
||||||
|
cur.execute("SELECT 1 FROM pg_database WHERE datname = %s", (dbName,))
|
||||||
|
if cur.fetchone():
|
||||||
|
return False
|
||||||
|
cur.execute(f'CREATE DATABASE "{dbName}"')
|
||||||
|
logger.info("Created missing database: %s", dbName)
|
||||||
|
return True
|
||||||
|
finally:
|
||||||
|
adminConn.close()
|
||||||
|
|
||||||
|
|
||||||
|
def _createTableFromExport(conn, tableName: str, rows: List[dict]) -> None:
|
||||||
|
"""Create a table based on the column structure found in the export data.
|
||||||
|
|
||||||
|
Uses TEXT for all columns since we don't have the original DDL.
|
||||||
|
The ``id`` column gets a PRIMARY KEY constraint.
|
||||||
|
"""
|
||||||
|
allKeys: List[str] = []
|
||||||
|
seen: set = set()
|
||||||
|
for row in rows:
|
||||||
|
for k in row.keys():
|
||||||
|
if k not in seen:
|
||||||
|
allKeys.append(k)
|
||||||
|
seen.add(k)
|
||||||
|
|
||||||
|
if not allKeys:
|
||||||
|
return
|
||||||
|
|
||||||
|
colDefs = []
|
||||||
|
for col in allKeys:
|
||||||
|
if col == "id":
|
||||||
|
colDefs.append(f'"{col}" TEXT PRIMARY KEY')
|
||||||
|
else:
|
||||||
|
colDefs.append(f'"{col}" TEXT')
|
||||||
|
|
||||||
|
ddl = f'CREATE TABLE IF NOT EXISTS "{tableName}" ({", ".join(colDefs)})'
|
||||||
|
with conn.cursor() as cur:
|
||||||
|
cur.execute(ddl)
|
||||||
|
logger.info("Created table %s with %d columns", tableName, len(allKeys))
|
||||||
|
|
||||||
|
|
||||||
def _importSingleDb(payload: dict, dbName: str, mode: str, protectedIds: List[str]) -> dict:
|
def _importSingleDb(payload: dict, dbName: str, mode: str, protectedIds: List[str]) -> dict:
|
||||||
"""Import a single database from the (already remapped) payload.
|
"""Import a single database from the (already remapped) payload.
|
||||||
|
|
||||||
|
|
@ -563,11 +631,21 @@ def _importSingleDb(payload: dict, dbName: str, mode: str, protectedIds: List[st
|
||||||
return {"database": dbName, "tables": {}, "recordCount": 0,
|
return {"database": dbName, "tables": {}, "recordCount": 0,
|
||||||
"warnings": [f"Keine Daten fuer '{dbName}' im Payload"]}
|
"warnings": [f"Keine Daten fuer '{dbName}' im Payload"]}
|
||||||
|
|
||||||
|
try:
|
||||||
|
dbCreated = _ensureDatabaseExists(dbName)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error("Failed to ensure database %s exists: %s", dbName, e)
|
||||||
|
return {"database": dbName, "tables": {}, "recordCount": 0,
|
||||||
|
"warnings": [f"Datenbank '{dbName}' konnte nicht erstellt werden: {e}"]}
|
||||||
|
|
||||||
protectedIdSet = set(protectedIds)
|
protectedIdSet = set(protectedIds)
|
||||||
tables = dbData.get("tables", {})
|
tables = dbData.get("tables", {})
|
||||||
warnings: List[str] = []
|
warnings: List[str] = []
|
||||||
dbResult: Dict[str, int] = {}
|
dbResult: Dict[str, int] = {}
|
||||||
|
|
||||||
|
if dbCreated:
|
||||||
|
warnings.append(f"Datenbank '{dbName}' wurde neu erstellt")
|
||||||
|
|
||||||
conn = _getConnection(dbName)
|
conn = _getConnection(dbName)
|
||||||
try:
|
try:
|
||||||
conn.autocommit = False
|
conn.autocommit = False
|
||||||
|
|
@ -576,9 +654,11 @@ def _importSingleDb(payload: dict, dbName: str, mode: str, protectedIds: List[st
|
||||||
for tableName, rows in tables.items():
|
for tableName, rows in tables.items():
|
||||||
if not isinstance(rows, list):
|
if not isinstance(rows, list):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if tableName not in existingTables:
|
if tableName not in existingTables:
|
||||||
warnings.append(f"Tabelle '{dbName}.{tableName}' existiert nicht, uebersprungen")
|
_createTableFromExport(conn, tableName, rows)
|
||||||
continue
|
conn.commit()
|
||||||
|
conn.autocommit = False
|
||||||
|
|
||||||
physicalCols = _getPhysicalColumns(conn, tableName)
|
physicalCols = _getPhysicalColumns(conn, tableName)
|
||||||
if not physicalCols:
|
if not physicalCols:
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue