Skip to content
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

Include database views in list of tables #357

Merged
merged 1 commit into from
Mar 19, 2019
Merged
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 README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,7 @@ EXPLORER_SQL_WHITELIST These phrases are allowed, even though p
EXPLORER_DEFAULT_ROWS The number of rows to show by default in the preview pane. 1000
EXPLORER_SCHEMA_INCLUDE_TABLE_PREFIXES If not None, show schema only for tables starting with these prefixes. "Wins" if in conflict with EXCLUDE None # shows all tables
EXPLORER_SCHEMA_EXCLUDE_TABLE_PREFIXES Don't show schema for tables starting with these prefixes, in the schema helper. ('django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.admin')
EXPLORER_SCHEMA_INCLUDE_VIEWS Include database views False
EXPLORER_ASYNC_SCHEMA Generate DB schema asynchronously. Requires Celery and EXPLORER_TASKS_ENABLED False
EXPLORER_CONNECTION_NAME The name of the Django database connection to use. Ideally set this to a connection with read only permissions None # Must be set for the app to work, as this is required
EXPLORER_CONNECTIONS A dictionary of { 'Friendly Name': 'django_db_alias'}. All {} # At a minimum, should be set to something like { 'Default': 'readonly' } or similar. See connections.py for more documentation.
Expand Down
1 change: 1 addition & 0 deletions explorer/app_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
'admin_'))

EXPLORER_SCHEMA_INCLUDE_TABLE_PREFIXES = getattr(settings, 'EXPLORER_SCHEMA_INCLUDE_TABLE_PREFIXES', None)
EXPLORER_SCHEMA_INCLUDE_VIEWS = getattr(settings, 'EXPLORER_SCHEMA_INCLUDE_VIEWS', False)

EXPLORER_TRANSFORMS = getattr(settings, 'EXPLORER_TRANSFORMS', [])
EXPLORER_PERMISSION_VIEW = getattr(settings, 'EXPLORER_PERMISSION_VIEW', lambda u: u.is_staff)
Expand Down
7 changes: 6 additions & 1 deletion explorer/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from explorer.app_settings import (
EXPLORER_SCHEMA_INCLUDE_TABLE_PREFIXES,
EXPLORER_SCHEMA_EXCLUDE_TABLE_PREFIXES,
EXPLORER_SCHEMA_INCLUDE_VIEWS,
ENABLE_TASKS,
EXPLORER_ASYNC_SCHEMA,
EXPLORER_CONNECTIONS
Expand All @@ -19,6 +20,10 @@ def _get_excludes():
return EXPLORER_SCHEMA_EXCLUDE_TABLE_PREFIXES


def _include_views():
return EXPLORER_SCHEMA_INCLUDE_VIEWS is True


def do_async():
return ENABLE_TASKS and EXPLORER_ASYNC_SCHEMA

Expand Down Expand Up @@ -62,7 +67,7 @@ def build_schema_info(connection_alias):
connection = get_valid_connection(connection_alias)
ret = []
with connection.cursor() as cursor:
tables_to_introspect = connection.introspection.table_names(cursor)
tables_to_introspect = connection.introspection.table_names(cursor, include_views=_include_views())

for table_name in tables_to_introspect:
if not _include_table(table_name):
Expand Down
23 changes: 23 additions & 0 deletions explorer/tests/test_schema.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from django.test import TestCase
from django.core.cache import cache
from django.db import connection
from explorer.app_settings import EXPLORER_DEFAULT_CONNECTION as CONN
from explorer import schema
from mock import patch
Expand Down Expand Up @@ -49,10 +50,32 @@ def test_app_inclusion_list_excluded(self, mocked_excludes, mocked_includes):
tables = [x[0] for x in res]
self.assertIn('explorer_query', tables)

@patch('explorer.schema._include_views')
def test_app_include_views(self, mocked_include_views):
database_view = setup_sample_database_view()
mocked_include_views.return_value = True
res = schema.schema_info(CONN)
tables = [x[0] for x in res]
self.assertIn(database_view, tables)

@patch('explorer.schema._include_views')
def test_app_exclude_views(self, mocked_include_views):
database_view = setup_sample_database_view()
mocked_include_views.return_value = False
res = schema.schema_info(CONN)
tables = [x[0] for x in res]
self.assertNotIn(database_view, tables)

@patch('explorer.schema.do_async')
def test_builds_async(self, mocked_async_check):
mocked_async_check.return_value = True
self.assertIsNone(schema.schema_info(CONN))
res = schema.schema_info(CONN)
tables = [x[0] for x in res]
self.assertIn('explorer_query', tables)


def setup_sample_database_view():
with connection.cursor() as cursor:
cursor.execute("CREATE VIEW IF NOT EXISTS v_explorer_query AS SELECT title, sql from explorer_query")
return 'v_explorer_query'