Merge pull request #235 from datastax/dct-schema

Schema metadata: use column names from composite types, exclude CQL-incompatible tables from export
This commit is contained in:
Adam Holmberg
2015-01-08 16:29:15 -06:00
3 changed files with 56 additions and 14 deletions

View File

@@ -129,13 +129,13 @@ def parse_casstype_args(typestring):
elif tok == ')':
types, names = args.pop()
prev_types, prev_names = args[-1]
prev_types[-1] = prev_types[-1].apply_parameters(types, names)
else:
types, names = args[-1]
if ':' in tok:
name, tok = tok.rsplit(':', 1)
names.append(name)
parts = re.split(':|=>', tok)
tok = parts.pop()
if parts:
names.append(parts[0])
else:
names.append(None)
@@ -294,7 +294,7 @@ class _CassandraType(object):
newname = cls.cass_parameterized_type_with(subtypes)
if six.PY2 and isinstance(newname, unicode):
newname = newname.encode('utf-8')
return type(newname, (cls,), {'subtypes': subtypes, 'cassname': cls.cassname})
return type(newname, (cls,), {'subtypes': subtypes, 'cassname': cls.cassname, 'fieldnames': names})
@classmethod
def cql_parameterized_type(cls):

View File

@@ -264,6 +264,10 @@ class Metadata(object):
is_compact = True
has_value = column_aliases or not cf_col_rows
clustering_size = num_column_name_components
# Some thrift tables define names in composite types (see PYTHON-192)
if not column_aliases and hasattr(comparator, 'fieldnames'):
column_aliases = comparator.fieldnames
else:
is_compact = True
if column_aliases or not cf_col_rows:
@@ -356,6 +360,7 @@ class Metadata(object):
table_meta.options = self._build_table_options(row)
table_meta.is_compact_storage = is_compact
return table_meta
def _build_table_options(self, row):
@@ -922,6 +927,18 @@ class TableMetadata(object):
A dict mapping trigger names to :class:`.TriggerMetadata` instances.
"""
@property
def is_cql_compatible(self):
"""
A boolean indicating if this table can be represented as CQL in export
"""
# no such thing as DCT in CQL
incompatible = issubclass(self.comparator, types.DynamicCompositeType)
# no compact storage with more than one column beyond PK
incompatible |= self.is_compact_storage and len(self.columns) > len(self.primary_key) + 1
return not incompatible
def __init__(self, keyspace_metadata, name, partition_key=None, clustering_key=None, columns=None, triggers=None, options=None):
self.keyspace = keyspace_metadata
self.name = name
@@ -938,6 +955,18 @@ class TableMetadata(object):
along with all indexes on it. The returned string is formatted to
be human readable.
"""
if self.is_cql_compatible:
ret = self.all_as_cql()
else:
# If we can't produce this table with CQL, comment inline
ret = "/*\nWarning: Table %s.%s omitted because it has constructs not compatible with CQL (was created via legacy API).\n" % \
(self.keyspace.name, self.name)
ret += "\nApproximate structure, for reference:\n(this should not be used to reproduce this schema)\n\n%s" % self.all_as_cql()
ret += "\n*/"
return ret
def all_as_cql(self):
ret = self.as_cql_query(formatted=True)
ret += ";"
@@ -947,7 +976,6 @@ class TableMetadata(object):
for trigger_meta in self.triggers.values():
ret += "\n%s;" % (trigger_meta.as_cql_query(),)
return ret
def as_cql_query(self, formatted=False):

View File

@@ -638,16 +638,22 @@ create column family composite_comp_with_col
# is a bit strange, but it replays in CQL with desired results
expected_string = """CREATE KEYSPACE legacy WITH replication = {'class': 'SimpleStrategy', 'replication_factor': '1'} AND durable_writes = true;
/*
Warning: Table legacy.composite_comp_with_col omitted because it has constructs not compatible with CQL (was created via legacy API).
Approximate structure, for reference:
(this should not be used to reproduce this schema)
CREATE TABLE legacy.composite_comp_with_col (
key blob,
column0 't=>org.apache.cassandra.db.marshal.TimeUUIDType',
column1 'b=>org.apache.cassandra.db.marshal.BytesType',
column2 's=>org.apache.cassandra.db.marshal.UTF8Type',
t timeuuid,
b blob,
s text,
"b@6869746d65776974686d75736963" blob,
"b@6d616d6d616a616d6d61" blob,
PRIMARY KEY (key, column0, column1, column2)
PRIMARY KEY (key, t, b, s)
) WITH COMPACT STORAGE
AND CLUSTERING ORDER BY (column0 ASC, column1 ASC, column2 ASC)
AND CLUSTERING ORDER BY (t ASC, b ASC, s ASC)
AND caching = '{"keys":"ALL", "rows_per_partition":"NONE"}'
AND comment = 'Stores file meta data'
AND compaction = {'min_threshold': '4', 'class': 'org.apache.cassandra.db.compaction.SizeTieredCompactionStrategy', 'max_threshold': '32'}
@@ -662,6 +668,7 @@ CREATE TABLE legacy.composite_comp_with_col (
AND speculative_retry = 'NONE';
CREATE INDEX idx_two ON legacy.composite_comp_with_col ("b@6869746d65776974686d75736963");
CREATE INDEX idx_one ON legacy.composite_comp_with_col ("b@6d616d6d616a616d6d61");
*/
CREATE TABLE legacy.nested_composite_key (
key 'org.apache.cassandra.db.marshal.CompositeType(org.apache.cassandra.db.marshal.UUIDType, org.apache.cassandra.db.marshal.UTF8Type)',
@@ -759,10 +766,16 @@ CREATE TABLE legacy.simple_no_col (
AND read_repair_chance = 0.0
AND speculative_retry = 'NONE';
/*
Warning: Table legacy.composite_comp_no_col omitted because it has constructs not compatible with CQL (was created via legacy API).
Approximate structure, for reference:
(this should not be used to reproduce this schema)
CREATE TABLE legacy.composite_comp_no_col (
key blob,
column1 'org.apache.cassandra.db.marshal.DynamicCompositeType(t=>org.apache.cassandra.db.marshal.TimeUUIDType, b=>org.apache.cassandra.db.marshal.BytesType, s=>org.apache.cassandra.db.marshal.UTF8Type)',
column2 's=>org.apache.cassandra.db.marshal.UTF8Type',
column1 'org.apache.cassandra.db.marshal.DynamicCompositeType(org.apache.cassandra.db.marshal.TimeUUIDType, org.apache.cassandra.db.marshal.BytesType, org.apache.cassandra.db.marshal.UTF8Type)',
column2 text,
value blob,
PRIMARY KEY (key, column1, column1, column2)
) WITH COMPACT STORAGE
@@ -778,7 +791,8 @@ CREATE TABLE legacy.composite_comp_no_col (
AND memtable_flush_period_in_ms = 0
AND min_index_interval = 128
AND read_repair_chance = 0.0
AND speculative_retry = 'NONE';"""
AND speculative_retry = 'NONE';
*/"""
ccm = get_cluster()
ccm.run_cli(cli_script)