15 # |
15 # |
16 # You should have received a copy of the GNU Lesser General Public License along |
16 # You should have received a copy of the GNU Lesser General Public License along |
17 # with CubicWeb. If not, see <http://www.gnu.org/licenses/>. |
17 # with CubicWeb. If not, see <http://www.gnu.org/licenses/>. |
18 """functions for schema / permissions (de)serialization using RQL""" |
18 """functions for schema / permissions (de)serialization using RQL""" |
19 |
19 |
20 from __future__ import print_function |
|
21 |
|
22 import json |
20 import json |
23 import sys |
21 import sys |
24 import sqlite3 |
22 import sqlite3 |
25 |
|
26 from six import PY2, text_type, string_types |
|
27 |
23 |
28 from logilab.common.shellutils import ProgressBar, DummyProgressBar |
24 from logilab.common.shellutils import ProgressBar, DummyProgressBar |
29 |
25 |
30 from yams import BadSchemaDefinition, schema as schemamod, buildobjs as ybo, constraints |
26 from yams import BadSchemaDefinition, schema as schemamod, buildobjs as ybo, constraints |
31 |
27 |
376 pb.update() |
372 pb.update() |
377 # serialize constraint types |
373 # serialize constraint types |
378 cstrtypemap = {} |
374 cstrtypemap = {} |
379 rql = 'INSERT CWConstraintType X: X name %(ct)s' |
375 rql = 'INSERT CWConstraintType X: X name %(ct)s' |
380 for cstrtype in CONSTRAINTS: |
376 for cstrtype in CONSTRAINTS: |
381 cstrtypemap[cstrtype] = execute(rql, {'ct': text_type(cstrtype)}, |
377 cstrtypemap[cstrtype] = execute(rql, {'ct': cstrtype}, |
382 build_descr=False)[0][0] |
378 build_descr=False)[0][0] |
383 pb.update() |
379 pb.update() |
384 # serialize relations |
380 # serialize relations |
385 for rschema in schema.relations(): |
381 for rschema in schema.relations(): |
386 # skip virtual relations such as eid, has_text and identity |
382 # skip virtual relations such as eid, has_text and identity |
481 restrictions = [] |
477 restrictions = [] |
482 substs = {} |
478 substs = {} |
483 for i, name in enumerate(unique_together): |
479 for i, name in enumerate(unique_together): |
484 rschema = eschema.schema.rschema(name) |
480 rschema = eschema.schema.rschema(name) |
485 rtype = 'T%d' % i |
481 rtype = 'T%d' % i |
486 substs[rtype] = text_type(rschema.type) |
482 substs[rtype] = rschema.type |
487 relations.append('C relations %s' % rtype) |
483 relations.append('C relations %s' % rtype) |
488 restrictions.append('%(rtype)s name %%(%(rtype)s)s' % {'rtype': rtype}) |
484 restrictions.append('%(rtype)s name %%(%(rtype)s)s' % {'rtype': rtype}) |
489 relations = ', '.join(relations) |
485 relations = ', '.join(relations) |
490 restrictions = ', '.join(restrictions) |
486 restrictions = ', '.join(restrictions) |
491 rql = ('INSERT CWUniqueTogetherConstraint C: C name %%(name)s, C constraint_of X, %s ' |
487 rql = ('INSERT CWUniqueTogetherConstraint C: C name %%(name)s, C constraint_of X, %s ' |
492 'WHERE X eid %%(x)s, %s') |
488 'WHERE X eid %%(x)s, %s') |
493 return rql % (relations, restrictions), substs |
489 return rql % (relations, restrictions), substs |
494 |
490 |
495 |
491 |
496 def _ervalues(erschema): |
492 def _ervalues(erschema): |
497 try: |
|
498 type_ = text_type(erschema.type) |
|
499 except UnicodeDecodeError as e: |
|
500 raise Exception("can't decode %s [was %s]" % (erschema.type, e)) |
|
501 try: |
|
502 desc = text_type(erschema.description) or u'' |
|
503 except UnicodeDecodeError as e: |
|
504 raise Exception("can't decode %s [was %s]" % (erschema.description, e)) |
|
505 return { |
493 return { |
506 'name': type_, |
494 'name': erschema.type, |
507 'final': erschema.final, |
495 'final': erschema.final, |
508 'description': desc, |
496 'description': erschema.description, |
509 } |
497 } |
510 |
498 |
511 # rtype serialization |
499 # rtype serialization |
512 |
500 |
513 def rschema2rql(rschema, cstrtypemap=None, addrdef=True, groupmap=None): |
501 def rschema2rql(rschema, cstrtypemap=None, addrdef=True, groupmap=None): |
529 def rschema_relations_values(rschema): |
517 def rschema_relations_values(rschema): |
530 values = _ervalues(rschema) |
518 values = _ervalues(rschema) |
531 values['final'] = rschema.final |
519 values['final'] = rschema.final |
532 values['symmetric'] = rschema.symmetric |
520 values['symmetric'] = rschema.symmetric |
533 values['inlined'] = rschema.inlined |
521 values['inlined'] = rschema.inlined |
534 if PY2 and isinstance(rschema.fulltext_container, str): |
522 values['fulltext_container'] = rschema.fulltext_container |
535 values['fulltext_container'] = unicode(rschema.fulltext_container) |
|
536 else: |
|
537 values['fulltext_container'] = rschema.fulltext_container |
|
538 relations = ['X %s %%(%s)s' % (attr, attr) for attr in sorted(values)] |
523 relations = ['X %s %%(%s)s' % (attr, attr) for attr in sorted(values)] |
539 return relations, values |
524 return relations, values |
540 |
525 |
541 def crschema2rql(crschema, groupmap): |
526 def crschema2rql(crschema, groupmap): |
542 relations, values = crschema_relations_values(crschema) |
527 relations, values = crschema_relations_values(crschema) |
545 for rql, args in _erperms2rql(crschema, groupmap): |
530 for rql, args in _erperms2rql(crschema, groupmap): |
546 yield rql, args |
531 yield rql, args |
547 |
532 |
548 def crschema_relations_values(crschema): |
533 def crschema_relations_values(crschema): |
549 values = _ervalues(crschema) |
534 values = _ervalues(crschema) |
550 values['rule'] = text_type(crschema.rule) |
535 values['rule'] = crschema.rule |
551 # XXX why oh why? |
536 # XXX why oh why? |
552 del values['final'] |
537 del values['final'] |
553 relations = ['X %s %%(%s)s' % (attr, attr) for attr in sorted(values)] |
538 relations = ['X %s %%(%s)s' % (attr, attr) for attr in sorted(values)] |
554 return relations, values |
539 return relations, values |
555 |
540 |
591 # XXX type cast really necessary? |
576 # XXX type cast really necessary? |
592 if prop in ('indexed', 'fulltextindexed', 'internationalizable'): |
577 if prop in ('indexed', 'fulltextindexed', 'internationalizable'): |
593 value = bool(value) |
578 value = bool(value) |
594 elif prop == 'ordernum': |
579 elif prop == 'ordernum': |
595 value = int(value) |
580 value = int(value) |
596 elif PY2 and isinstance(value, str): |
|
597 value = unicode(value) |
|
598 if value is not None and prop == 'default': |
581 if value is not None and prop == 'default': |
599 value = Binary.zpickle(value) |
582 value = Binary.zpickle(value) |
600 values[amap.get(prop, prop)] = value |
583 values[amap.get(prop, prop)] = value |
601 if extra: |
584 if extra: |
602 values['extra_props'] = Binary(json.dumps(extra).encode('ascii')) |
585 values['extra_props'] = Binary(json.dumps(extra).encode('ascii')) |
604 return relations, values |
587 return relations, values |
605 |
588 |
606 def constraints2rql(cstrtypemap, constraints, rdefeid=None): |
589 def constraints2rql(cstrtypemap, constraints, rdefeid=None): |
607 for constraint in constraints: |
590 for constraint in constraints: |
608 values = {'ct': cstrtypemap[constraint.type()], |
591 values = {'ct': cstrtypemap[constraint.type()], |
609 'value': text_type(constraint.serialize()), |
592 'value': constraint.serialize(), |
610 'x': rdefeid} # when not specified, will have to be set by the caller |
593 'x': rdefeid} # when not specified, will have to be set by the caller |
611 yield 'INSERT CWConstraint X: X value %(value)s, X cstrtype CT, EDEF constrained_by X WHERE \ |
594 yield 'INSERT CWConstraint X: X value %(value)s, X cstrtype CT, EDEF constrained_by X WHERE \ |
612 CT eid %(ct)s, EDEF eid %(x)s', values |
595 CT eid %(ct)s, EDEF eid %(x)s', values |
613 |
596 |
614 |
597 |
623 grantedto = erschema.action_permissions(action) |
606 grantedto = erschema.action_permissions(action) |
624 except KeyError: |
607 except KeyError: |
625 # may occurs when modifying persistent schema |
608 # may occurs when modifying persistent schema |
626 continue |
609 continue |
627 for group_or_rqlexpr in grantedto: |
610 for group_or_rqlexpr in grantedto: |
628 if isinstance(group_or_rqlexpr, string_types): |
611 if isinstance(group_or_rqlexpr, str): |
629 # group |
612 # group |
630 try: |
613 try: |
631 yield ('SET X %s_permission Y WHERE Y eid %%(g)s, X eid %%(x)s' % action, |
614 yield ('SET X %s_permission Y WHERE Y eid %%(g)s, X eid %%(x)s' % action, |
632 {'g': groupmap[group_or_rqlexpr]}) |
615 {'g': groupmap[group_or_rqlexpr]}) |
633 except KeyError: |
616 except KeyError: |
637 else: |
620 else: |
638 # rqlexpr |
621 # rqlexpr |
639 rqlexpr = group_or_rqlexpr |
622 rqlexpr = group_or_rqlexpr |
640 yield ('INSERT RQLExpression E: E expression %%(e)s, E exprtype %%(t)s, ' |
623 yield ('INSERT RQLExpression E: E expression %%(e)s, E exprtype %%(t)s, ' |
641 'E mainvars %%(v)s, X %s_permission E WHERE X eid %%(x)s' % action, |
624 'E mainvars %%(v)s, X %s_permission E WHERE X eid %%(x)s' % action, |
642 {'e': text_type(rqlexpr.expression), |
625 {'e': rqlexpr.expression, |
643 'v': text_type(','.join(sorted(rqlexpr.mainvars))), |
626 'v': ','.join(sorted(rqlexpr.mainvars)), |
644 't': text_type(rqlexpr.__class__.__name__)}) |
627 't': rqlexpr.__class__.__name__}) |
645 |
628 |
646 # update functions |
629 # update functions |
647 |
630 |
648 def updateeschema2rql(eschema, eid): |
631 def updateeschema2rql(eschema, eid): |
649 relations, values = eschema_relations_values(eschema) |
632 relations, values = eschema_relations_values(eschema) |
651 yield 'SET %s WHERE X eid %%(x)s' % ','.join(relations), values |
634 yield 'SET %s WHERE X eid %%(x)s' % ','.join(relations), values |
652 |
635 |
653 def updaterschema2rql(rschema, eid): |
636 def updaterschema2rql(rschema, eid): |
654 if rschema.rule: |
637 if rschema.rule: |
655 yield ('SET X rule %(r)s WHERE X eid %(x)s', |
638 yield ('SET X rule %(r)s WHERE X eid %(x)s', |
656 {'x': eid, 'r': text_type(rschema.rule)}) |
639 {'x': eid, 'r': rschema.rule}) |
657 else: |
640 else: |
658 relations, values = rschema_relations_values(rschema) |
641 relations, values = rschema_relations_values(rschema) |
659 values['x'] = eid |
642 values['x'] = eid |
660 yield 'SET %s WHERE X eid %%(x)s' % ','.join(relations), values |
643 yield 'SET %s WHERE X eid %%(x)s' % ','.join(relations), values |
661 |
644 |