"""Streams active tables base model.""" import os from pynamodb.attributes import UnicodeAttribute from pynamodb.models import Model class ActiveTables(Model): """Model for active tables.""" class Meta: """Meta data for ActiveTables.""" table_name = '{env}_active_tables'.format( env=os.environ.get('Environment', 'dev')) table_type = UnicodeAttribute(hash_key=True) table_name = UnicodeAttribute() class DynamicModel(Model): """Base model for tables with dynamic names. You can subclass this model, if you want to create a model that is bound to a DynamoDB table with dynamic suffix. Please note, if you subclass from `DynamicModel`, you do not have to specify "{env}_" prefix for Meta.table_name. Since it will be used as a key to lookup the active table name. Example: Assume, that you have a table in dynamo DB, which is being recreated every day, and its name is "{env}_streams_vendor_totals_{X}. Where {X} is a suffix that is being changed for each new table. Then, the ETL should update a record in {env}_active_tables every time it recreates the table. The record with hash key "streams_vendor_totals" will contain full table name for the current active table. E.g. "dev_streams_vendor_totals_2". Your model, subclassed from `DynamicModel` will get the current active table name from {env}_active_tables before each query. Your model can look like this: class StreamsVendorTotals(DynamicModel): class Meta: table_name = 'streams_vendor_totals' some_field = UnicodeAttribute() some_other field = UnicodeAttribute() """ @classmethod def _get_connection(cls): """Get a cached DynamoDB table connection. Returns: TableConnection """ connection = super(DynamicModel, cls)._get_connection() connection.table_name = ActiveTables.get( hash_key=cls.Meta.table_name).table_name return connection @classmethod def get_noncached_connection(cls): """Return a NON-CACHED connection. We must override this method in source_of_streams ETL, but we can't do it just by standard overriding due to specifics of the pynamodb magic, so we have to import this alternative method and patch the attribute: E.g., in analytics_aggregation/flows/source_of_streams/config.py: from sosmodels.active_tables import get_noncached_connection from sosmodels.streams_vendor_placements import StreamsVendorPlacements StreamsVendorPlacements._get_connection = get_noncached_connection """ cls._connection = None # clears cached connection object, if exists connection = super(DynamicModel, cls)._get_connection() connection.table_name = cls.Meta.table_name return connection @classmethod def get_incremented_connection(cls): """Return a CACHED connection with an incremented table_name. We must override _get_connection() method in Lambdas. from sosmodels.active_tables import get_noncached_incremented_connection from sosmodels.streams_vendor_placements import StreamsVendorPlacements StreamsVendorPlacements._get_connection = get_noncached_incremented_connection """ connection = super(DynamicModel, cls)._get_connection() active_table_name = ActiveTables.get( hash_key=cls.Meta.table_name).table_name incremented_table_number = int(active_table_name.split('_')[-1]) + 1 incremented_table_name = '_'.join( active_table_name.split('_')[:-1]) + '_' + str( incremented_table_number) connection.table_name = incremented_table_name return connection