Projet

Général

Profil

0004-misc-migration-to-convert-python-datasources-72096.patch

Lauréline Guérin, 16 décembre 2022 18:35

Télécharger (12,2 ko)

Voir les différences:

Subject: [PATCH 4/4] misc: migration to convert python datasources (#72096)

 tests/test_sql.py | 173 +++++++++++++++++++++++++++++++++++++++++++++-
 wcs/sql.py        |  77 ++++++++++++++++++++-
 2 files changed, 248 insertions(+), 2 deletions(-)
tests/test_sql.py
12 12
import wcs.qommon.storage as st
13 13
from wcs import fields, sql
14 14
from wcs.blocks import BlockDef
15
from wcs.carddef import CardDef
16
from wcs.data_sources import NamedDataSource
15 17
from wcs.formdata import Evolution
16 18
from wcs.formdef import FormDef
17 19
from wcs.qommon import force_str
18 20
from wcs.wf.register_comment import RegisterCommenterWorkflowStatusItem
19
from wcs.workflows import Workflow, WorkflowCriticalityLevel
21
from wcs.workflows import Workflow, WorkflowBackofficeFieldsFormDef, WorkflowCriticalityLevel
20 22

  
21 23
from .utilities import clean_temporary_pub, create_temporary_pub
22 24

  
......
2278 2280

  
2279 2281
    lazy = sql.LazyEvolutionList(dump)
2280 2282
    assert list(pickle.loads(pickle.dumps(lazy))) == list(lazy)
2283

  
2284

  
2285
def test_python_datasource_migration(pub):
2286
    FormDef.wipe()
2287
    CardDef.wipe()
2288
    Workflow.wipe()
2289
    NamedDataSource.wipe()
2290

  
2291
    ds1 = {'type': 'formula', 'value': repr([('un'), ('deux')])}
2292
    ds2 = {'type': 'formula', 'value': repr([('1', 'un'), ('2', 'deux')])}
2293
    ds3 = {'type': 'formula', 'value': repr([('1', 'un', 'foo'), ('2', 'deux', 'bar')])}
2294
    ds4 = {'type': 'formula', 'value': repr([{'id': '1', 'text': 'un'}, {'id': '2', 'text': 'deux'}])}
2295
    failing_ds1 = {'type': 'formula', 'value': repr([{'id': '', 'text': 'un'}, {'id': '2', 'text': 'deux'}])}
2296
    failing_ds2 = {'type': 'formula', 'value': repr([{'id': '1', 'text': 'un'}, {'id': '2', 'text': ''}])}
2297
    failing_ds3 = {'type': 'formula', 'value': 'xxx()'}
2298

  
2299
    for i, ds in enumerate([ds1, ds2, ds3, ds4, failing_ds1, failing_ds2, failing_ds3]):
2300
        formdef = FormDef()
2301
        formdef.name = 'foobar %s' % i
2302
        formdef.fields = [
2303
            fields.ItemField(id='1', label='item', data_source=ds),
2304
        ]
2305
        formdef.store()
2306

  
2307
    for i, ds in enumerate([ds1, ds2, ds3, ds4, failing_ds1, failing_ds2, failing_ds3]):
2308
        carddef = CardDef()
2309
        carddef.name = 'foobar %s' % i
2310
        carddef.fields = [
2311
            fields.ItemField(id='1', label='item', data_source=ds),
2312
        ]
2313
        carddef.store()
2314

  
2315
    for i, ds in enumerate([ds1, ds2, ds3, ds4, failing_ds1, failing_ds2, failing_ds3]):
2316
        wf = Workflow()
2317
        wf.name = 'foobar %s' % i
2318
        wf.backoffice_fields_formdef = WorkflowBackofficeFieldsFormDef(wf)
2319
        wf.backoffice_fields_formdef.fields = [
2320
            fields.ItemField(id='1', label='item', data_source=ds),
2321
        ]
2322
        wf.store()
2323

  
2324
    for i, ds in enumerate([ds1, ds2, ds3, ds4, failing_ds1, failing_ds2, failing_ds3]):
2325
        data_source = NamedDataSource(name='foobar %s' % i)
2326
        data_source.data_source = ds
2327
        data_source.store()
2328

  
2329
        conn, cur = sql.get_connection_and_cursor()
2330

  
2331
    cur.execute('UPDATE wcs_meta SET value = 70 WHERE key = %s', ('sql_level',))
2332
    conn.commit()
2333
    cur.close()
2334

  
2335
    conn, cur = sql.get_connection_and_cursor()
2336
    sql.migrate()
2337

  
2338
    assert sql.is_reindex_needed('python_ds_migration', conn=conn, cur=cur) is True
2339
    sql.reindex()
2340

  
2341
    formdef = FormDef.get(1)
2342
    assert formdef.fields[0].data_source == {
2343
        'type': 'jsonvalue',
2344
        'value': '[{"id": "un", "text": "un"}, {"id": "deux", "text": "deux"}]',
2345
    }
2346
    formdef = FormDef.get(2)
2347
    assert formdef.fields[0].data_source == {
2348
        'type': 'jsonvalue',
2349
        'value': '[{"id": "1", "text": "un"}, {"id": "2", "text": "deux"}]',
2350
    }
2351
    formdef = FormDef.get(3)
2352
    assert formdef.fields[0].data_source == {
2353
        'type': 'jsonvalue',
2354
        'value': '[{"id": "1", "text": "un", "key": "foo"}, {"id": "2", "text": "deux", "key": "bar"}]',
2355
    }
2356
    formdef = FormDef.get(4)
2357
    assert formdef.fields[0].data_source == {
2358
        'type': 'jsonvalue',
2359
        'value': '[{"id": "1", "text": "un"}, {"id": "2", "text": "deux"}]',
2360
    }
2361
    formdef = FormDef.get(5)
2362
    assert formdef.fields[0].data_source == failing_ds1
2363
    formdef = FormDef.get(6)
2364
    assert formdef.fields[0].data_source == failing_ds2
2365
    formdef = FormDef.get(7)
2366
    assert formdef.fields[0].data_source == failing_ds3
2367

  
2368
    carddef = CardDef.get(1)
2369
    assert carddef.fields[0].data_source == {
2370
        'type': 'jsonvalue',
2371
        'value': '[{"id": "un", "text": "un"}, {"id": "deux", "text": "deux"}]',
2372
    }
2373
    carddef = CardDef.get(2)
2374
    assert carddef.fields[0].data_source == {
2375
        'type': 'jsonvalue',
2376
        'value': '[{"id": "1", "text": "un"}, {"id": "2", "text": "deux"}]',
2377
    }
2378
    carddef = CardDef.get(3)
2379
    assert carddef.fields[0].data_source == {
2380
        'type': 'jsonvalue',
2381
        'value': '[{"id": "1", "text": "un", "key": "foo"}, {"id": "2", "text": "deux", "key": "bar"}]',
2382
    }
2383
    carddef = CardDef.get(4)
2384
    assert carddef.fields[0].data_source == {
2385
        'type': 'jsonvalue',
2386
        'value': '[{"id": "1", "text": "un"}, {"id": "2", "text": "deux"}]',
2387
    }
2388
    carddef = CardDef.get(5)
2389
    assert carddef.fields[0].data_source == failing_ds1
2390
    carddef = CardDef.get(6)
2391
    assert carddef.fields[0].data_source == failing_ds2
2392
    carddef = CardDef.get(7)
2393
    assert carddef.fields[0].data_source == failing_ds3
2394

  
2395
    wf = Workflow.get(1)
2396
    assert wf.backoffice_fields_formdef.fields[0].data_source == {
2397
        'type': 'jsonvalue',
2398
        'value': '[{"id": "un", "text": "un"}, {"id": "deux", "text": "deux"}]',
2399
    }
2400
    wf = Workflow.get(2)
2401
    assert wf.backoffice_fields_formdef.fields[0].data_source == {
2402
        'type': 'jsonvalue',
2403
        'value': '[{"id": "1", "text": "un"}, {"id": "2", "text": "deux"}]',
2404
    }
2405
    wf = Workflow.get(3)
2406
    assert wf.backoffice_fields_formdef.fields[0].data_source == {
2407
        'type': 'jsonvalue',
2408
        'value': '[{"id": "1", "text": "un", "key": "foo"}, {"id": "2", "text": "deux", "key": "bar"}]',
2409
    }
2410
    wf = Workflow.get(4)
2411
    assert wf.backoffice_fields_formdef.fields[0].data_source == {
2412
        'type': 'jsonvalue',
2413
        'value': '[{"id": "1", "text": "un"}, {"id": "2", "text": "deux"}]',
2414
    }
2415
    wf = Workflow.get(5)
2416
    assert wf.backoffice_fields_formdef.fields[0].data_source == failing_ds1
2417
    wf = Workflow.get(6)
2418
    assert wf.backoffice_fields_formdef.fields[0].data_source == failing_ds2
2419
    wf = Workflow.get(7)
2420
    assert wf.backoffice_fields_formdef.fields[0].data_source == failing_ds3
2421

  
2422
    data_source = NamedDataSource.get(1)
2423
    assert data_source.data_source == {
2424
        'type': 'jsonvalue',
2425
        'value': '[{"id": "un", "text": "un"}, {"id": "deux", "text": "deux"}]',
2426
    }
2427
    data_source = NamedDataSource.get(2)
2428
    assert data_source.data_source == {
2429
        'type': 'jsonvalue',
2430
        'value': '[{"id": "1", "text": "un"}, {"id": "2", "text": "deux"}]',
2431
    }
2432
    data_source = NamedDataSource.get(3)
2433
    assert data_source.data_source == {
2434
        'type': 'jsonvalue',
2435
        'value': '[{"id": "1", "text": "un", "key": "foo"}, {"id": "2", "text": "deux", "key": "bar"}]',
2436
    }
2437
    data_source = NamedDataSource.get(4)
2438
    assert data_source.data_source == {
2439
        'type': 'jsonvalue',
2440
        'value': '[{"id": "1", "text": "un"}, {"id": "2", "text": "deux"}]',
2441
    }
2442
    data_source = NamedDataSource.get(5)
2443
    assert data_source.data_source == failing_ds1
2444
    data_source = NamedDataSource.get(6)
2445
    assert data_source.data_source == failing_ds2
2446
    data_source = NamedDataSource.get(7)
2447
    assert data_source.data_source == failing_ds3
2448

  
2449
    # check it's no longer needed afterwards
2450
    sql.migrate()
2451
    assert sql.is_reindex_needed('python_ds_migration', conn=conn, cur=cur) is False
wcs/sql.py
17 17
import copy
18 18
import datetime
19 19
import io
20
import itertools
20 21
import json
21 22
import re
22 23
import time
......
4659 4660
# latest migration, number + description (description is not used
4660 4661
# programmaticaly but will make sure git conflicts if two migrations are
4661 4662
# separately added with the same number)
4662
SQL_LEVEL = (70, 'repair anonymisation')
4663
SQL_LEVEL = (71, 'python datasource migration')
4663 4664

  
4664 4665

  
4665 4666
def migrate_global_views(conn, cur):
......
4943 4944
        for formdef in FormDef.select():
4944 4945
            do_formdef_tables(formdef, rebuild_views=False, rebuild_global_views=False)
4945 4946

  
4947
    if sql_level < 71:
4948
        # 71: python datasource migration
4949
        set_reindex('python_ds_migration', 'needed', conn=conn, cur=cur)
4950

  
4946 4951
    if sql_level != SQL_LEVEL[0]:
4947 4952
        cur.execute(
4948 4953
            '''UPDATE wcs_meta SET value = %s, updated_at=NOW() WHERE key = %s''',
......
4976 4981
                    print('error reindexing %s (%r)' % (formdata, e))
4977 4982
        set_reindex('formdata', 'done', conn=conn, cur=cur)
4978 4983

  
4984
    if is_reindex_needed('python_ds_migration', conn=conn, cur=cur):
4985
        # migrate python datasource
4986

  
4987
        def migrate_value(value):
4988
            try:
4989
                value = eval(value)
4990
            except Exception:
4991
                return
4992
            if len(value) == 0:
4993
                return []
4994
            if isinstance(value[0], (list, tuple)):
4995
                if len(value[0]) >= 3:
4996
                    return [{'id': x[0], 'text': x[1], 'key': x[2]} for x in value]
4997
                elif len(value[0]) == 2:
4998
                    return [{'id': x[0], 'text': x[1]} for x in value]
4999
                elif len(value[0]) == 1:
5000
                    return [{'id': x[0], 'text': x[0]} for x in value]
5001
                return value
5002
            elif isinstance(value[0], str):
5003
                return [{'id': x, 'text': x} for x in value]
5004
            elif isinstance(value[0], dict):
5005
                if all(str(x.get('id', '')) and x.get('text') for x in value):
5006
                    return value
5007

  
5008
        def migrate_field(field):
5009
            if not getattr(field, 'data_source', None):
5010
                return
5011
            data_source_type = field.data_source.get('type')
5012
            if data_source_type != 'formula':
5013
                return
5014
            value = migrate_value(field.data_source.get('value'))
5015

  
5016
            if value is not None:
5017
                field.data_source['type'] = 'jsonvalue'
5018
                field.data_source['value'] = json.dumps(value)
5019
                return True
5020

  
5021
        for formdef in itertools.chain(FormDef.select(), CardDef.select()):
5022
            changed = False
5023
            for field in formdef.fields or []:
5024
                changed |= bool(migrate_field(field))
5025
            if changed:
5026
                formdef.store(comment=_('Automatic update'), snapshot_store_user=False)
5027

  
5028
        from wcs.workflows import Workflow
5029

  
5030
        for workflow in Workflow.select():
5031
            changed = False
5032
            if workflow.backoffice_fields_formdef and workflow.backoffice_fields_formdef.fields:
5033
                for field in workflow.backoffice_fields_formdef.fields:
5034
                    changed |= bool(migrate_field(field))
5035
            if changed:
5036
                workflow.store(
5037
                    migration_update=True, comment=_('Automatic update'), snapshot_store_user=False
5038
                )
5039

  
5040
        from wcs.data_sources import NamedDataSource
5041

  
5042
        for datasource in NamedDataSource.select():
5043
            data_source = datasource.data_source
5044
            if not data_source.get('type') == 'formula':
5045
                continue
5046
            value = migrate_value(data_source.get('value'))
5047
            if value is not None:
5048
                datasource.data_source['type'] = 'jsonvalue'
5049
                datasource.data_source['value'] = json.dumps(value)
5050
                datasource.store(comment=_('Automatic update'), snapshot_store_user=False)
5051

  
5052
        set_reindex('python_ds_migration', 'done', conn=conn, cur=cur)
5053

  
4979 5054
    conn.commit()
4980 5055
    cur.close()
4981 5056

  
4982
-