cubicweb/server/schemaserial.py
changeset 12567 26744ad37953
parent 12542 85194bd49119
equal deleted inserted replaced
12566:6b3523f81f42 12567:26744ad37953
    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