Skip to content
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
4 changes: 4 additions & 0 deletions CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ Changes for crate
Unreleased
==========

- added missing functionality in CrateDialect, containing:
default schema name, server version info,
check if table/schema exists, list all tables/schemas

- run tests against crate 0.46.1

2014/10/27 0.12.3
Expand Down
45 changes: 39 additions & 6 deletions src/crate/client/sqlalchemy/dialect.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,16 @@
import logging
from datetime import datetime, date

from sqlalchemy.engine import default
from sqlalchemy import sql
from sqlalchemy import types as sqltypes
from sqlalchemy.engine import default, reflection

from .compiler import CrateCompiler
from crate.client.exceptions import TimezoneUnawareException


log = logging.getLogger(__name__)


class Date(sqltypes.Date):
def bind_processor(self, dialect):
def process(value):
Expand Down Expand Up @@ -116,15 +116,17 @@ class CrateDialect(default.DefaultDialect):

def __init__(self, *args, **kwargs):
super(CrateDialect, self).__init__(*args, **kwargs)

# currently our sql parser doesn't support unquoted column names that
# start with _. Adding it here causes sqlalchemy to quote such columns
self.identifier_preparer.illegal_initial_characters.add('_')

def initialize(self, connection):
# the DefaultDialect issues some queries to test for unicode support in
# the resutls. etc. -> don't need any of that.
pass
# get lowest server version
self.server_version_info = \
self._get_server_version_info(connection)
# get default schema name
self.default_schema_name = \
self._get_default_schema_name(connection)

def do_rollback(self, connection):
# if any exception is raised by the dbapi, sqlalchemy by default
Expand All @@ -143,7 +145,38 @@ def connect(self, host=None, port=None, *args, **kwargs):
return self.dbapi.connect(servers=server, **kwargs)
return self.dbapi.connect(**kwargs)

def _get_default_schema_name(self, connection):
return 'doc'

def _get_server_version_info(self, connection):
return tuple(connection.connection.lowest_server_version.version)

@classmethod
def dbapi(cls):
from crate import client
return client

def has_schema(self, connection, schema):
return schema in self.get_schema_names(connection)

def has_table(self, connection, table_name, schema=None):
return table_name in self.get_table_names(connection, schema=schema)

@reflection.cache
def get_schema_names(self, connection, **kw):
cursor = connection.execute(
"select schema_name "
"from information_schema.schemata "
"order by schema_name asc"
)
return [row[0] for row in cursor.fetchall()]

@reflection.cache
def get_table_names(self, connection, schema=None, **kw):
cursor = connection.execute(
"select table_name from information_schema.tables "
"where schema_name = ? "
"order by table_name asc, schema_name asc",
[schema or self.default_schema_name]
)
return [row[0] for row in cursor.fetchall()]
39 changes: 39 additions & 0 deletions src/crate/client/sqlalchemy/dialect.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
======================
CrateDialect Internals
======================

The initialize method sets the default schema name and version info::

>>> connection = engine.connect()
>>> dialect = CrateDialect()
>>> dialect.initialize(connection)

>>> dialect.default_schema_name
'doc'

>>> dialect.server_version_info
(0, 46, 4)

Check if table exists::

>>> dialect.has_table(connection, 'locations')
True

List all tables::

>>> dialect.get_table_names(connection)
['characters', 'locations']

>>> dialect.get_table_names(connection, schema='sys')
['cluster', 'jobs', 'jobs_log', 'nodes', 'operations', 'operations_log', 'shards']

Check if schema exists::

>>> dialect.has_schema(connection, 'doc')
True

List all schemas::

>>> dialect.get_schema_names(connection)
[u'blob', u'doc', u'information_schema', u'sys']

1 change: 1 addition & 0 deletions src/crate/client/sqlalchemy/itests.txt
Original file line number Diff line number Diff line change
Expand Up @@ -185,3 +185,4 @@ Reset the clima::

>>> location.details
[]

3 changes: 3 additions & 0 deletions src/crate/client/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
from crate.testing.layer import CrateLayer
from crate.testing.tests import crate_path, docs_path
from crate.client import connect
from crate.client.sqlalchemy.dialect import CrateDialect

from . import http
from .test_cursor import CursorTest
Expand Down Expand Up @@ -158,6 +159,7 @@ class Location(Base):
test.globs['Base'] = Base
test.globs['session'] = session
test.globs['Session'] = Session
test.globs['CrateDialect'] = CrateDialect


_server = None
Expand Down Expand Up @@ -283,6 +285,7 @@ def test_suite():

s = doctest.DocFileSuite(
'sqlalchemy/itests.txt',
'sqlalchemy/dialect.txt',
checker=checker,
setUp=setUpCrateLayerAndSqlAlchemy,
tearDown=tearDownWithCrateLayer,
Expand Down
2 changes: 1 addition & 1 deletion src/crate/testing/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ def docs_path(*parts):


def crate_path(*parts):
return docs_path('..', '..', 'parts', 'crate', *parts)
return os.path.abspath(docs_path('..', '..', 'parts', 'crate', *parts))

def public_ip():
import socket
Expand Down