Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions config/keymap.template.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"enter_tree_visual_mode": "v",
"clear_connection_selection": "escape",
"select_table": "s",
"drop_table": "d",
"refresh_tree": [
"f",
"R"
Expand Down
1 change: 1 addition & 0 deletions sqlit/core/input_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,4 @@ class InputContext:
has_results: bool
stacked_result_count: int = 0
count_buffer: str = ""
current_provider_supports_drop_table: bool = False
1 change: 1 addition & 0 deletions sqlit/core/keymap.py
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,7 @@ def _build_action_keys(self) -> list[ActionKeyDef]:
ActionKeyDef("d", "delete_connection_folder", "tree"),
ActionKeyDef("delete", "delete_connection_folder", "tree", primary=False),
ActionKeyDef("d", "delete_connection", "tree"),
ActionKeyDef("d", "drop_table", "tree"),
ActionKeyDef("delete", "delete_connection", "tree", primary=False),
ActionKeyDef("D", "duplicate_connection", "tree"),
ActionKeyDef("m", "move_connection_to_folder", "tree"),
Expand Down
1 change: 1 addition & 0 deletions sqlit/domains/connections/providers/adapter_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ def build_adapter_provider(spec: ProviderSpec, schema: ConnectionSchema, adapter
supports_indexes=bool(getattr(adapter, "supports_indexes", False)),
supports_triggers=bool(getattr(adapter, "supports_triggers", False)),
supports_sequences=bool(getattr(adapter, "supports_sequences", False)),
support_drop_table=(bool(getattr(adapter, "supports_drop_table", False))),
default_schema=str(getattr(adapter, "default_schema", "")),
system_databases=frozenset(getattr(adapter, "system_databases", frozenset())),
)
Expand Down
15 changes: 15 additions & 0 deletions sqlit/domains/connections/providers/adapters/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,10 @@ def supports_process_worker(self) -> bool:
"""Whether this adapter supports running queries in a separate process."""
return True

@property
def supports_drop_table(self) -> bool:
return True

@property
def test_query(self) -> str:
"""A simple query to test the connection.
Expand Down Expand Up @@ -445,6 +449,17 @@ def build_select_query(self, table: str, limit: int, database: str | None = None
"""
pass

@abstractmethod
def build_drop_table_query(self, table: str, database: str | None = None, schema: str | None = None) -> str:
"""Build a SELECT query with limit.

Args:
table: Table name.
database: Database name (if supported).
schema: Schema name (if supported).
"""
pass

@abstractmethod
def execute_query(self, conn: Any, query: str, max_rows: int | None = None) -> tuple[list[str], list[tuple], bool]:
"""Execute a query and return (columns, rows, truncated).
Expand Down
4 changes: 4 additions & 0 deletions sqlit/domains/connections/providers/athena/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,10 @@ def build_select_query(self, table: str, limit: int, database: str | None = None
target_db = database or schema or self.default_schema
return f"SELECT * FROM {target_db}.{table} LIMIT {limit}"

def build_drop_table_query(self, table: str, database: str | None = None, schema: str | None = None) -> str:
"""Build DROP TABLE query."""
return f'DROP TABLE IF EXISTS "{database or ""}.{table}"'

def get_procedures(self, conn: Any, database: str | None = None) -> list[str]:
return []

Expand Down
5 changes: 5 additions & 0 deletions sqlit/domains/connections/providers/bigquery/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -375,3 +375,8 @@ def build_select_query(
return f"SELECT * FROM `{dataset}.{table}` LIMIT {limit}"
return f"SELECT * FROM `{dataset}`.`{table}` LIMIT {limit}"
return f"SELECT * FROM `{table}` LIMIT {limit}"

def build_drop_table_query(self, table: str, database: str | None = None, schema: str | None = None) -> str:
"""Build DROP TABLE query."""
dataset = schema or database
return f"DROP TABLE IF EXISTS `{dataset}.{table}`"
9 changes: 9 additions & 0 deletions sqlit/domains/connections/providers/clickhouse/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,15 @@ def build_select_query(
return f"SELECT * FROM {quoted_db}.{quoted_table} LIMIT {limit}"
return f"SELECT * FROM {quoted_table} LIMIT {limit}"

def build_drop_table_query(self, table: str, database: str | None = None, schema: str | None = None) -> str:
"""Build DROP TABLE query."""
db = database or schema
quoted_table = self.quote_identifier(table)
if db:
quoted_db = self.quote_identifier(db)
return f"DROP TABLE IF EXISTS {quoted_db}.{quoted_table}"
return f"DROP TABLE IF EXISTS {quoted_table}"

def execute_query(
self, conn: Any, query: str, max_rows: int | None = None
) -> tuple[list[str], list[tuple], bool]:
Expand Down
4 changes: 4 additions & 0 deletions sqlit/domains/connections/providers/d1/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,10 @@ def build_select_query(self, table: str, limit: int, database: str | None = None
"""Builds a standard SELECT ... LIMIT query."""
return f"SELECT * FROM {self.quote_identifier(table)} LIMIT {limit}"

def build_drop_table_query(self, table: str, database: str | None = None, schema: str | None = None) -> str:
"""Build DROP TABLE query."""
return f"DROP TABLE IF EXISTS {self.quote_identifier(table)}"

def execute_query(
self, conn: D1Connection, query: str, max_rows: int | None = None
) -> tuple[list[str], list[tuple], bool]:
Expand Down
5 changes: 5 additions & 0 deletions sqlit/domains/connections/providers/db2/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,3 +190,8 @@ def build_select_query(self, table: str, limit: int, database: str | None = None
if schema:
return f'SELECT * FROM "{schema}"."{table}" FETCH FIRST {limit} ROWS ONLY'
return f'SELECT * FROM "{table}" FETCH FIRST {limit} ROWS ONLY'

def build_drop_table_query(self, table: str, database: str | None = None, schema: str | None = None) -> str:
"""Build DROP TABLE query."""
schema = schema or ""
return f'DROP TABLE "{schema}"."{table}"' if schema else f'DROP TABLE "{table}"'
4 changes: 4 additions & 0 deletions sqlit/domains/connections/providers/duckdb/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,10 @@ def build_select_query(self, table: str, limit: int, database: str | None = None
schema = schema or "main"
return f'SELECT * FROM "{schema}"."{table}" LIMIT {limit}'

def build_drop_table_query(self, table: str, database: str | None = None, schema: str | None = None) -> str:
schema = schema or "main"
return f'DROP TABLE IF EXISTS "{schema}"."{table}"'

def execute_query(self, conn: Any, query: str, max_rows: int | None = None) -> tuple[list[str], list[tuple], bool]:
"""Execute a query on DuckDB with optional row limit."""
result = conn.execute(query)
Expand Down
4 changes: 4 additions & 0 deletions sqlit/domains/connections/providers/firebird/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,10 @@ def build_select_query(
"""Build SELECT LIMIT query."""
return f'SELECT * FROM "{table}" ROWS {limit}'

def build_drop_table_query(self, table: str, database: str | None = None, schema: str | None = None) -> str:
"""Build DROP TABLE query."""
return f'DROP TABLE "{table}"'

def execute_non_query(self, conn: Any, query: str) -> int:
# Firebird has no autocommit mode, so we need to guarantee it ourselves.
try:
Expand Down
8 changes: 8 additions & 0 deletions sqlit/domains/connections/providers/flight/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,14 @@ def build_select_query(
return f"SELECT * FROM {quoted_schema}.{quoted_table} LIMIT {limit}"
return f"SELECT * FROM {quoted_table} LIMIT {limit}"

def build_drop_table_query(self, table: str, database: str | None = None, schema: str | None = None) -> str:
"""Build DROP TABLE query."""
quoted_table = self.quote_identifier(table)
if schema:
quoted_schema = self.quote_identifier(schema)
return f'DROP TABLE IF EXISTS {quoted_schema}.{quoted_table}'
return f'DROP TABLE IF EXISTS {quoted_table}'

def _arrow_table_to_tuples(
self, table: Any
) -> tuple[list[str], list[tuple[Any, ...]]]:
Expand Down
5 changes: 5 additions & 0 deletions sqlit/domains/connections/providers/hana/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,3 +183,8 @@ def quote_identifier(self, name: str) -> str:
def build_select_query(self, table: str, limit: int, database: str | None = None, schema: str | None = None) -> str:
schema = schema or self.default_schema
return f'SELECT * FROM "{schema}"."{table}" LIMIT {limit}'

def build_drop_table_query(self, table: str, database: str | None = None, schema: str | None = None) -> str:
"""Build DROP TABLE query."""
schema = schema or self.default_schema
return f'DROP TABLE "{schema}"."{table}"'
3 changes: 3 additions & 0 deletions sqlit/domains/connections/providers/impala/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,3 +174,6 @@ def build_select_query(
if database:
return f"SELECT * FROM `{database}`.`{table}` LIMIT {limit}"
return f"SELECT * FROM `{table}` LIMIT {limit}"

def build_drop_table_query(self, table: str, database: str | None = None, schema: str | None = None) -> str:
return f"DROP TABLE IF EXISTS `{database}`.`{table}`" if database else f"DROP TABLE IF EXISTS `{table}`"
4 changes: 4 additions & 0 deletions sqlit/domains/connections/providers/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ class SchemaCapabilities:
supports_indexes: bool
supports_triggers: bool
supports_sequences: bool
support_drop_table: bool
default_schema: str
system_databases: frozenset[str]

Expand All @@ -60,6 +61,9 @@ def quote_identifier(self, name: str) -> str: ...
def build_select_query(self, table: str, limit: int, database: str | None = None, schema: str | None = None) -> str:
...

def build_drop_table_query(self, table: str, database: str | None = None, schema: str | None = None) -> str:
...

def format_table_name(self, schema: str | None, table: str) -> str: ...

def qualified_name(self, database: str | None, schema: str | None, name: str) -> str:
Expand Down
5 changes: 5 additions & 0 deletions sqlit/domains/connections/providers/mssql/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,11 @@ def build_select_query(self, table: str, limit: int, database: str | None = None
schema = schema or "dbo"
return f"SELECT TOP {limit} * FROM [{schema}].[{table}]"

def build_drop_table_query(self, table: str, database: str | None = None, schema: str | None = None) -> str:
"""Build DROP TABLE query."""
schema = schema or "dbo"
return f'DROP TABLE IF EXISTS [{schema}].[{table}]'

def execute_query(self, conn: Any, query: str, max_rows: int | None = None) -> tuple[list[str], list[tuple], bool]:
"""Execute a query on SQL Server with optional row limit."""
cursor = conn.cursor()
Expand Down
6 changes: 6 additions & 0 deletions sqlit/domains/connections/providers/mysql/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,12 @@ def build_select_query(self, table: str, limit: int, database: str | None = None
return f"SELECT * FROM `{database}`.`{table}` LIMIT {limit}"
return f"SELECT * FROM `{table}` LIMIT {limit}"

def build_drop_table_query(self, table: str, database: str | None = None, schema: str | None = None) -> str:
"""Build DROP TABLE query."""
db = database or schema
return f"DROP TABLE IF EXISTS `{db}`.`{table}`" if db else f"DROP TABLE IF EXISTS `{table}`"


def get_indexes(self, conn: Any, database: str | None = None) -> list[IndexInfo]:
"""Get indexes from MySQL/MariaDB."""
cursor = conn.cursor()
Expand Down
4 changes: 4 additions & 0 deletions sqlit/domains/connections/providers/oracle/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,10 @@ def build_select_query(self, table: str, limit: int, database: str | None = None
"""Build SELECT query with FETCH FIRST for Oracle 12c+. Schema parameter is ignored."""
return f'SELECT * FROM "{table}" FETCH FIRST {limit} ROWS ONLY'

def build_drop_table_query(self, table: str, database: str | None = None, schema: str | None = None) -> str:
"""Build DROP TABLE query."""
return f'DROP TABLE "{table}"'

def execute_query(self, conn: Any, query: str, max_rows: int | None = None) -> tuple[list[str], list[tuple], bool]:
"""Execute a query on Oracle with optional row limit."""
cursor = conn.cursor()
Expand Down
8 changes: 8 additions & 0 deletions sqlit/domains/connections/providers/osquery/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ def supports_process_worker(self) -> bool:
# osquery spawned instances may not work well across process boundaries
return False

@property
def supports_drop_table(self) -> bool:
return False

@property
def default_schema(self) -> str:
return ""
Expand Down Expand Up @@ -199,6 +203,10 @@ def build_select_query(
) -> str:
return f'SELECT * FROM "{table}" LIMIT {limit}'

def build_drop_table_query(self, table: str, database: str | None = None, schema: str | None = None) -> str:
"""Build DROP TABLE query."""
return ''

def execute_query(
self, conn: Any, query: str, max_rows: int | None = None
) -> tuple[list[str], list[tuple], bool]:
Expand Down
5 changes: 5 additions & 0 deletions sqlit/domains/connections/providers/postgresql/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,11 @@ def build_select_query(self, table: str, limit: int, database: str | None = None
schema = schema or "public"
return f'SELECT * FROM "{schema}"."{table}" LIMIT {limit}'

def build_drop_table_query(self, table: str, database: str | None = None, schema: str | None = None) -> str:
"""Build DROP TABLE query."""
schema = schema or "public"
return f'DROP TABLE IF EXISTS "{schema}"."{table}"'

@property
def supports_sequences(self) -> bool:
"""PostgreSQL supports sequences."""
Expand Down
8 changes: 8 additions & 0 deletions sqlit/domains/connections/providers/presto/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,3 +190,11 @@ def build_select_query(self, table: str, limit: int, database: str | None = None
if schema_name:
return f'SELECT * FROM "{schema_name}"."{table}" LIMIT {limit}'
return f'SELECT * FROM "{table}" LIMIT {limit}'

def build_drop_table_query(self, table: str, database: str | None = None, schema: str | None = None) -> str:
schema_name = schema or self.default_schema
if database and schema_name:
return f'DROP TABLE IF EXISTS "{database}"."{schema_name}"."{table}"'
if db := database or schema:
return f'DROP TABLE IF EXISTS "{db}"."{table}"'
return f'DROP TABLE IF EXISTS "{table}"'
5 changes: 5 additions & 0 deletions sqlit/domains/connections/providers/redshift/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,3 +233,8 @@ def build_select_query(
"""Build SELECT query with LIMIT."""
schema = schema or self.default_schema
return f'SELECT * FROM "{schema}"."{table}" LIMIT {limit}'


def build_drop_table_query(self, table: str, database: str | None = None, schema: str | None = None) -> str:
schema = schema or self.default_schema
return f'DROP TABLE IF EXISTS "{schema}"."{table}"'
5 changes: 5 additions & 0 deletions sqlit/domains/connections/providers/snowflake/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,11 @@ def build_select_query(self, table: str, limit: int, database: str | None = None
schema = schema or "PUBLIC"
return f'SELECT * FROM "{schema}"."{table}" LIMIT {limit}'

def build_drop_table_query(self, table: str, database: str | None = None, schema: str | None = None) -> str:
"""Build DROP TABLE query."""
schema = schema or "PUBLIC"
return f'DROP TABLE IF EXISTS "{schema}"."{table}"'

def get_procedures(self, conn: Any, database: str | None = None) -> list[str]:
"""Get stored procedures."""
cursor = conn.cursor()
Expand Down
5 changes: 5 additions & 0 deletions sqlit/domains/connections/providers/spanner/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -376,3 +376,8 @@ def build_select_query_for_conn(
"""Build SELECT query with LIMIT using connection-aware quoting."""
quoted = self._quote_identifier_for_conn(conn, table)
return f"SELECT * FROM {quoted} LIMIT {limit}"

def build_drop_table_query(self, table: str, database: str | None = None, schema: str | None = None) -> str:
"""Build DROP TABLE query."""
quoted_table = self._quote_identifier_for_dialect(DIALECT_GOOGLESQL, table)
return f'DROP TABLE IF EXISTS {quoted_table}'
4 changes: 4 additions & 0 deletions sqlit/domains/connections/providers/sqlite/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,10 @@ def build_select_query(self, table: str, limit: int, database: str | None = None
"""Build SELECT LIMIT query for SQLite. Schema parameter is ignored."""
return f'SELECT * FROM "{table}" LIMIT {limit}'

def build_drop_table_query(self, table: str, database: str | None = None, schema: str | None = None) -> str:
"""Build DROP TABLE query."""
return f"DROP TABLE IF EXISTS {table}"

def execute_query(self, conn: Any, query: str, max_rows: int | None = None) -> tuple[list[str], list[tuple], bool]:
"""Execute a query on SQLite with optional row limit."""
cursor = conn.cursor()
Expand Down
4 changes: 4 additions & 0 deletions sqlit/domains/connections/providers/surrealdb/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,10 @@ def build_select_query(
) -> str:
return f"SELECT * FROM {self.quote_identifier(table)} LIMIT {limit}"

def build_drop_table_query(self, table: str, database: str | None = None, schema: str | None = None) -> str:
"""Build REMOVE TABLE query."""
return f"REMOVE TABLE {self.quote_identifier(table)}"

def execute_query(
self, conn: Any, query: str, max_rows: int | None = None
) -> tuple[list[str], list[tuple], bool]:
Expand Down
4 changes: 4 additions & 0 deletions sqlit/domains/connections/providers/teradata/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,3 +264,7 @@ def build_select_query(self, table: str, limit: int, database: str | None = None
if schema_name:
return f'lock row for access select top {limit} * from "{schema_name}"."{table}"'
return f'lock row for access select top {limit} * from "{table}"'

def build_drop_table_query(self, table: str, database: str | None = None, schema: str | None = None) -> str:
db = database or schema
return f'DROP TABLE "{db}"."{table}"' if db else f'DROP TABLE "{table}"'
9 changes: 9 additions & 0 deletions sqlit/domains/connections/providers/trino/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,3 +190,12 @@ def build_select_query(self, table: str, limit: int, database: str | None = None
if schema_name:
return f'SELECT * FROM "{schema_name}"."{table}" LIMIT {limit}'
return f'SELECT * FROM "{table}" LIMIT {limit}'

def build_drop_table_query(self, table: str, database: str | None = None, schema: str | None = None) -> str:
"""Build DROP TABLE query."""
schema_name = schema or self.default_schema
if database and schema_name:
return f'DROP TABLE IF EXISTS "{database}"."{schema_name}"."{table}"'
if db := database or schema_name:
return f'DROP TABLE IF EXISTS "{db}"."{table}"'
return f'DROP TABLE IF EXISTS "{table}"'
4 changes: 4 additions & 0 deletions sqlit/domains/connections/providers/turso/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,10 @@ def build_select_query(self, table: str, limit: int, database: str | None = None
"""Build SELECT LIMIT query for Turso. Schema parameter is ignored."""
return f'SELECT * FROM "{table}" LIMIT {limit}'

def build_drop_table_query(self, table: str, database: str | None = None, schema: str | None = None) -> str:
"""Build DROP TABLE query."""
return f'DROP TABLE IF EXISTS "{table}"'

def execute_query(self, conn: Any, query: str, max_rows: int | None = None) -> tuple[list[str], list[tuple], bool]:
"""Execute a query on Turso with optional row limit."""
cur = conn.cursor()
Expand Down
15 changes: 15 additions & 0 deletions sqlit/domains/explorer/state/tree_on_table.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ class TreeOnTableState(State):

def _setup_actions(self) -> None:
self.allows("select_table", label="Select TOP 100", help="Select TOP 100 (table/view)")
self.allows(
"drop_table",
guard=lambda app: app.tree_node_kind == "table" and app.current_provider_supports_drop_table,
label="Drop Table",
help="Drop selected Table",
)

def get_display_bindings(self, app: InputContext) -> tuple[list[DisplayBinding], list[DisplayBinding]]:
left: list[DisplayBinding] = []
Expand All @@ -28,6 +34,15 @@ def get_display_bindings(self, app: InputContext) -> tuple[list[DisplayBinding],
)
)
seen.add("select_table")
if app.tree_node_kind == "table" and app.current_provider_supports_drop_table:
left.append(
DisplayBinding(
key=resolve_display_key("drop_table") or "d",
label="Drop Table",
action="drop_table",
)
)
seen.add("drop_table")
left.append(
DisplayBinding(
key=resolve_display_key("refresh_tree") or "f",
Expand Down
Loading