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

test_upserting()   F

Complexity

Conditions 12

Size

Total Lines 40

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 12
c 1
b 0
f 0
dl 0
loc 40
rs 2.7855

How to fix   Complexity   

Complexity

Complex classes like test_upserting() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

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