-
Notifications
You must be signed in to change notification settings - Fork 967
Cog 414 fix postgres database deletion #163
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 5 commits
ee2f1fb
c1c0dc4
36377c0
c67639f
ddaa1e8
09f5fa8
dc8680f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,7 +1,8 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from os import path | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from typing import Optional | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from typing import AsyncGenerator | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from contextlib import asynccontextmanager | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from sqlalchemy import text, select | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from sqlalchemy import text, select, MetaData | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from sqlalchemy.orm import joinedload | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine, async_sessionmaker | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -50,11 +51,14 @@ async def create_table(self, schema_name: str, table_name: str, table_config: li | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await connection.execute(text(f"CREATE TABLE IF NOT EXISTS {schema_name}.{table_name} ({', '.join(fields_query_parts)});")) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await connection.close() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| async def delete_table(self, table_name: str): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| async def delete_table(self, table_name: str, schema_name: Optional[str] = "public"): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| async with self.engine.begin() as connection: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await connection.execute(text(f"DROP TABLE IF EXISTS {table_name} CASCADE;")) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await connection.close() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if self.engine.dialect.name == "sqlite": | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # SQLite doesn’t support schema namespaces and the CASCADE keyword. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # However, foreign key constraint can be defined with ON DELETE CASCADE during table creation. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await connection.execute(text(f"DROP TABLE IF EXISTS {table_name};")) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| else: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await connection.execute(text(f"DROP TABLE IF EXISTS {schema_name}.{table_name} CASCADE;")) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| async def insert_data(self, schema_name: str, table_name: str, data: list[dict]): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| columns = ", ".join(data[0].keys()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -119,12 +123,22 @@ async def delete_database(self): | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| self.db_path = None | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| else: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| async with self.engine.begin() as connection: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Load the schema information into the MetaData object | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await connection.run_sync(Base.metadata.reflect) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for table in Base.metadata.sorted_tables: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| drop_table_query = text(f"DROP TABLE IF EXISTS {table.name} CASCADE") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await connection.execute(drop_table_query) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| result = await connection.execute( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| text(""" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| SELECT schema_name FROM information_schema.schemata | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| WHERE schema_name NOT IN ('pg_catalog', 'pg_toast', 'information_schema'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Create a MetaData instance to load table information | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| metadata = MetaData() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Drop all tables from all schemas | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for schema in result.fetchall(): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Load the schema information into the MetaData object | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await connection.run_sync(metadata.reflect, schema=schema[0]) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for table in metadata.sorted_tables: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| drop_table_query = text(f"DROP TABLE IF EXISTS {schema[0]}.{table.name} CASCADE") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await connection.execute(drop_table_query) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| metadata.clear() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| result = await connection.execute( | |
| text(""" | |
| SELECT schema_name FROM information_schema.schemata | |
| WHERE schema_name NOT IN ('pg_catalog', 'pg_toast', 'information_schema'); | |
| """) | |
| ) | |
| # Create a MetaData instance to load table information | |
| metadata = MetaData() | |
| # Drop all tables from all schemas | |
| for schema in result.fetchall(): | |
| # Load the schema information into the MetaData object | |
| await connection.run_sync(metadata.reflect, schema=schema[0]) | |
| for table in metadata.sorted_tables: | |
| drop_table_query = text(f"DROP TABLE IF EXISTS {schema[0]}.{table.name} CASCADE") | |
| await connection.execute(drop_table_query) | |
| metadata.clear() | |
| result = await connection.execute( | |
| text(""" | |
| SELECT schema_name FROM information_schema.schemata | |
| WHERE schema_name NOT IN ('pg_catalog', 'pg_toast', 'information_schema'); | |
| """) | |
| ) | |
| # Create a MetaData instance to load table information | |
| metadata = MetaData() | |
| # Drop entire schemas instead of individual tables | |
| for schema in result.fetchall(): | |
| drop_schema_query = text(f'DROP SCHEMA IF EXISTS "{schema[0]}" CASCADE') | |
| await connection.execute(drop_schema_query) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Consider using SQL parameters for table and schema names.
The implementation correctly handles different database types, but direct string interpolation in SQL queries could be vulnerable to SQL injection. Consider using parameters:
📝 Committable suggestion