Projet

Général

Profil

0003-misc-add-migration-to-ensure-jsonb-type-42312.patch

Valentin Deniaud, 05 mai 2020 10:08

Télécharger (18,9 ko)

Voir les différences:

Subject: [PATCH 3/3] misc: add migration to ensure jsonb type (#42312)

 .../migrations/0004_text_to_jsonb.py          | 18 +++++++
 .../migrations/0018_text_to_jsonb.py          | 18 +++++++
 .../migrations/0012_text_to_jsonb.py          | 21 ++++++++
 .../migrations/0018_text_to_jsonb.py          | 19 +++++++
 .../gesbac/migrations/0004_text_to_jsonb.py   | 19 +++++++
 .../migrations/0008_text_to_jsonb.py          | 18 +++++++
 .../migrations/0003_text_to_jsonb.py          | 18 +++++++
 .../opengis/migrations/0011_text_to_jsonb.py  | 18 +++++++
 .../pastell/migrations/0008_text_to_jsonb.py  | 18 +++++++
 .../migrations/0002_text_to_jsonb.py          | 18 +++++++
 .../sp_fr/migrations/0003_text_to_jsonb.py    | 18 +++++++
 .../base/migrations/0019_text_to_jsonb.py     | 20 +++++++
 .../migrations/0006_text_to_jsonb.py          | 18 +++++++
 .../migrations/0005_text_to_jsonb.py          | 18 +++++++
 .../migrations/0006_text_to_jsonb.py          | 18 +++++++
 .../migrations/0009_text_to_jsonb.py          | 18 +++++++
 passerelle/utils/db.py                        | 53 +++++++++++++++++++
 tests/test_misc.py                            | 41 ++++++++++++++
 18 files changed, 389 insertions(+)
 create mode 100644 passerelle/apps/atos_genesys/migrations/0004_text_to_jsonb.py
 create mode 100644 passerelle/apps/base_adresse/migrations/0018_text_to_jsonb.py
 create mode 100644 passerelle/apps/cartads_cs/migrations/0012_text_to_jsonb.py
 create mode 100644 passerelle/apps/csvdatasource/migrations/0018_text_to_jsonb.py
 create mode 100644 passerelle/apps/gesbac/migrations/0004_text_to_jsonb.py
 create mode 100644 passerelle/apps/jsondatastore/migrations/0008_text_to_jsonb.py
 create mode 100644 passerelle/apps/mdel_ddpacs/migrations/0003_text_to_jsonb.py
 create mode 100644 passerelle/apps/opengis/migrations/0011_text_to_jsonb.py
 create mode 100644 passerelle/apps/pastell/migrations/0008_text_to_jsonb.py
 create mode 100644 passerelle/apps/phonecalls/migrations/0002_text_to_jsonb.py
 create mode 100644 passerelle/apps/sp_fr/migrations/0003_text_to_jsonb.py
 create mode 100644 passerelle/base/migrations/0019_text_to_jsonb.py
 create mode 100644 passerelle/contrib/fake_family/migrations/0006_text_to_jsonb.py
 create mode 100644 passerelle/contrib/meyzieu_newsletters/migrations/0005_text_to_jsonb.py
 create mode 100644 passerelle/contrib/planitech/migrations/0006_text_to_jsonb.py
 create mode 100644 passerelle/contrib/teamnet_axel/migrations/0009_text_to_jsonb.py
 create mode 100644 passerelle/utils/db.py
passerelle/apps/atos_genesys/migrations/0004_text_to_jsonb.py
1
# -*- coding: utf-8 -*-
2
# Generated by Django 1.11.18 on 2020-05-04 12:06
3
from __future__ import unicode_literals
4

  
5
from django.db import migrations
6

  
7
from passerelle.utils.db import EnsureJsonbType
8

  
9

  
10
class Migration(migrations.Migration):
11

  
12
    dependencies = [
13
        ('atos_genesys', '0003_auto_20200504_1402'),
14
    ]
15

  
16
    operations = [
17
        EnsureJsonbType(model_name='Link', field_name='extra'),
18
    ]
passerelle/apps/base_adresse/migrations/0018_text_to_jsonb.py
1
# -*- coding: utf-8 -*-
2
# Generated by Django 1.11.18 on 2020-05-04 12:06
3
from __future__ import unicode_literals
4

  
5
from django.db import migrations
6

  
7
from passerelle.utils.db import EnsureJsonbType
8

  
9

  
10
class Migration(migrations.Migration):
11

  
12
    dependencies = [
13
        ('base_adresse', '0017_auto_20200504_1402'),
14
    ]
15

  
16
    operations = [
17
        EnsureJsonbType(model_name='AddressCacheModel', field_name='data'),
18
    ]
passerelle/apps/cartads_cs/migrations/0012_text_to_jsonb.py
1
# -*- coding: utf-8 -*-
2
# Generated by Django 1.11.18 on 2020-05-04 12:06
3
from __future__ import unicode_literals
4

  
5
from django.db import migrations
6

  
7
from passerelle.utils.db import EnsureJsonbType
8

  
9

  
10
class Migration(migrations.Migration):
11

  
12
    dependencies = [
13
        ('cartads_cs', '0011_cartadsdossier_cartads_cache_infos'),
14
    ]
15

  
16
    operations = [
17
        EnsureJsonbType(model_name='CartaDSDataCache', field_name='data_parameters'),
18
        EnsureJsonbType(model_name='CartaDSDataCache', field_name='data_values'),
19
        EnsureJsonbType(model_name='cartadsdossier', field_name='cartads_steps_cache'),
20
        EnsureJsonbType(model_name='cartadsdossier', field_name='cartads_cache_infos'),
21
    ]
passerelle/apps/csvdatasource/migrations/0018_text_to_jsonb.py
1
# -*- coding: utf-8 -*-
2
# Generated by Django 1.11.18 on 2020-05-04 12:06
3
from __future__ import unicode_literals
4

  
5
from django.db import migrations
6

  
7
from passerelle.utils.db import EnsureJsonbType
8

  
9

  
10
class Migration(migrations.Migration):
11

  
12
    dependencies = [
13
        ('csvdatasource', '0017_auto_20200504_1402'),
14
    ]
15

  
16
    operations = [
17
        EnsureJsonbType(model_name='csvdatasource', field_name='_dialect_options'),
18
        EnsureJsonbType(model_name='TableRow', field_name='data'),
19
    ]
passerelle/apps/gesbac/migrations/0004_text_to_jsonb.py
1
# -*- coding: utf-8 -*-
2
# Generated by Django 1.11.18 on 2020-05-04 12:06
3
from __future__ import unicode_literals
4

  
5
from django.db import migrations
6

  
7
from passerelle.utils.db import EnsureJsonbType
8

  
9

  
10
class Migration(migrations.Migration):
11

  
12
    dependencies = [
13
        ('gesbac', '0003_auto_20200504_1402'),
14
    ]
15

  
16
    operations = [
17
        EnsureJsonbType(model_name='Form', field_name='demand_data'),
18
        EnsureJsonbType(model_name='Form', field_name='card_data'),
19
    ]
passerelle/apps/jsondatastore/migrations/0008_text_to_jsonb.py
1
# -*- coding: utf-8 -*-
2
# Generated by Django 1.11.18 on 2020-05-04 12:06
3
from __future__ import unicode_literals
4

  
5
from django.db import migrations
6

  
7
from passerelle.utils.db import EnsureJsonbType
8

  
9

  
10
class Migration(migrations.Migration):
11

  
12
    dependencies = [
13
        ('jsondatastore', '0007_auto_20200504_1402'),
14
    ]
15

  
16
    operations = [
17
        EnsureJsonbType(model_name='JsonData', field_name='content'),
18
    ]
passerelle/apps/mdel_ddpacs/migrations/0003_text_to_jsonb.py
1
# -*- coding: utf-8 -*-
2
# Generated by Django 1.11.18 on 2020-05-04 12:06
3
from __future__ import unicode_literals
4

  
5
from django.db import migrations
6

  
7
from passerelle.utils.db import EnsureJsonbType
8

  
9

  
10
class Migration(migrations.Migration):
11

  
12
    dependencies = [
13
        ('mdel_ddpacs', '0002_auto_20200504_1402'),
14
    ]
15

  
16
    operations = [
17
        EnsureJsonbType(model_name='Demand', field_name='data'),
18
    ]
passerelle/apps/opengis/migrations/0011_text_to_jsonb.py
1
# -*- coding: utf-8 -*-
2
# Generated by Django 1.11.18 on 2020-05-04 12:06
3
from __future__ import unicode_literals
4

  
5
from django.db import migrations
6

  
7
from passerelle.utils.db import EnsureJsonbType
8

  
9

  
10
class Migration(migrations.Migration):
11

  
12
    dependencies = [
13
        ('opengis', '0010_auto_20200504_1402'),
14
    ]
15

  
16
    operations = [
17
        EnsureJsonbType(model_name='FeatureCache', field_name='data'),
18
    ]
passerelle/apps/pastell/migrations/0008_text_to_jsonb.py
1
# -*- coding: utf-8 -*-
2
# Generated by Django 1.11.18 on 2020-05-04 12:06
3
from __future__ import unicode_literals
4

  
5
from django.db import migrations
6

  
7
from passerelle.utils.db import EnsureJsonbType
8

  
9

  
10
class Migration(migrations.Migration):
11

  
12
    dependencies = [
13
        ('pastell', '0007_auto_20200504_1402'),
14
    ]
15

  
16
    operations = [
17
        EnsureJsonbType(model_name='Pastell', field_name='document_fields'),
18
    ]
passerelle/apps/phonecalls/migrations/0002_text_to_jsonb.py
1
# -*- coding: utf-8 -*-
2
# Generated by Django 1.11.18 on 2020-05-04 12:06
3
from __future__ import unicode_literals
4

  
5
from django.db import migrations
6

  
7
from passerelle.utils.db import EnsureJsonbType
8

  
9

  
10
class Migration(migrations.Migration):
11

  
12
    dependencies = [
13
        ('phonecalls', '0001_initial'),
14
    ]
15

  
16
    operations = [
17
        EnsureJsonbType(model_name='Call', field_name='details'),
18
    ]
passerelle/apps/sp_fr/migrations/0003_text_to_jsonb.py
1
# -*- coding: utf-8 -*-
2
# Generated by Django 1.11.18 on 2020-05-04 12:06
3
from __future__ import unicode_literals
4

  
5
from django.db import migrations
6

  
7
from passerelle.utils.db import EnsureJsonbType
8

  
9

  
10
class Migration(migrations.Migration):
11

  
12
    dependencies = [
13
        ('sp_fr', '0002_auto_20200504_1402'),
14
    ]
15

  
16
    operations = [
17
        EnsureJsonbType(model_name='Mapping', field_name='rules'),
18
    ]
passerelle/base/migrations/0019_text_to_jsonb.py
1
# -*- coding: utf-8 -*-
2
# Generated by Django 1.11.18 on 2020-05-04 12:06
3
from __future__ import unicode_literals
4

  
5
from django.db import migrations
6

  
7
from passerelle.utils.db import EnsureJsonbType
8

  
9

  
10
class Migration(migrations.Migration):
11

  
12
    dependencies = [
13
        ('base', '0018_smslog'),
14
    ]
15

  
16
    operations = [
17
        EnsureJsonbType(model_name='ResourceLog', field_name='extra'),
18
        EnsureJsonbType(model_name='Job', field_name='parameters'),
19
        EnsureJsonbType(model_name='Job', field_name='status_details'),
20
    ]
passerelle/contrib/fake_family/migrations/0006_text_to_jsonb.py
1
# -*- coding: utf-8 -*-
2
# Generated by Django 1.11.18 on 2020-05-04 12:06
3
from __future__ import unicode_literals
4

  
5
from django.db import migrations
6

  
7
from passerelle.utils.db import EnsureJsonbType
8

  
9

  
10
class Migration(migrations.Migration):
11

  
12
    dependencies = [
13
        ('fake_family', '0005_auto_20200504_1402'),
14
    ]
15

  
16
    operations = [
17
        EnsureJsonbType(model_name='FakeFamily', field_name='jsondatabase'),
18
    ]
passerelle/contrib/meyzieu_newsletters/migrations/0005_text_to_jsonb.py
1
# -*- coding: utf-8 -*-
2
# Generated by Django 1.11.18 on 2020-05-04 12:06
3
from __future__ import unicode_literals
4

  
5
from django.db import migrations
6

  
7
from passerelle.utils.db import EnsureJsonbType
8

  
9

  
10
class Migration(migrations.Migration):
11

  
12
    dependencies = [
13
        ('meyzieu_newsletters', '0004_remove_meyzieunewsletters_log_level'),
14
    ]
15

  
16
    operations = [
17
        EnsureJsonbType(model_name='MeyzieuNewsletters', field_name='transport_titles_mapping'),
18
    ]
passerelle/contrib/planitech/migrations/0006_text_to_jsonb.py
1
# -*- coding: utf-8 -*-
2
# Generated by Django 1.11.18 on 2020-05-04 12:06
3
from __future__ import unicode_literals
4

  
5
from django.db import migrations
6

  
7
from passerelle.utils.db import EnsureJsonbType
8

  
9

  
10
class Migration(migrations.Migration):
11

  
12
    dependencies = [
13
        ('planitech', '0005_auto_20200504_1402'),
14
    ]
15

  
16
    operations = [
17
        EnsureJsonbType(model_name='planitechconnector', field_name='custom_fields'),
18
    ]
passerelle/contrib/teamnet_axel/migrations/0009_text_to_jsonb.py
1
# -*- coding: utf-8 -*-
2
# Generated by Django 1.11.18 on 2020-05-04 12:06
3
from __future__ import unicode_literals
4

  
5
from django.db import migrations
6

  
7
from passerelle.utils.db import EnsureJsonbType
8

  
9

  
10
class Migration(migrations.Migration):
11

  
12
    dependencies = [
13
        ('teamnet_axel', '0008_auto_20200504_1402'),
14
    ]
15

  
16
    operations = [
17
        EnsureJsonbType(model_name='TeamnetAxel', field_name='billing_regies'),
18
    ]
passerelle/utils/db.py
1
# passerelle - uniform access to multiple data sources and services
2
# Copyright (C) 2020 Entr'ouvert
3
#
4
# This program is free software: you can redistribute it and/or modify it
5
# under the terms of the GNU Affero General Public License as published
6
# by the Free Software Foundation, either version 3 of the License, or
7
# (at your option) any later version.
8
#
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU Affero General Public License for more details.
13
#
14
# You should have received a copy of the GNU Affero General Public License
15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16

  
17
from django.db.migrations.operations.base import Operation
18

  
19

  
20
class EnsureJsonbType(Operation):
21

  
22
    reversible = True
23

  
24
    def __init__(self, model_name, field_name):
25
        self.model_name = model_name
26
        self.field_name = field_name
27

  
28
    def state_forwards(self, app_label, state):
29
        pass
30

  
31
    def database_forwards(self, app_label, schema_editor, from_state, to_state):
32
        model = from_state.apps.get_model(app_label, self.model_name)
33
        table_name = model._meta.db_table
34
        field = model._meta.get_field(self.field_name)
35
        _, column_name = field.get_attname_column()
36
        with schema_editor.connection.cursor() as cursor:
37
            cursor.execute(
38
                'SELECT data_type FROM information_schema.columns WHERE table_name = %s AND '
39
                'column_name = %s;', (table_name, column_name)
40
            )
41
            current_type = cursor.fetchone()[0].lower()
42
            if current_type != 'jsonb':
43
                assert current_type in ('json', 'text')
44
                cursor.execute(
45
                    'ALTER TABLE {table} ALTER COLUMN {col} TYPE jsonb USING {col}::jsonb;'
46
                    .format(table=table_name, col=column_name)
47
                )
48

  
49
    def database_backwards(self, app_label, schema_editor, from_state, to_state):
50
        pass
51

  
52
    def describe(self):
53
        return "Migrate to postgres jsonb type"
tests/test_misc.py
2 2
import pytest
3 3
from mock import patch
4 4

  
5
from django.core.files import File
6
from django.db import connection
7
from django.db.migrations.executor import MigrationExecutor
5 8
from django.utils import timezone
9
from django.utils.six import StringIO
6 10

  
7 11
from passerelle.base.models import ResourceLog
8 12
from passerelle.apps.opengis.models import OpenGIS
......
88 92
        assert len(mailoutbox) == 2
89 93
        assert mailoutbox[0].to == ['admin@example.net']
90 94
        assert mailoutbox[1].to == ['john.doe@example.net']
95

  
96

  
97
def test_jsonb_migration(transactional_db):
98
    app = 'csvdatasource'
99

  
100
    migrate_from = [(app, '0017_auto_20200504_1402')]
101
    migrate_to = [(app, '0018_text_to_jsonb')]
102
    executor = MigrationExecutor(connection)
103
    old_apps = executor.loader.project_state(migrate_from).apps
104
    # state of the db is not important
105
    executor.migrate(migrate_from, fake=True)
106

  
107
    data = {'data': {'test': 1}}
108
    CsvDataSource = old_apps.get_model(app, 'CsvDataSource')
109
    connector = CsvDataSource.objects.create(csv_file=File(StringIO(''), 't.csv'),
110
                                             _dialect_options=data)
111
    pk = connector.pk
112

  
113
    field = CsvDataSource._meta.get_field('_dialect_options')
114
    with connection.cursor() as cursor:
115
        cursor.execute(
116
            'ALTER TABLE {table} ALTER COLUMN {col} TYPE text USING {col}::text;'
117
            .format(table=CsvDataSource._meta.db_table, col=field.get_attname_column()[1])
118
        )
119
    connector = CsvDataSource.objects.get(pk=pk)
120
    # db is in a broken state
121
    assert connector._dialect_options != data
122

  
123
    # ensure migration fixes it
124
    executor = MigrationExecutor(connection)
125
    executor.migrate(migrate_to)
126
    executor.loader.build_graph()
127

  
128
    apps = executor.loader.project_state(migrate_to).apps
129
    CsvDataSource = apps.get_model(app, 'CsvDataSource')
130
    connector = CsvDataSource.objects.get(pk=pk)
131
    assert connector._dialect_options == data
91
-