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:
@@ -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):
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user