[PATCH 01 of 18 seda] [schema] Add a new 'ordering' attribute on some etype + hook to set it autonomatically

Sylvain Thenault sylvain.thenault at logilab.fr
Mon Dec 11 16:53:33 CET 2017


# HG changeset patch
# User Sylvain Thénault <sylvain.thenault at logilab.fr>
# Date 1512478074 -3600
#      Tue Dec 05 13:47:54 2017 +0100
# Node ID c1276fadfad848052287777f10024de331b17d22
# Parent  57a7ff87ab4db394ba38b32afee0b2f08ada7fd7
[schema] Add a new 'ordering' attribute on some etype + hook to set it autonomatically

in order to being able to order children elements of an entity.

diff --git a/cubicweb_seda/__init__.py b/cubicweb_seda/__init__.py
--- a/cubicweb_seda/__init__.py
+++ b/cubicweb_seda/__init__.py
@@ -68,5 +68,32 @@ def iter_all_rdefs(schema, container_ety
                 if target not in visited:
                     visited.add(target)
                     stack.append(target)
         for rdef, role in _iter_external_rdefs(schema[etype], skip_external_rtypes):
             yield rdef, role
+
+
+# list of entity types that may be used multiple times at a same level, and
+# through which relation
+MULTIPLE_CHILDREN = [
+    ('SEDAArchiveUnit', 'seda_archive_unit'),
+    ('SEDABinaryDataObject', 'seda_binary_data_object'),
+    ('SEDAPhysicalDataObject', 'seda_physical_data_object'),
+    ('SEDADataObjectReference', 'seda_data_object_reference'),
+    ('SEDARelatedTransferReference', 'seda_related_transfer_reference'),
+    ('SEDAWriter', 'seda_writer_from'),
+    ('SEDAAddressee', 'seda_addressee_from'),
+    ('SEDARecipient', 'seda_recipient_from'),
+    ('SEDASpatial', 'seda_spatial'),
+    ('SEDATemporal', 'seda_temporal '),
+    ('SEDAJuridictional', 'seda_juridictional'),
+    ('SEDAKeyword', 'seda_keyword'),
+    ('SEDATag', 'seda_tag'),
+    ('SEDAIsVersionOf', 'seda_is_version_of'),
+    ('SEDAReplaces', 'seda_replaces'),
+    ('SEDARequires', 'seda_requires'),
+    ('SEDAIsPartOf', 'seda_is_part_of'),
+    ('SEDAReferences', 'seda_references'),
+    ('SEDAEvent', 'seda_event'),
+    ('SEDACustodialHistoryItem', 'seda_custodial_history_item'),
+    ('SEDARelationship', 'seda_relationship'),
+]
diff --git a/cubicweb_seda/hooks.py b/cubicweb_seda/hooks.py
--- a/cubicweb_seda/hooks.py
+++ b/cubicweb_seda/hooks.py
@@ -23,10 +23,11 @@ from yams.schema import role_name
 
 from cubicweb import _
 from cubicweb.predicates import is_instance, score_entity
 from cubicweb.server import hook
 
+from . import MULTIPLE_CHILDREN
 from .entities import rule_type_from_etype, diag
 from .entities.generated import (CHOICE_RTYPE,
                                  CHECK_CARD_ETYPES, CHECK_CHILDREN_CARD_RTYPES)
 
 
@@ -504,10 +505,29 @@ class SyncFileCategoryHook(hook.Hook):
 
     def __call__(self):
         SyncFileCategoryOp.get_instance(self._cw).add_data(self.eidfrom)
 
 
+class SetOrderingHook(hook.Hook):
+    """Hook to set ordering attribute of child object when some relation is added.
+    """
+    __regid__ = 'seda.ordering.set'
+    __select__ = hook.Hook.__select__ & hook.match_rtype_sets(
+        {rtype for _, rtype in MULTIPLE_CHILDREN})
+
+    events = ('after_add_relation',)
+
+    def __call__(self):
+        eid, parent_eid = self.eidfrom, self.eidto
+        rql = 'Any MAX(O) WHERE X {rtype} P, P eid %(p)s, X ordering O'
+        ordering = self._cw.execute(rql.format(rtype=self.rtype),
+                                    {'p': parent_eid})[0][0]
+        ordering = 0 if ordering is None else ordering
+        entity = self._cw.entity_from_eid(eid)
+        entity.cw_set(ordering=ordering + 1)
+
+
 def registration_callback(vreg):
     from cubicweb.server import ON_COMMIT_ADD_RELATIONS
     from cubicweb_seda import seda_profile_container_def, iter_all_rdefs
 
     vreg.register_all(globals().values(), __name__)
diff --git a/cubicweb_seda/i18n/en.po b/cubicweb_seda/i18n/en.po
--- a/cubicweb_seda/i18n/en.po
+++ b/cubicweb_seda/i18n/en.po
@@ -4596,10 +4596,97 @@ msgid "optional"
 msgstr ""
 
 msgid "optional timestamp"
 msgstr ""
 
+msgid "ordering"
+msgstr ""
+
+msgctxt "SEDAAddressee"
+msgid "ordering"
+msgstr ""
+
+msgctxt "SEDAArchiveUnit"
+msgid "ordering"
+msgstr ""
+
+msgctxt "SEDABinaryDataObject"
+msgid "ordering"
+msgstr ""
+
+msgctxt "SEDACustodialHistoryItem"
+msgid "ordering"
+msgstr ""
+
+msgctxt "SEDADataObjectReference"
+msgid "ordering"
+msgstr ""
+
+msgctxt "SEDAEvent"
+msgid "ordering"
+msgstr ""
+
+msgctxt "SEDAIsPartOf"
+msgid "ordering"
+msgstr ""
+
+msgctxt "SEDAIsVersionOf"
+msgid "ordering"
+msgstr ""
+
+msgctxt "SEDAJuridictional"
+msgid "ordering"
+msgstr ""
+
+msgctxt "SEDAKeyword"
+msgid "ordering"
+msgstr ""
+
+msgctxt "SEDAPhysicalDataObject"
+msgid "ordering"
+msgstr ""
+
+msgctxt "SEDARecipient"
+msgid "ordering"
+msgstr ""
+
+msgctxt "SEDAReferences"
+msgid "ordering"
+msgstr ""
+
+msgctxt "SEDARelatedTransferReference"
+msgid "ordering"
+msgstr ""
+
+msgctxt "SEDARelationship"
+msgid "ordering"
+msgstr ""
+
+msgctxt "SEDAReplaces"
+msgid "ordering"
+msgstr ""
+
+msgctxt "SEDARequires"
+msgid "ordering"
+msgstr ""
+
+msgctxt "SEDASpatial"
+msgid "ordering"
+msgstr ""
+
+msgctxt "SEDATag"
+msgid "ordering"
+msgstr ""
+
+msgctxt "SEDATemporal"
+msgid "ordering"
+msgstr ""
+
+msgctxt "SEDAWriter"
+msgid "ordering"
+msgstr ""
+
 msgid "originating_agency_archive_unit_identifier"
 msgstr ""
 
 msgctxt "SEDAOriginatingAgencyArchiveUnitIdentifier"
 msgid "originating_agency_archive_unit_identifier"
diff --git a/cubicweb_seda/i18n/fr.po b/cubicweb_seda/i18n/fr.po
--- a/cubicweb_seda/i18n/fr.po
+++ b/cubicweb_seda/i18n/fr.po
@@ -4621,10 +4621,97 @@ msgid "optional"
 msgstr "optionnel"
 
 msgid "optional timestamp"
 msgstr "horodatage optionel"
 
+msgid "ordering"
+msgstr ""
+
+msgctxt "SEDAAddressee"
+msgid "ordering"
+msgstr ""
+
+msgctxt "SEDAArchiveUnit"
+msgid "ordering"
+msgstr ""
+
+msgctxt "SEDABinaryDataObject"
+msgid "ordering"
+msgstr ""
+
+msgctxt "SEDACustodialHistoryItem"
+msgid "ordering"
+msgstr ""
+
+msgctxt "SEDADataObjectReference"
+msgid "ordering"
+msgstr ""
+
+msgctxt "SEDAEvent"
+msgid "ordering"
+msgstr ""
+
+msgctxt "SEDAIsPartOf"
+msgid "ordering"
+msgstr ""
+
+msgctxt "SEDAIsVersionOf"
+msgid "ordering"
+msgstr ""
+
+msgctxt "SEDAJuridictional"
+msgid "ordering"
+msgstr ""
+
+msgctxt "SEDAKeyword"
+msgid "ordering"
+msgstr ""
+
+msgctxt "SEDAPhysicalDataObject"
+msgid "ordering"
+msgstr ""
+
+msgctxt "SEDARecipient"
+msgid "ordering"
+msgstr ""
+
+msgctxt "SEDAReferences"
+msgid "ordering"
+msgstr ""
+
+msgctxt "SEDARelatedTransferReference"
+msgid "ordering"
+msgstr ""
+
+msgctxt "SEDARelationship"
+msgid "ordering"
+msgstr ""
+
+msgctxt "SEDAReplaces"
+msgid "ordering"
+msgstr ""
+
+msgctxt "SEDARequires"
+msgid "ordering"
+msgstr ""
+
+msgctxt "SEDASpatial"
+msgid "ordering"
+msgstr ""
+
+msgctxt "SEDATag"
+msgid "ordering"
+msgstr ""
+
+msgctxt "SEDATemporal"
+msgid "ordering"
+msgstr ""
+
+msgctxt "SEDAWriter"
+msgid "ordering"
+msgstr ""
+
 msgid "originating_agency_archive_unit_identifier"
 msgstr "valeur"
 
 msgctxt "SEDAOriginatingAgencyArchiveUnitIdentifier"
 msgid "originating_agency_archive_unit_identifier"
diff --git a/cubicweb_seda/migration/0.13.0_Any.py b/cubicweb_seda/migration/0.13.0_Any.py
new file mode 100644
--- /dev/null
+++ b/cubicweb_seda/migration/0.13.0_Any.py
@@ -0,0 +1,16 @@
+from cubicweb_seda.xsd2yams import MULTIPLE_CHILDREN
+
+add_relation_type('ordering')
+
+parent_rtypes = [rtype for _, rtype in MULTIPLE_CHILDREN]
+
+for rtype in parent_rtypes:
+    for peid, in rql('Any P GROUPBY P WHERE X {} P HAVING COUNT(X) > 1'.format(rtype)):
+        for idx, child in enumerate(rql('Any X WHERE X {} P, P eid %(p)s'.format(rtype),
+                                    {'p': peid}).entities()):
+            child.cw_set(ordering=idx + 1)
+    commit()
+
+rql('SET X ordering 1 WHERE X ordering NULL')
+
+commit()
diff --git a/cubicweb_seda/schema/__init__.py b/cubicweb_seda/schema/__init__.py
--- a/cubicweb_seda/schema/__init__.py
+++ b/cubicweb_seda/schema/__init__.py
@@ -21,10 +21,12 @@ from yams.buildobjs import String
 from cubicweb import _
 from cubicweb.schema import ERQLExpression, RRQLExpression, RQLConstraint
 
 from cubes.skos import schema as skos
 
+from . import MULTIPLE_CHILDREN
+
 _('1')
 _('0..1')
 _('0..n')
 _('1..n')
 
@@ -92,10 +94,16 @@ class file_category(RelationDefinition):
     constraints = [
         RQLConstraint('O in_scheme CS, CS scheme_relation_type CR, CR name "file_category"'),
     ]
 
 
+class ordering(RelationDefinition):
+    subject = tuple([etype for etype, _ in MULTIPLE_CHILDREN])
+    object = 'Int'
+    cardinality = '?1'
+
+
 class container(RelationType):
     inlined = False
 
 
 class _clone_of(RelationDefinition):
diff --git a/test/test_hooks.py b/test/test_hooks.py
--- a/test/test_hooks.py
+++ b/test/test_hooks.py
@@ -304,8 +304,48 @@ class DispatchFileCategoryTC(CubicWebTC)
         self.assertEqual(mime_types, set(expected_mime_types))
         format_ids = set(x.label() for x in bdo.reverse_seda_format_id_from[0].seda_format_id_to)
         self.assertEqual(format_ids, set(expected_format_ids))
 
 
+class SetOrderingHooksTC(CubicWebTC):
+
+    def test_first_level_archive_units(self):
+        with self.admin_access.cnx() as cnx:
+            transfer = cnx.create_entity('SEDAArchiveTransfer', title=u'test profile')
+            unit1 = testutils.create_archive_unit(transfer)[0]
+            unit2 = testutils.create_archive_unit(transfer)[0]
+            cnx.commit()
+
+            self.assertEqual(unit1.ordering, 1)
+            self.assertEqual(unit2.ordering, 2)
+
+    def test_archive_units(self):
+        with self.admin_access.cnx() as cnx:
+            transfer = cnx.create_entity('SEDAArchiveTransfer', title=u'test profile')
+            unit, unit_alt, unit_alt_seq = testutils.create_archive_unit(transfer)
+            unit1 = testutils.create_archive_unit(unit_alt_seq)[0]
+            unit2 = testutils.create_archive_unit(unit_alt_seq)[0]
+            cnx.commit()
+
+            self.assertEqual(unit1.ordering, 1)
+            self.assertEqual(unit2.ordering, 2)
+
+    def test_data_objects(self):
+        with self.admin_access.cnx() as cnx:
+            transfer = cnx.create_entity('SEDAArchiveTransfer', title=u'test profile',
+                                         simplified_profile=True)
+            unit, unit_alt, unit_alt_seq = testutils.create_archive_unit(transfer)
+            bdo1 = testutils.create_data_object(unit_alt_seq, user_cardinality=u'1',
+                                                seda_binary_data_object=transfer)
+            bdo2 = testutils.create_data_object(unit_alt_seq, user_cardinality=u'1',
+                                                seda_binary_data_object=transfer)
+            cnx.commit()
+
+            self.assertEqual(bdo1.ordering, 1)
+            self.assertEqual(bdo2.ordering, 2)
+            self.assertEqual(bdo1.reverse_seda_data_object_reference_id[0].ordering, 1)
+            self.assertEqual(bdo2.reverse_seda_data_object_reference_id[0].ordering, 2)
+
+
 if __name__ == '__main__':
     import unittest
     unittest.main()


More information about the saem-devel mailing list