--- a/entities/schemaobjs.py Tue Mar 09 11:01:44 2010 +0100
+++ b/entities/schemaobjs.py Tue Mar 09 11:05:29 2010 +0100
@@ -56,30 +56,21 @@
return u'%s <<%s>>' % (self.dc_title(), ', '.join(stereotypes))
return self.dc_title()
- def inlined_changed(self, inlined):
- """check inlining is necessary and possible:
-
- * return False if nothing has changed
- * raise ValidationError if inlining is'nt possible
- * eventually return True
+ def check_inlined_allowed(self):
+ """check inlining is possible, raise ValidationError if not possible
"""
- rschema = self._cw.vreg.schema.rschema(self.name)
- if inlined == rschema.inlined:
- return False
- if inlined:
- # don't use the persistent schema, we may miss cardinality changes
- # in the same transaction
- for rdef in self.reverse_relation_type:
- card = rdef.cardinality[0]
- if not card in '?1':
- rtype = self.name
- stype = rdef.stype
- otype = rdef.otype
- msg = self._cw._("can't set inlined=%(inlined)s, "
- "%(stype)s %(rtype)s %(otype)s "
- "has cardinality=%(card)s")
- raise ValidationError(self.eid, {'inlined': msg % locals()})
- return True
+ # don't use the persistent schema, we may miss cardinality changes
+ # in the same transaction
+ for rdef in self.reverse_relation_type:
+ card = rdef.cardinality[0]
+ if not card in '?1':
+ rtype = self.name
+ stype = rdef.stype
+ otype = rdef.otype
+ msg = self._cw._("can't set inlined=%(inlined)s, "
+ "%(stype)s %(rtype)s %(otype)s "
+ "has cardinality=%(card)s")
+ raise ValidationError(self.eid, {'inlined': msg % locals()})
def db_key_name(self):
"""XXX goa specific"""
--- a/goa/goactl.py Tue Mar 09 11:01:44 2010 +0100
+++ b/goa/goactl.py Tue Mar 09 11:05:29 2010 +0100
@@ -15,38 +15,40 @@
create_dir)
from cubicweb.cwconfig import CubicWebConfiguration
-from logilab import common as lgc
-from logilab import constraint as lgcstr
-from logilab import mtconverter as lgmtc
-import rql, yams, yapps, simplejson, docutils, roman
-SLINK_DIRECTORIES = [
- (lgc.__path__[0], 'logilab/common'),
- (lgmtc.__path__[0], 'logilab/mtconverter'),
- (lgcstr.__path__[0], 'logilab/constraint'),
- (rql.__path__[0], 'rql'),
- (simplejson.__path__[0], 'simplejson'),
- (yams.__path__[0], 'yams'),
- (yapps.__path__[0], 'yapps'),
- (docutils.__path__[0], 'docutils'),
- (roman.__file__.replace('.pyc', '.py'), 'roman.py'),
+def slink_directories():
+ import rql, yams, yapps, simplejson, docutils, roman
+ from logilab import common as lgc
+ from logilab import constraint as lgcstr
+ from logilab import mtconverter as lgmtc
+ dirs = [
+ (lgc.__path__[0], 'logilab/common'),
+ (lgmtc.__path__[0], 'logilab/mtconverter'),
+ (lgcstr.__path__[0], 'logilab/constraint'),
+ (rql.__path__[0], 'rql'),
+ (simplejson.__path__[0], 'simplejson'),
+ (yams.__path__[0], 'yams'),
+ (yapps.__path__[0], 'yapps'),
+ (docutils.__path__[0], 'docutils'),
+ (roman.__file__.replace('.pyc', '.py'), 'roman.py'),
- ('/usr/share/fckeditor/', 'fckeditor'),
+ ('/usr/share/fckeditor/', 'fckeditor'),
+
+ (join(CW_SOFTWARE_ROOT, 'web', 'data'), join('cubes', 'shared', 'data')),
+ (join(CW_SOFTWARE_ROOT, 'web', 'wdoc'), join('cubes', 'shared', 'wdoc')),
+ (join(CW_SOFTWARE_ROOT, 'i18n'), join('cubes', 'shared', 'i18n')),
+ (join(CW_SOFTWARE_ROOT, 'goa', 'tools'), 'tools'),
+ (join(CW_SOFTWARE_ROOT, 'goa', 'bin'), 'bin'),
+ ]
- (join(CW_SOFTWARE_ROOT, 'web', 'data'), join('cubes', 'shared', 'data')),
- (join(CW_SOFTWARE_ROOT, 'web', 'wdoc'), join('cubes', 'shared', 'wdoc')),
- (join(CW_SOFTWARE_ROOT, 'i18n'), join('cubes', 'shared', 'i18n')),
- (join(CW_SOFTWARE_ROOT, 'goa', 'tools'), 'tools'),
- (join(CW_SOFTWARE_ROOT, 'goa', 'bin'), 'bin'),
- ]
-
-try:
- import dateutil
- import vobject
- SLINK_DIRECTORIES.extend([ (dateutil.__path__[0], 'dateutil'),
- (vobject.__path__[0], 'vobject') ] )
-except ImportError:
- pass
+ try:
+ import dateutil
+ import vobject
+ dirs.extend([ (dateutil.__path__[0], 'dateutil'),
+ (vobject.__path__[0], 'vobject') ] )
+ except ImportError:
+ pass
+ return dirs
COPY_CW_FILES = (
'__init__.py',
@@ -194,7 +196,7 @@
copy_skeleton(join(CW_SOFTWARE_ROOT, 'goa', 'skel'),
appldir, context, askconfirm=True)
# cubicweb core dependancies
- for directory, subdirectory in SLINK_DIRECTORIES:
+ for directory, subdirectory in slink_directories():
subdirectory = join(appldir, subdirectory)
if not exists(split(subdirectory)[0]):
create_dir(split(subdirectory)[0])
--- a/hooks/syncschema.py Tue Mar 09 11:01:44 2010 +0100
+++ b/hooks/syncschema.py Tue Mar 09 11:05:29 2010 +0100
@@ -227,25 +227,26 @@
class SourceDbCWRTypeUpdate(hook.Operation):
"""actually update some properties of a relation definition"""
- rschema = entity = None # make pylint happy
+ rschema = entity = values = None # make pylint happy
def precommit_event(self):
+ rschema = self.rschema
+ if rschema.final:
+ return
session = self.session
- rschema = self.rschema
- entity = self.entity
- if 'fulltext_container' in entity.edited_attributes:
+ if 'fulltext_container' in self.values:
ftiupdates = session.transaction_data.setdefault(
'fti_update_etypes', set())
for subjtype, objtype in rschema.rdefs:
ftiupdates.add(subjtype)
ftiupdates.add(objtype)
UpdateFTIndexOp(session)
- if rschema.final or not 'inlined' in entity.edited_attributes:
+ if not 'inlined' in self.values:
return # nothing to do
- inlined = entity.inlined
+ inlined = self.values['inlined']
# check in-lining is necessary / possible
- if not entity.inlined_changed(inlined):
- return # nothing to do
+ if inlined:
+ self.entity.check_inlined_allowed()
# inlined changed, make necessary physical changes!
sqlexec = self.session.system_sql
rtype = rschema.type
@@ -934,26 +935,22 @@
class BeforeUpdateCWRTypeHook(DelCWRTypeHook):
"""check name change, handle final"""
- __regid__ = 'checkupdatecwrtype'
+ __regid__ = 'syncupdatecwrtype'
events = ('before_update_entity',)
def __call__(self):
- check_valid_changes(self._cw, self.entity)
-
-
-class AfterUpdateCWRTypeHook(DelCWRTypeHook):
- __regid__ = 'syncupdatecwrtype'
- events = ('after_update_entity',)
-
- def __call__(self):
entity = self.entity
+ check_valid_changes(self._cw, entity)
newvalues = {}
for prop in ('symmetric', 'inlined', 'fulltext_container'):
if prop in entity.edited_attributes:
- newvalues[prop] = entity[prop]
+ old, new = hook.entity_oldnewvalue(entity, prop)
+ if old != new:
+ newvalues[prop] = entity[prop]
if newvalues:
rschema = self._cw.vreg.schema.rschema(entity.name)
- SourceDbCWRTypeUpdate(self._cw, rschema=rschema, entity=entity)
+ SourceDbCWRTypeUpdate(self._cw, rschema=rschema, entity=entity,
+ values=newvalues)
MemSchemaCWRTypeUpdate(self._cw, rschema=rschema, values=newvalues)
@@ -1033,8 +1030,8 @@
class AfterUpdateCWRDefHook(SyncSchemaHook):
__regid__ = 'syncaddcwattribute'
__select__ = SyncSchemaHook.__select__ & implements('CWAttribute',
- 'CWRelation')
- events = ('after_update_entity',)
+ 'CWRelation')
+ events = ('before_update_entity',)
def __call__(self):
entity = self.entity
@@ -1049,7 +1046,9 @@
if prop == 'order':
prop = 'ordernum'
if prop in entity.edited_attributes:
- newvalues[prop] = entity[prop]
+ old, new = hook.entity_oldnewvalue(entity, prop)
+ if old != new:
+ newvalues[prop] = entity[prop]
if newvalues:
subjtype = entity.stype.name
MemSchemaRDefUpdate(self._cw, kobj=(subjtype, desttype),
--- a/hooks/test/unittest_syncschema.py Tue Mar 09 11:01:44 2010 +0100
+++ b/hooks/test/unittest_syncschema.py Tue Mar 09 11:05:29 2010 +0100
@@ -266,7 +266,7 @@
'WHERE E is CWEType, E name "Email", A is CWAttribute,'
'A from_entity E, A relation_type R, R name "subject"')
self.commit()
- rset = req.execute('Any X Where X has_text "rick.roll"')
+ rset = req.execute('Any X WHERE X has_text "rick.roll"')
self.failIf(rset)
assert req.execute('SET A fulltextindexed TRUE '
'WHERE A from_entity E, A relation_type R, '
@@ -285,7 +285,7 @@
assert self.execute('SET R fulltext_container NULL '
'WHERE R name "use_email"')
self.commit()
- rset = self.execute('Any X Where X has_text "rick.roll"')
+ rset = self.execute('Any X WHERE X has_text "rick.roll"')
self.assertIn(target.eid, [item[0] for item in rset])
assert self.execute('SET R fulltext_container "subject" '
'WHERE R name "use_email"')
--- a/server/hook.py Tue Mar 09 11:01:44 2010 +0100
+++ b/server/hook.py Tue Mar 09 11:05:29 2010 +0100
@@ -95,16 +95,16 @@
VRegistry.REGISTRY_FACTORY['hooks'] = HooksRegistry
-
+_MARKER = object()
def entity_oldnewvalue(entity, attr):
"""returns the couple (old attr value, new attr value)
NOTE: will only work in a before_update_entity hook
"""
# get new value and remove from local dict to force a db query to
# fetch old value
- newvalue = entity.pop(attr, None)
+ newvalue = entity.pop(attr, _MARKER)
oldvalue = getattr(entity, attr)
- if newvalue is not None:
+ if newvalue is not _MARKER:
entity[attr] = newvalue
return oldvalue, newvalue
--- a/server/hookhelper.py Tue Mar 09 11:01:44 2010 +0100
+++ b/server/hookhelper.py Tue Mar 09 11:05:29 2010 +0100
@@ -13,7 +13,6 @@
@deprecated('[3.6] entity_oldnewvalue should be imported from cw.server.hook')
def entity_oldnewvalue(entity, attr):
- """return the "name" attribute of the entity with the given eid"""
return hook.entity_oldnewvalue(entity, attr)
@deprecated('[3.6] entity_name is deprecated, use entity.name')
--- a/server/serverctl.py Tue Mar 09 11:01:44 2010 +0100
+++ b/server/serverctl.py Tue Mar 09 11:05:29 2010 +0100
@@ -66,7 +66,13 @@
cnx = get_connection(driver, dbhost, dbname, user, password=password,
port=source.get('db-port'),
**extra)
- cnx.logged_user = logged_user
+ try:
+ cnx.logged_user = user
+ except AttributeError:
+ # C object, __slots__
+ from logilab.db import _SimpleConnectionWrapper
+ cnx = _SimpleConnectionWrapper(cnx)
+ cnx.logged_user = user
return cnx
def system_source_cnx(source, dbms_system_base=False,
--- a/server/session.py Tue Mar 09 11:01:44 2010 +0100
+++ b/server/session.py Tue Mar 09 11:05:29 2010 +0100
@@ -280,9 +280,15 @@
self.set_language(value)
def deleted_in_transaction(self, eid):
+ """return True if the entity of the given eid is being deleted in the
+ current transaction
+ """
return eid in self.transaction_data.get('pendingeids', ())
def added_in_transaction(self, eid):
+ """return True if the entity of the given eid is being created in the
+ current transaction
+ """
return eid in self.transaction_data.get('neweids', ())
def schema_rproperty(self, rtype, eidfrom, eidto, rprop):
--- a/server/sources/rql2sql.py Tue Mar 09 11:01:44 2010 +0100
+++ b/server/sources/rql2sql.py Tue Mar 09 11:05:29 2010 +0100
@@ -341,6 +341,9 @@
}
if not self.dbms_helper.union_parentheses_support:
self.union_sql = self.noparen_union_sql
+ if self.dbms_helper.fti_need_distinct:
+ self.__union_sql = self.union_sql
+ self.union_sql = self.has_text_need_distinct_union_sql
self._lock = threading.Lock()
if attrmap is None:
attrmap = {}
@@ -374,6 +377,12 @@
finally:
self._lock.release()
+ def has_text_need_distinct_union_sql(self, union, needalias=False):
+ if getattr(union, 'has_text_query', False):
+ for select in union.children:
+ select.need_distinct = True
+ return self.__union_sql(union, needalias)
+
def union_sql(self, union, needalias=False): # pylint: disable-msg=E0202
if len(union.children) == 1:
return self.select_sql(union.children[0], needalias)
--- a/server/test/unittest_rql2sql.py Tue Mar 09 11:01:44 2010 +0100
+++ b/server/test/unittest_rql2sql.py Tue Mar 09 11:05:29 2010 +0100
@@ -1486,26 +1486,26 @@
def test_has_text(self):
for t in self._parse((
('Any X WHERE X has_text "toto tata"',
- """SELECT appears0.uid
+ """SELECT DISTINCT appears0.uid
FROM appears AS appears0
WHERE appears0.word_id IN (SELECT word_id FROM word WHERE word in ('toto', 'tata'))"""),
('Any X WHERE X has_text %(text)s',
- """SELECT appears0.uid
+ """SELECT DISTINCT appears0.uid
FROM appears AS appears0
WHERE appears0.word_id IN (SELECT word_id FROM word WHERE word in ('hip', 'hop', 'momo'))"""),
('Personne X WHERE X has_text "toto tata"',
- """SELECT _X.eid
+ """SELECT DISTINCT _X.eid
FROM appears AS appears0, entities AS _X
WHERE appears0.word_id IN (SELECT word_id FROM word WHERE word in ('toto', 'tata')) AND appears0.uid=_X.eid AND _X.type='Personne'"""),
('Any X WHERE X has_text "toto tata", X name "tutu", X is IN (Basket,Folder)',
- """SELECT _X.cw_eid
+ """SELECT DISTINCT _X.cw_eid
FROM appears AS appears0, cw_Basket AS _X
WHERE appears0.word_id IN (SELECT word_id FROM word WHERE word in ('toto', 'tata')) AND appears0.uid=_X.cw_eid AND _X.cw_name=tutu
-UNION ALL
-SELECT _X.cw_eid
+UNION
+SELECT DISTINCT _X.cw_eid
FROM appears AS appears0, cw_Folder AS _X
WHERE appears0.word_id IN (SELECT word_id FROM word WHERE word in ('toto', 'tata')) AND appears0.uid=_X.cw_eid AND _X.cw_name=tutu
"""),
--- a/sobjects/test/unittest_supervising.py Tue Mar 09 11:01:44 2010 +0100
+++ b/sobjects/test/unittest_supervising.py Tue Mar 09 11:05:29 2010 +0100
@@ -27,7 +27,6 @@
def test_supervision(self):
- session = self.session
# do some modification
user = self.execute('INSERT CWUser X: X login "toto", X upassword "sosafe", X in_group G '
'WHERE G name "users"').get_entity(0, 0)
@@ -37,6 +36,7 @@
self.execute('SET X content "duh?" WHERE X is Comment')
self.execute('DELETE X comments Y WHERE Y is Card, Y title "une autre news !"')
# check only one supervision email operation
+ session = self.session
sentops = [op for op in session.pending_operations
if isinstance(op, SupervisionMailOp)]
self.assertEquals(len(sentops), 1)