Merge pull request #491 from datastax/py337
PYTHON-337: case sensitive support for column family name
This commit is contained in:
@@ -194,7 +194,7 @@ def sync_table(model):
|
||||
if table.indexes.get(index_name):
|
||||
continue
|
||||
|
||||
qs = ['CREATE INDEX {0}'.format(index_name)]
|
||||
qs = ['CREATE INDEX {0}'.format(metadata.protect_name(index_name))]
|
||||
qs += ['ON {0}'.format(cf_name)]
|
||||
qs += ['("{0}")'.format(column.db_field_name)]
|
||||
qs = ' '.join(qs)
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
import logging
|
||||
import re
|
||||
import six
|
||||
import warnings
|
||||
from warnings import warn
|
||||
|
||||
from cassandra.cqlengine import CQLEngineException, ValidationError
|
||||
from cassandra.cqlengine import columns
|
||||
@@ -327,6 +327,8 @@ class BaseModel(object):
|
||||
|
||||
__table_name__ = None
|
||||
|
||||
__table_name_case_sensitive__ = False
|
||||
|
||||
__keyspace__ = None
|
||||
|
||||
__discriminator_value__ = None
|
||||
@@ -520,7 +522,14 @@ class BaseModel(object):
|
||||
def _raw_column_family_name(cls):
|
||||
if not cls._table_name:
|
||||
if cls.__table_name__:
|
||||
cls._table_name = cls.__table_name__.lower()
|
||||
if cls.__table_name_case_sensitive__:
|
||||
cls._table_name = cls.__table_name__
|
||||
else:
|
||||
table_name = cls.__table_name__.lower()
|
||||
if cls.__table_name__ != table_name:
|
||||
warn(("Model __table_name__ will be case sensitive by default in 4.0. "
|
||||
"You should fix the __table_name__ value of the '{0}' model.").format(cls.__name__))
|
||||
cls._table_name = table_name
|
||||
else:
|
||||
if cls._is_polymorphic and not cls._is_polymorphic_base:
|
||||
cls._table_name = cls._polymorphic_base._raw_column_family_name()
|
||||
@@ -957,6 +966,11 @@ class Model(BaseModel):
|
||||
*Optional.* Sets the name of the CQL table for this model. If left blank, the table name will be the name of the model, with it's module name as it's prefix. Manually defined table names are not inherited.
|
||||
"""
|
||||
|
||||
__table_name_case_sensitive__ = False
|
||||
"""
|
||||
*Optional.* By default, __table_name__ is case insensitive. Set this to True if you want to preserve the case sensitivity.
|
||||
"""
|
||||
|
||||
__keyspace__ = None
|
||||
"""
|
||||
Sets the name of the keyspace used by this model.
|
||||
|
||||
@@ -28,6 +28,8 @@ Model
|
||||
|
||||
.. autoattribute:: __table_name__
|
||||
|
||||
.. autoattribute:: __table_name_case_sensitive__
|
||||
|
||||
.. autoattribute:: __keyspace__
|
||||
|
||||
.. _ttl-change:
|
||||
|
||||
@@ -235,6 +235,49 @@ class SyncTableTests(BaseCassEngTestCase):
|
||||
self.assertIn('SizeTieredCompactionStrategy', table_meta.as_cql_query())
|
||||
|
||||
|
||||
class IndexModel(Model):
|
||||
|
||||
__table_name__ = 'index_model'
|
||||
first_key = columns.UUID(primary_key=True)
|
||||
second_key = columns.Text(index=True)
|
||||
|
||||
|
||||
class IndexCaseSensitiveModel(Model):
|
||||
|
||||
__table_name__ = 'IndexModel'
|
||||
__table_name_case_sensitive__ = True
|
||||
first_key = columns.UUID(primary_key=True)
|
||||
second_key = columns.Text(index=True)
|
||||
|
||||
|
||||
class IndexTests(BaseCassEngTestCase):
|
||||
|
||||
def setUp(self):
|
||||
drop_table(IndexModel)
|
||||
|
||||
def test_sync_index(self):
|
||||
|
||||
sync_table(IndexModel)
|
||||
table_meta = management._get_table_metadata(IndexModel)
|
||||
self.assertIn("index_index_model_second_key", table_meta.indexes)
|
||||
|
||||
# index already exists
|
||||
sync_table(IndexModel)
|
||||
table_meta = management._get_table_metadata(IndexModel)
|
||||
self.assertIn("index_index_model_second_key", table_meta.indexes)
|
||||
|
||||
def test_sync_index_case_sensitive(self):
|
||||
|
||||
sync_table(IndexCaseSensitiveModel)
|
||||
table_meta = management._get_table_metadata(IndexCaseSensitiveModel)
|
||||
self.assertIn("index_IndexModel_second_key", table_meta.indexes)
|
||||
|
||||
# index already exists
|
||||
sync_table(IndexCaseSensitiveModel)
|
||||
table_meta = management._get_table_metadata(IndexCaseSensitiveModel)
|
||||
self.assertIn("index_IndexModel_second_key", table_meta.indexes)
|
||||
|
||||
|
||||
class NonModelFailureTest(BaseCassEngTestCase):
|
||||
class FakeModel(object):
|
||||
pass
|
||||
|
||||
@@ -216,6 +216,7 @@ class TestModelClassFunction(BaseCassEngTestCase):
|
||||
|
||||
self.assertEqual(len(warn), 0)
|
||||
|
||||
|
||||
class TestManualTableNaming(BaseCassEngTestCase):
|
||||
|
||||
class RenamedTest(Model):
|
||||
@@ -229,6 +230,31 @@ class TestManualTableNaming(BaseCassEngTestCase):
|
||||
assert self.RenamedTest.column_family_name(include_keyspace=False) == 'manual_name'
|
||||
assert self.RenamedTest.column_family_name(include_keyspace=True) == 'whatever.manual_name'
|
||||
|
||||
|
||||
class TestManualTableNamingCaseSensitive(BaseCassEngTestCase):
|
||||
|
||||
class RenamedCaseInsensitiveTest(Model):
|
||||
__keyspace__ = 'whatever'
|
||||
__table_name__ = 'Manual_Name'
|
||||
|
||||
id = columns.UUID(primary_key=True)
|
||||
|
||||
class RenamedCaseSensitiveTest(Model):
|
||||
__keyspace__ = 'whatever'
|
||||
__table_name__ = 'Manual_Name'
|
||||
__table_name_case_sensitive__ = True
|
||||
|
||||
id = columns.UUID(primary_key=True)
|
||||
|
||||
def test_proper_table_naming_case_insensitive(self):
|
||||
self.assertEqual(self.RenamedCaseInsensitiveTest.column_family_name(include_keyspace=False), 'manual_name')
|
||||
self.assertEqual(self.RenamedCaseInsensitiveTest.column_family_name(include_keyspace=True), 'whatever.manual_name')
|
||||
|
||||
def test_proper_table_naming_case_sensitive(self):
|
||||
self.assertEqual(self.RenamedCaseSensitiveTest.column_family_name(include_keyspace=False), '"Manual_Name"')
|
||||
self.assertEqual(self.RenamedCaseSensitiveTest.column_family_name(include_keyspace=True), 'whatever."Manual_Name"')
|
||||
|
||||
|
||||
class AbstractModel(Model):
|
||||
__abstract__ = True
|
||||
|
||||
|
||||
@@ -126,6 +126,23 @@ class TestModel(unittest.TestCase):
|
||||
# .. but we can still get the bare CF name
|
||||
self.assertEqual(TestModel.column_family_name(include_keyspace=False), "test_model")
|
||||
|
||||
def test_column_family_case_sensitive(self):
|
||||
class TestModel(Model):
|
||||
__table_name__ = 'TestModel'
|
||||
__table_name_case_sensitive__ = True
|
||||
|
||||
k = columns.Integer(primary_key=True)
|
||||
|
||||
self.assertEqual(TestModel.column_family_name(), '%s."TestModel"' % (models.DEFAULT_KEYSPACE,))
|
||||
|
||||
TestModel.__keyspace__ = "my_test_keyspace"
|
||||
self.assertEqual(TestModel.column_family_name(), '%s."TestModel"' % (TestModel.__keyspace__,))
|
||||
|
||||
del TestModel.__keyspace__
|
||||
with patch('cassandra.cqlengine.models.DEFAULT_KEYSPACE', None):
|
||||
self.assertRaises(CQLEngineException, TestModel.column_family_name)
|
||||
self.assertEqual(TestModel.column_family_name(include_keyspace=False), '"TestModel"')
|
||||
|
||||
|
||||
class BuiltInAttributeConflictTest(unittest.TestCase):
|
||||
"""tests Model definitions that conflict with built-in attributes/methods"""
|
||||
|
||||
Reference in New Issue
Block a user