def test_materialized_view_model_refresh(): """Tests whether a materialized view can be refreshed.""" underlying_model = get_fake_model({"name": models.TextField()}) model = define_fake_materialized_view_model( {"name": models.TextField()}, {"query": underlying_model.objects.filter(name="test1")}, ) underlying_model.objects.create(name="test1") underlying_model.objects.create(name="test2") schema_editor = PostgresSchemaEditor(connection) schema_editor.create_materialized_view_model(model) # materialized view should only show records name="test"1 objs = list(model.objects.all()) assert len(objs) == 1 assert objs[0].name == "test1" # create another record with "test1" and refresh underlying_model.objects.create(name="test1") model.refresh() objs = list(model.objects.all()) assert len(objs) == 2
def create( self, model: PostgresPartitionedModel, schema_editor: PostgresSchemaEditor, comment: Optional[str] = None, ) -> None: schema_editor.add_range_partition( model=model, name=self.name(), from_values=self.from_values, to_values=self.to_values, comment=comment, )
def test_schema_editor_add_default_partition(method, key): model = define_fake_partitioned_model( { "name": models.TextField(), "timestamp": models.DateTimeField() }, { "method": method, "key": key }, ) schema_editor = PostgresSchemaEditor(connection) schema_editor.create_partitioned_model(model) schema_editor.add_default_partition(model, name="mypartition", comment="test") table = db_introspection.get_partitioned_table(model._meta.db_table) assert len(table.partitions) == 1 assert table.partitions[0].name == "mypartition" assert ( table.partitions[0].full_name == f"{model._meta.db_table}_mypartition") assert table.partitions[0].comment == "test" schema_editor.delete_partition(model, "mypartition") table = db_introspection.get_partitioned_table(model._meta.db_table) assert len(table.partitions) == 0
def test_schema_editor_add_list_partition(): """Tests whether adding a list partition works.""" model = define_fake_partitioned_model( {"name": models.TextField()}, { "method": PostgresPartitioningMethod.LIST, "key": ["name"] }, ) schema_editor = PostgresSchemaEditor(connection) schema_editor.create_partitioned_model(model) schema_editor.add_list_partition(model, name="mypartition", values=["1"], comment="test") table = db_introspection.get_partitioned_table(model._meta.db_table) assert len(table.partitions) == 1 assert table.partitions[0].name == "mypartition" assert ( table.partitions[0].full_name == f"{model._meta.db_table}_mypartition") assert table.partitions[0].comment == "test" schema_editor.delete_partition(model, "mypartition") table = db_introspection.get_partitioned_table(model._meta.db_table) assert len(table.partitions) == 0
def test_schema_editor_add_range_partition(): """Tests whether adding a range partition works.""" model = define_fake_partitioned_model( { "name": models.TextField(), "timestamp": models.DateTimeField() }, {"key": ["timestamp"]}, ) schema_editor = PostgresSchemaEditor(connection) schema_editor.create_partitioned_model(model) schema_editor.add_range_partition( model, name="mypartition", from_values="2019-1-1", to_values="2019-2-1", comment="test", ) table = db_introspection.get_partitioned_table(model._meta.db_table) assert len(table.partitions) == 1 assert table.partitions[0].name == "mypartition" assert ( table.partitions[0].full_name == f"{model._meta.db_table}_mypartition") assert table.partitions[0].comment == "test" schema_editor.delete_partition(model, "mypartition") table = db_introspection.get_partitioned_table(model._meta.db_table) assert len(table.partitions) == 0
def test_schema_editor_create_partitioned_model_no_key(): """Tests whether trying to create a partitioned model without a partitioning key raises :see:ImproperlyConfigured as its not possible to create a partitioned model without one and we cannot have a sane default.""" model = define_fake_partitioned_model( { "name": models.TextField(), "timestamp": models.DateTimeField() }, {"method": PostgresPartitioningMethod.RANGE}, ) schema_editor = PostgresSchemaEditor(connection) with pytest.raises(ImproperlyConfigured): schema_editor.create_partitioned_model(model)
def test_schema_editor_create_delete_materialized_view(): """Tests whether creating and then deleting a materialized view using the schema editor works as expected.""" underlying_model = get_fake_model({"name": models.TextField()}) model = define_fake_materialized_view_model( {"name": models.TextField()}, {"query": underlying_model.objects.filter(name="test1")}, ) underlying_model.objects.create(name="test1") underlying_model.objects.create(name="test2") schema_editor = PostgresSchemaEditor(connection) schema_editor.create_materialized_view_model(model) # materialized view should only show records name="test"1 objs = list(model.objects.all()) assert len(objs) == 1 assert objs[0].name == "test1" # delete the materialized view schema_editor.delete_materialized_view_model(model) # make sure it was actually deleted assert model._meta.db_table not in db_introspection.table_names(True)
def test_schema_editor_replace_view(): """Tests whether creating a view and then replacing it with another one (thus changing the backing query) works as expected.""" underlying_model = get_fake_model({"name": models.TextField()}) model = define_fake_view_model( {"name": models.TextField()}, {"query": underlying_model.objects.filter(name="test1")}, ) underlying_model.objects.create(name="test1") underlying_model.objects.create(name="test2") schema_editor = PostgresSchemaEditor(connection) schema_editor.create_view_model(model) objs = list(model.objects.all()) assert len(objs) == 1 assert objs[0].name == "test1" model._view_meta.query = underlying_model.objects.filter( name="test2" ).query.sql_with_params() schema_editor.replace_view_model(model) objs = list(model.objects.all()) assert len(objs) == 1 assert objs[0].name == "test2"
def test_schema_editor_create_partitioned_model_no_method(): """Tests whether its possible to create a partitioned model without explicitly setting a partitioning method. The default is "range" so setting one explicitely should not be needed. """ model = define_fake_partitioned_model( { "name": models.TextField(), "timestamp": models.DateTimeField() }, {"key": ["timestamp"]}, ) schema_editor = PostgresSchemaEditor(connection) schema_editor.create_partitioned_model(model) pt = db_introspection.get_partitioned_table(model._meta.db_table) assert pt.method == PostgresPartitioningMethod.RANGE assert len(pt.partitions) == 0
def test_schema_editor_create_delete_partitioned_model_list(): """Tests whether creating a partitioned model and adding a range partition to it using the. :see:PostgresSchemaEditor works. """ method = PostgresPartitioningMethod.LIST key = ["category"] model = define_fake_partitioning_model( {"name": models.TextField(), "category": models.TextField()}, {"method": method, "key": key}, ) schema_editor = PostgresSchemaEditor(connection) schema_editor.create_partitioned_model(model) schema_editor.add_list_partition(model, "pt1", ["car", "boat"]) with connection.cursor() as cursor: introspection = connection.introspection table = introspection.get_partitioned_table( cursor, model._meta.db_table ) assert table.name == model._meta.db_table assert table.method == method assert table.key == key assert table.partitions[0].name == model._meta.db_table + "_pt1" schema_editor.delete_partitioned_model(model) with connection.cursor() as cursor: introspection = connection.introspection table = introspection.get_partitioned_table( cursor, model._meta.db_table ) assert not table partitions = introspection.get_partitions(cursor, model._meta.db_table) assert len(partitions) == 0
def test_schema_editor_replace_materialized_view(): """Tests whether creating a materialized view and then replacing it with another one (thus changing the backing query) works as expected.""" underlying_model = get_fake_model({"name": models.TextField()}) model = define_fake_materialized_view_model( {"name": models.TextField()}, {"query": underlying_model.objects.filter(name="test1")}, {"indexes": [models.Index(fields=["name"])]}, ) underlying_model.objects.create(name="test1") underlying_model.objects.create(name="test2") schema_editor = PostgresSchemaEditor(connection) schema_editor.create_materialized_view_model(model) for index in model._meta.indexes: schema_editor.add_index(model, index) constraints_before = db_introspection.get_constraints(model._meta.db_table) objs = list(model.objects.all()) assert len(objs) == 1 assert objs[0].name == "test1" model._view_meta.query = underlying_model.objects.filter( name="test2" ).query.sql_with_params() schema_editor.replace_materialized_view_model(model) objs = list(model.objects.all()) assert len(objs) == 1 assert objs[0].name == "test2" # make sure all indexes/constraints still exists because # replacing a materialized view involves re-creating it constraints_after = db_introspection.get_constraints(model._meta.db_table) assert constraints_after == constraints_before
def test_schema_editor_create_delete_partitioned_model_default(): """Tests whether creating a partitioned model and adding a default partition to it using the :see:PostgresSchemaEditor works.""" method = PostgresPartitioningMethod.LIST key = ["category"] model = define_fake_partitioned_model( { "name": models.TextField(), "category": models.TextField() }, { "method": method, "key": key }, ) schema_editor = PostgresSchemaEditor(connection) schema_editor.create_partitioned_model(model) schema_editor.add_default_partition(model, "default") table = db_introspection.get_partitioned_table(model._meta.db_table) assert table.name == model._meta.db_table assert table.method == method assert table.key == key assert table.partitions[0].full_name == model._meta.db_table + "_default" schema_editor.delete_partitioned_model(model) table = db_introspection.get_partitioned_table(model._meta.db_table) assert not table partitions = db_introspection.get_partitions(model._meta.db_table) assert len(partitions) == 0
def test_schema_editor_create_delete_partitioned_model_range(): """Tests whether creating a partitioned model and adding a list partition to it using the :see:PostgresSchemaEditor works.""" method = PostgresPartitioningMethod.RANGE key = ["timestamp"] model = define_fake_partitioned_model( { "name": models.TextField(), "timestamp": models.DateTimeField() }, { "method": method, "key": key }, ) schema_editor = PostgresSchemaEditor(connection) schema_editor.create_partitioned_model(model) schema_editor.add_range_partition(model, "pt1", "2019-01-01", "2019-02-01") table = db_introspection.get_partitioned_table(model._meta.db_table) assert table.name == model._meta.db_table assert table.method == method assert table.key == key assert table.partitions[0].full_name == model._meta.db_table + "_pt1" schema_editor.delete_partitioned_model(model) table = db_introspection.get_partitioned_table(model._meta.db_table) assert not table partitions = db_introspection.get_partitions(model._meta.db_table) assert len(partitions) == 0
def delete( self, model: PostgresPartitionedModel, schema_editor: PostgresSchemaEditor, ) -> None: schema_editor.delete_partition(model, self.name())