Passed
Push — master ( 626055...8f2304 )
by Swen
01:01 queued 13s
created

test_inserting()   B

Complexity

Conditions 5

Size

Total Lines 35

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
c 1
b 0
f 0
dl 0
loc 35
rs 8.0894
1
import pytest
2
3
from psqlextra.indexes import ConditionalUniqueIndex
4
from .migrations import MigrationSimulator
5
6
from django.db import models, IntegrityError, transaction
0 ignored issues
show
Configuration introduced by
The import django.db could not be resolved.

This can be caused by one of the following:

1. Missing Dependencies

This error could indicate a configuration issue of Pylint. Make sure that your libraries are available by adding the necessary commands.

# .scrutinizer.yml
before_commands:
    - sudo pip install abc # Python2
    - sudo pip3 install abc # Python3
Tip: We are currently not using virtualenv to run pylint, when installing your modules make sure to use the command for the correct version.

2. Missing __init__.py files

This error could also result from missing __init__.py files in your module folders. Make sure that you place one file in each sub-folder.

Loading history...
7
from django.db.migrations import AddIndex, CreateModel
0 ignored issues
show
Configuration introduced by
The import django.db.migrations could not be resolved.

This can be caused by one of the following:

1. Missing Dependencies

This error could indicate a configuration issue of Pylint. Make sure that your libraries are available by adding the necessary commands.

# .scrutinizer.yml
before_commands:
    - sudo pip install abc # Python2
    - sudo pip3 install abc # Python3
Tip: We are currently not using virtualenv to run pylint, when installing your modules make sure to use the command for the correct version.

2. Missing __init__.py files

This error could also result from missing __init__.py files in your module folders. Make sure that you place one file in each sub-folder.

Loading history...
8
9
from .util import get_fake_model
10
11
12
def test_deconstruct():
13
    """Tests whether the :see:HStoreField's deconstruct()
14
    method works properly."""
15
16
    original_kwargs = dict(condition='field IS NULL', name='great_index', fields=['field', 'build'])
17
    _, _, new_kwargs = ConditionalUniqueIndex(**original_kwargs).deconstruct()
0 ignored issues
show
Coding Style introduced by
Usage of * or ** arguments should usually be done with care.

Generally, there is nothing wrong with usage of * or ** arguments. For readability of the code base, we suggest to not over-use these language constructs though.

For more information, we can recommend this blog post from Ned Batchelder including its comments which also touches this aspect.

Loading history...
18
19
    for key, value in original_kwargs.items():
20
        assert new_kwargs[key] == value
21
22
23
def test_migrations():
24
    """Tests whether the migrations are properly generated and executed."""
25
26
    simulator = MigrationSimulator()
27
28
    Model = simulator.define_model(
29
        fields={
30
            'id': models.IntegerField(primary_key=True),
31
            'name': models.CharField(max_length=255, null=True),
32
            'other_name': models.CharField(max_length=255)
33
        },
34
        meta_options={
35
            'indexes': [
36
                ConditionalUniqueIndex(
37
                    fields=['name', 'other_name'],
38
                    condition='"name" IS NOT NULL',
39
                    name='index1'
40
                ),
41
                ConditionalUniqueIndex(
42
                    fields=['other_name'],
43
                    condition='"name" IS NULL',
44
                    name='index2'
45
                )
46
            ]
47
        }
48
    )
49
50
    migration = simulator.make_migrations()
51
    assert len(migration.operations) == 3
52
53
    operations = migration.operations
54
    assert isinstance(operations[0], CreateModel)
55
56
    for operation in operations[1:]:
57
        assert isinstance(operation, AddIndex)
58
59
    calls = [call[0] for _, call, _ in simulator.migrate('CREATE UNIQUE INDEX')[0]['CREATE UNIQUE INDEX']]
60
61
    db_table = Model._meta.db_table
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like _meta was declared protected and should not be accessed from this context.

Prefixing a member variable _ is usually regarded as the equivalent of declaring it with protected visibility that exists in other languages. Consequentially, such a member should only be accessed from the same class or a child class:

class MyParent:
    def __init__(self):
        self._x = 1;
        self.y = 2;

class MyChild(MyParent):
    def some_method(self):
        return self._x    # Ok, since accessed from a child class

class AnotherClass:
    def some_method(self, instance_of_my_child):
        return instance_of_my_child._x   # Would be flagged as AnotherClass is not
                                         # a child class of MyParent
Loading history...
62
    assert calls[0] == 'CREATE UNIQUE INDEX "index1" ON "{0}" ("name", "other_name") WHERE "name" IS NOT NULL'.format(
63
        db_table
64
    )
65
    assert calls[1] == 'CREATE UNIQUE INDEX "index2" ON "{0}" ("other_name") WHERE "name" IS NULL'.format(
66
        db_table
67
    )
68
69
    with transaction.atomic():
70
        Model.objects.create(id=1, name="name", other_name="other_name")
71
        with pytest.raises(IntegrityError):
72
            Model.objects.create(id=2, name="name", other_name="other_name")
73
74
    with transaction.atomic():
75
        Model.objects.create(id=1, name=None, other_name="other_name")
76
        with pytest.raises(IntegrityError):
77
            Model.objects.create(id=2, name=None, other_name="other_name")
78
79
80
def test_upserting():
81
    """Tests upserting respects the :see:ConditionalUniqueIndex rules"""
82
    model = get_fake_model(
83
        fields={
84
            'a': models.IntegerField(),
85
            'b': models.IntegerField(null=True),
86
            'c': models.IntegerField(),
87
        },
88
        meta_options={
89
            'indexes': [
90
                ConditionalUniqueIndex(
91
                    fields=['a', 'b'],
92
                    condition='"b" IS NOT NULL'
93
                ),
94
                ConditionalUniqueIndex(
95
                    fields=['a'],
96
                    condition='"b" IS NULL'
97
                )
98
            ]
99
        }
100
    )
101
102
    model.objects.upsert(conflict_target=['a'], index_predicate='"b" IS NULL', fields=dict(a=1, c=1))
103
    assert model.objects.all().count() == 1
104
    assert model.objects.filter(a=1, c=1).count() == 1
105
106
    model.objects.upsert(conflict_target=['a'], index_predicate='"b" IS NULL', fields=dict(a=1, c=2))
107
    assert model.objects.all().count() == 1
108
    assert model.objects.filter(a=1, c=1).count() == 0
109
    assert model.objects.filter(a=1, c=2).count() == 1
110
111
    model.objects.upsert(conflict_target=['a', 'b'], index_predicate='"b" IS NOT NULL', fields=dict(a=1, b=1, c=1))
112
    assert model.objects.all().count() == 2
113
    assert model.objects.filter(a=1, c=2).count() == 1
114
    assert model.objects.filter(a=1, b=1, c=1).count() == 1
115
116
    model.objects.upsert(conflict_target=['a', 'b'], index_predicate='"b" IS NOT NULL', fields=dict(a=1, b=1, c=2))
117
    assert model.objects.all().count() == 2
118
    assert model.objects.filter(a=1, c=1).count() == 0
119
    assert model.objects.filter(a=1, b=1, c=2).count() == 1
120
121
122
def test_inserting():
123
    """Tests inserting respects the :see:ConditionalUniqueIndex rules"""
124
125
    model = get_fake_model(
126
        fields={
127
            'a': models.IntegerField(),
128
            'b': models.IntegerField(null=True),
129
            'c': models.IntegerField(),
130
        },
131
        meta_options={
132
            'indexes': [
133
                ConditionalUniqueIndex(
134
                    fields=['a', 'b'],
135
                    condition='"b" IS NOT NULL'
136
                ),
137
                ConditionalUniqueIndex(
138
                    fields=['a'],
139
                    condition='"b" IS NULL'
140
                )
141
            ]
142
        }
143
    )
144
145
    model.objects.create(a=1, c=1)
146
    with transaction.atomic():
147
        with pytest.raises(IntegrityError):
148
            model.objects.create(a=1, c=2)
149
    model.objects.create(a=2, c=1)
150
151
    model.objects.create(a=1, b=1, c=1)
152
    with transaction.atomic():
153
        with pytest.raises(IntegrityError):
154
            model.objects.create(a=1, b=1, c=2)
155
156
    model.objects.create(a=1, b=2, c=1)
157