0003-misc-add-migration-to-ensure-jsonb-type-42312.patch
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 = False |
|
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 describe(self): |
|
50 |
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 |
- |