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
示例#2
0
 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,
     )
示例#3
0
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
示例#4
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
示例#5
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
示例#6
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)
示例#7
0
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)
示例#8
0
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"
示例#9
0
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
示例#11
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
示例#12
0
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
示例#13
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
示例#14
0
 def delete(
     self,
     model: PostgresPartitionedModel,
     schema_editor: PostgresSchemaEditor,
 ) -> None:
     schema_editor.delete_partition(model, self.name())