From f3612d41aab22f3ee4580eb8eeca1940d8972709 Mon Sep 17 00:00:00 2001 From: Adam Holmberg Date: Fri, 13 Jan 2017 16:44:34 -0600 Subject: [PATCH] make table extensions for for views, too PYTHON-682 --- cassandra/metadata.py | 46 +++++++++++----- tests/integration/standard/test_metadata.py | 59 +++++++++++++++------ 2 files changed, 76 insertions(+), 29 deletions(-) diff --git a/cassandra/metadata.py b/cassandra/metadata.py index 6e902028..e410631a 100644 --- a/cassandra/metadata.py +++ b/cassandra/metadata.py @@ -1081,15 +1081,6 @@ class TableMetadata(object): Metadata describing configuration for table extensions """ - _extension_registry = {} - - class _RegisteredExtensionType(type): - def __new__(mcs, name, bases, dct): - cls = super(TableMetadata._RegisteredExtensionType, mcs).__new__(mcs, name, bases, dct) - if name != 'RegisteredTableExtension': - TableMetadata._extension_registry[cls.name] = cls - return cls - def __init__(self, keyspace_name, name, partition_key=None, clustering_key=None, columns=None, triggers=None, options=None): self.keyspace_name = keyspace_name self.name = name @@ -1138,9 +1129,10 @@ class TableMetadata(object): for view_meta in self.views.values(): ret += "\n\n%s;" % (view_meta.as_cql_query(formatted=True),) - if self.extensions: # None - for k in six.viewkeys(self._extension_registry) & self.extensions: # no viewkeys on OrderedMapSerializeKey - ext = self._extension_registry[k] + if self.extensions: + registry = _RegisteredExtensionType._extension_registry + for k in six.viewkeys(registry) & self.extensions: # no viewkeys on OrderedMapSerializeKey + ext = registry[k] cql = ext.after_table_cql(self, k, self.extensions[k]) if cql: ret += "\n\n%s" % (cql,) @@ -1260,7 +1252,18 @@ class TableExtensionInterface(object): pass -@six.add_metaclass(TableMetadata._RegisteredExtensionType) +class _RegisteredExtensionType(type): + + _extension_registry = {} + + def __new__(mcs, name, bases, dct): + cls = super(_RegisteredExtensionType, mcs).__new__(mcs, name, bases, dct) + if name != 'RegisteredTableExtension': + mcs._extension_registry[cls.name] = cls + return cls + + +@six.add_metaclass(_RegisteredExtensionType) class RegisteredTableExtension(TableExtensionInterface): """ Extending this class registers it by name (associated by key in the `system_schema.tables.extensions` map). @@ -2327,6 +2330,7 @@ class SchemaParserV3(SchemaParserV22): view_meta = MaterializedViewMetadata(keyspace_name, view_name, base_table_name, include_all_columns, where_clause, self._build_table_options(row)) self._build_table_columns(view_meta, col_rows) + view_meta.extensions = row.get('extensions', {}) return view_meta @@ -2487,6 +2491,11 @@ class MaterializedViewMetadata(object): view. """ + extensions = None + """ + Metadata describing configuration for table extensions + """ + def __init__(self, keyspace_name, view_name, base_table_name, include_all_columns, where_clause, options): self.keyspace_name = keyspace_name self.name = view_name @@ -2523,13 +2532,22 @@ class MaterializedViewMetadata(object): properties = TableMetadataV3._property_string(formatted, self.clustering_key, self.options) - return "CREATE MATERIALIZED VIEW %(keyspace)s.%(name)s AS%(sep)s" \ + ret = "CREATE MATERIALIZED VIEW %(keyspace)s.%(name)s AS%(sep)s" \ "SELECT %(selected_cols)s%(sep)s" \ "FROM %(keyspace)s.%(base_table)s%(sep)s" \ "WHERE %(where_clause)s%(sep)s" \ "PRIMARY KEY %(pk)s%(sep)s" \ "WITH %(properties)s" % locals() + if self.extensions: + registry = _RegisteredExtensionType._extension_registry + for k in six.viewkeys(registry) & self.extensions: # no viewkeys on OrderedMapSerializeKey + ext = registry[k] + cql = ext.after_table_cql(self, k, self.extensions[k]) + if cql: + ret += "\n\n%s" % (cql,) + return ret + def export_as_string(self): return self.as_cql_query(formatted=True) + ";" diff --git a/tests/integration/standard/test_metadata.py b/tests/integration/standard/test_metadata.py index 66bb3b48..925029a8 100644 --- a/tests/integration/standard/test_metadata.py +++ b/tests/integration/standard/test_metadata.py @@ -29,13 +29,15 @@ from cassandra.cluster import Cluster from cassandra.encoder import Encoder from cassandra.metadata import (Metadata, KeyspaceMetadata, IndexMetadata, Token, MD5Token, TokenMap, murmur3, Function, Aggregate, protect_name, protect_names, - get_schema_parser, RegisteredTableExtension) + get_schema_parser, RegisteredTableExtension, _RegisteredExtensionType) from cassandra.policies import SimpleConvictionPolicy from cassandra.pool import Host -from tests.integration import get_cluster, use_singledc, PROTOCOL_VERSION, get_server_versions, execute_until_pass, \ - BasicSegregatedKeyspaceUnitTestCase, BasicSharedKeyspaceUnitTestCase, BasicExistingKeyspaceUnitTestCase, drop_keyspace_shutdown_cluster, CASSANDRA_VERSION, \ - BasicExistingSegregatedKeyspaceUnitTestCase, dseonly, DSE_VERSION, get_supported_protocol_versions, greaterthanorequalcass30 +from tests.integration import (get_cluster, use_singledc, PROTOCOL_VERSION, get_server_versions, execute_until_pass, + BasicSegregatedKeyspaceUnitTestCase, BasicSharedKeyspaceUnitTestCase, + BasicExistingKeyspaceUnitTestCase, drop_keyspace_shutdown_cluster, CASSANDRA_VERSION, + BasicExistingSegregatedKeyspaceUnitTestCase, dseonly, DSE_VERSION, + get_supported_protocol_versions, greaterthanorequalcass30) def setup_module(): @@ -864,15 +866,19 @@ class SchemaMetadataTests(BasicSegregatedKeyspaceUnitTestCase): ks = self.keyspace_name ks_meta = s.cluster.metadata.keyspaces[ks] t = self.function_table_name + v = t + 'view' s.execute("CREATE TABLE %s.%s (k text PRIMARY KEY, v int)" % (ks, t)) + s.execute("CREATE MATERIALIZED VIEW %s.%s AS SELECT * FROM %s.%s WHERE v IS NOT NULL PRIMARY KEY (v, k)" % (ks, v, ks, t)) table_meta = ks_meta.tables[t] + view_meta = table_meta.views[v] self.assertFalse(table_meta.extensions) - self.assertNotIn(t, table_meta._extension_registry) + self.assertFalse(view_meta.extensions) - original_cql = table_meta.export_as_string() + original_table_cql = table_meta.export_as_string() + original_view_cql = view_meta.export_as_string() # extensions registered, not present # -------------------------------------- @@ -887,44 +893,67 @@ class SchemaMetadataTests(BasicSegregatedKeyspaceUnitTestCase): name = t + '##' self.assertFalse(table_meta.extensions) - self.assertIn(Ext0.name, table_meta._extension_registry) - self.assertIn(Ext1.name, table_meta._extension_registry) - self.assertEqual(len(table_meta._extension_registry), 2) + self.assertFalse(view_meta.extensions) + self.assertIn(Ext0.name, _RegisteredExtensionType._extension_registry) + self.assertIn(Ext1.name, _RegisteredExtensionType._extension_registry) + self.assertEqual(len(_RegisteredExtensionType._extension_registry), 2) self.cluster.refresh_table_metadata(ks, t) table_meta = ks_meta.tables[t] + view_meta = table_meta.views[v] - self.assertEqual(table_meta.export_as_string(), original_cql) + self.assertEqual(table_meta.export_as_string(), original_table_cql) + self.assertEqual(view_meta.export_as_string(), original_view_cql) - p = s.prepare('UPDATE system_schema.tables SET extensions=? WHERE keyspace_name=? AND table_name=?') # for blob type coercing + update_t = s.prepare('UPDATE system_schema.tables SET extensions=? WHERE keyspace_name=? AND table_name=?') # for blob type coercing + update_v = s.prepare('UPDATE system_schema.views SET extensions=? WHERE keyspace_name=? AND view_name=?') # extensions registered, one present # -------------------------------------- ext_map = {Ext0.name: six.b("THA VALUE")} - [s.execute(p, (ext_map, ks, t)) for _ in self.cluster.metadata.all_hosts()] # we're manipulating metadata - do it on all hosts + [(s.execute(update_t, (ext_map, ks, t)), s.execute(update_v, (ext_map, ks, v))) + for _ in self.cluster.metadata.all_hosts()] # we're manipulating metadata - do it on all hosts self.cluster.refresh_table_metadata(ks, t) + self.cluster.refresh_materialized_view_metadata(ks, v) table_meta = ks_meta.tables[t] + view_meta = table_meta.views[v] self.assertIn(Ext0.name, table_meta.extensions) new_cql = table_meta.export_as_string() - self.assertNotEqual(new_cql, original_cql) + self.assertNotEqual(new_cql, original_table_cql) self.assertIn(Ext0.after_table_cql(table_meta, Ext0.name, ext_map[Ext0.name]), new_cql) self.assertNotIn(Ext1.name, new_cql) + self.assertIn(Ext0.name, view_meta.extensions) + new_cql = view_meta.export_as_string() + self.assertNotEqual(new_cql, original_view_cql) + self.assertIn(Ext0.after_table_cql(view_meta, Ext0.name, ext_map[Ext0.name]), new_cql) + self.assertNotIn(Ext1.name, new_cql) + # extensions registered, one present # -------------------------------------- ext_map = {Ext0.name: six.b("THA VALUE"), Ext1.name: six.b("OTHA VALUE")} - [s.execute(p, (ext_map, ks, t)) for _ in self.cluster.metadata.all_hosts()] # we're manipulating metadata - do it on all hosts + [(s.execute(update_t, (ext_map, ks, t)), s.execute(update_v, (ext_map, ks, v))) + for _ in self.cluster.metadata.all_hosts()] # we're manipulating metadata - do it on all hosts self.cluster.refresh_table_metadata(ks, t) + self.cluster.refresh_materialized_view_metadata(ks, v) table_meta = ks_meta.tables[t] + view_meta = table_meta.views[v] self.assertIn(Ext0.name, table_meta.extensions) self.assertIn(Ext1.name, table_meta.extensions) new_cql = table_meta.export_as_string() - self.assertNotEqual(new_cql, original_cql) + self.assertNotEqual(new_cql, original_table_cql) self.assertIn(Ext0.after_table_cql(table_meta, Ext0.name, ext_map[Ext0.name]), new_cql) self.assertIn(Ext1.after_table_cql(table_meta, Ext1.name, ext_map[Ext1.name]), new_cql) + self.assertIn(Ext0.name, view_meta.extensions) + self.assertIn(Ext1.name, view_meta.extensions) + new_cql = view_meta.export_as_string() + self.assertNotEqual(new_cql, original_view_cql) + self.assertIn(Ext0.after_table_cql(view_meta, Ext0.name, ext_map[Ext0.name]), new_cql) + self.assertIn(Ext1.after_table_cql(view_meta, Ext1.name, ext_map[Ext1.name]), new_cql) + class TestCodeCoverage(unittest.TestCase):