def update(self):
      self.mode = self.request.form.get('mode')
      setobject_id = self.request.form.get('setobject_id')
      self.graph_xml = self.request.form.get('graph')
      if self.graph_xml != None:
          del(self.request.form['graph'])
      self.source_id = self.request.form.get('source_id')
      if self.source_id != None:
          # Delete request's source_id, as subforms should not see it.
          del(self.request.form['source_id'])
  	self.linked = self.request.form.get('linked')
      if self.linked != None:
          del(self.request.form['linked'])
      if self.linked != None and self.linked != 'true' and self.linked != 'false':
  	    raise Exception("Invalid value for parameter linked")
  	if self.source_id != None and self.linked == None:
  		raise Exception("source_id parameter must be accompanied by linked parameter")
  	if self.linked != None and self.source_id == None:
          raise Exception("linked parameter must be accompanied by linked source_id parameter.")
  	self.relation_source_id = self.request.form.get('relation_source_id')
      
      db_utility = getUtility(IDbUtility)
      session = db_utility.Session()
    
      if self.mode == 'OPERATIONAL':
          classname = self.context.op_setobject_type.__name__
      elif self.mode == 'DESIGNER' or self.mode == 'ARCHETYPE':
          classname = self.context.__class__.__name__
      else:
           raise Exception("Mode must have one of the values ARCHETYPE, DESIGNER, OPERATIONAL")
      
      self.klass = setobject_type_registry.lookup(classname)
      if not setobject_id:
          setobject = self.klass()
          session.add(setobject)
          setobject_id = setobject.id
          session.flush()
      
      if self.graph_xml != None and self.graph_xml != '':
          graph = SetobjectGraph(self.request, self.graph_xml)        
          graph.link(self.source_id, classname, setobject_id, self.linked)
          
      if setobject_id != None:
          self.setobject = session.query(self.klass).filter(self.klass.get_primary_key_attr() == setobject_id).one()
      
      relation_id = self.request.get('relation_id')
      if relation_id != None:
          if self.relation_source_id == None:
              raise Exception("relation_id parameter must be accompanied by relation_source_id.")
          self.relation = session.query(EmbeddedForm).filter_by(span_identifier=relation_id).one()
          source_type = setobject_type_registry.lookup(self.relation.linkage.source_model.klass)
          self.relation_source = session.query(source_type).filter(source_type.get_primary_key_attr() == self.relation_source_id).one()   
      
      if self.graph_xml != None and self.graph_xml != '':
          # Each query after graph.link() call might generate new dynamic linkage id's. Correct them if necessary.
          graph.update_collections()
 
      self.context = self.setobject
Пример #2
0
 def init_xref_relation(self):
     # Get some vars beforehand:
     type1 = setobject_type_registry.lookup(self.source_module, self.source_classname)
     type2 = setobject_type_registry.lookup(self.target_module, self.target_classname)
     table1class = type1.get_table_class()
     table2class = type2.get_table_class()
     table1primarykey = type1.get_primary_key_attr_name()
     table2primarykey = type2.get_primary_key_attr_name()
     table1name = type1.get_table_name()
     table2name = type2.get_table_name()
     
     if self.relation.foreignkeycol.lower() == self.relation.foreignkeycol2.lower():
         raise UserException("Please choose different column names for both of the two foreign key columns")
     
     # Create/obtain xref table
     fkcol1 = Column(
         self.relation.foreignkeycol,
         getattr(table1class.c, table1primarykey).type,
         ForeignKey(table1name + "." + table1primarykey)
     )
     fkcol2 = Column(
         self.relation.foreignkeycol2,
         getattr(table2class.c, table2primarykey).type,
         ForeignKey(table2name + "." + table2primarykey)
     )
     
     mytable = Table(self.relation.xref_table, metadata, useexisting=True)
     if not mytable.exists():
         # Create table with new columns
         mytable = Table(self.relation.xref_table, metadata,
             fkcol1,
             fkcol2,
             Column('id', Integer(8), primary_key=True, autoincrement=True, default=0, nullable=False), 
             useexisting=True, mysql_engine='InnoDB')
         
         # Register table type
         setobject_table_registry.register_type('p2.datashackle.core.models.model', self.relation.xref_table, self.relation.xref_table, mytable)
         
         # Create table
         mytable.create()
         
         # Create setobject type
         create_basemodel_type(self.relation.xref_table, self.relation.xref_table)
     else:
         # Alter table to have the new columns if they aren't there yet
         mytable = Table(self.relation.xref_table, metadata, autoload=True, useexisting=True)
         if hasattr(mytable.c, self.relation.foreignkeycol) != True:
             # add fkcol1
             fkcol1.create(mytable)
         if hasattr(mytable.c, self.relation.foreignkeycol2) != True:
             # add fkcol2
             fkcol2.create(mytable)
             
         # Remap xref table setobject
         setobject_type_registry.lookup_by_table(self.relation.xref_table).sa_map()
 def __init__(self, span_name=None):
     self.required = True
     ft = setobject_type_registry.lookup('p2_fieldtype')
     sess = getUtility(IDbUtility).Session()
     self.field_type = sess.query(ft).filter_by(field_type='textline').one()
     self.style = "left:" + str(self.label_width) + "px; width:" + str(self.label_width) + "px;"
     super(Alphanumeric, self).__init__(span_name)
Пример #4
0
 def _create_relation(self):
     if self.cardinality.id == 'ONE_TO_MANY' or \
             self.cardinality.id == 'ONE_TO_ONE(FK)':
         # Create Foreign key and re-map setobject if necessary
         self.check_create_fk(
             self.target_table,
             self.source_table,
             ignoreexisting=True
         )
         return
     elif self.cardinality.id == 'MANY_TO_ONE' or \
             self.cardinality.id == 'ONE(FK)_TO_ONE':
         # Create Foreign key and re-map setobject if necessary
         self.check_create_fk(
             self.source_table,
             self.target_table,
             ignoreexisting=True
         )
         return
     elif self.cardinality.id == 'MANY_TO_MANY':
 
         if self.source_classname.lower() == self.target_classname.lower() and self.source_module.lower() == self.target_module.lower():
             raise UserException("You cannot add a relation from a plan to itself (or another plan on the same table)")
         
         self.init_xref_relation()
         
         # update session and remap source table
         getUtility(IDbUtility).Session().flush()
         sourceobj = setobject_type_registry.lookup(self.source_module, self.source_classname)
         sourceobj.sa_map()
Пример #5
0
def map_tables(exclude_sys_tables=False):
    # Map bootstrap orm Linkage object (and dependent objects 
    # Relation and Cardinality) by hand
    if not exclude_sys_tables:
        for klass in BOOTSTRAP_CLASSES:
            class_ = setobject_type_registry.lookup(klass)
            class_.sa_map()

    # First, create all properties for the orm.relation method. This is a separate step,
    # as we use the sqlalchemy orm query object that requires all mapping acitvies are in a consistent state.
    # This we can only guarantee before and after the mapping process. Therefore we do it before.
    for setobject_type in setobject_type_registry.values():
        if needs_mapping(setobject_type, exclude_sys_tables):
            try:
                setobject_type.compute_mapper_properties()
            except NoPrimaryKeyException:
                # Table has no primary key, don't map it
                table_identifier = setobject_type.get_table_name()
                setobject_type_registry.delete_by_table(table_identifier)
                setobject_table_registry.delete_by_table(table_identifier)
  
    # In a second step we do the actual mapping with the already computed properties 
    # Map table type to ORM setobject type
    for setobject_type in setobject_type_registry.values():
        if needs_mapping(setobject_type, exclude_sys_tables):
            setobject_type.map_computed_properties()
 def post_order_traverse(self, mode):
     if mode == 'save':
         klass = setobject_type_registry.lookup(self.op_setobject_type.__name__)
         table_name = klass.get_table_name()
         map_field_attr(
             table_name,
             self.field_identifier,
             String(255))
Пример #7
0
 def sa_map(cls):
     #cls.sa_map_dispose()
     #cardinality_type.sa_map_dispose()
     #orm.mapper(cardinality_type, cardinality_table)
     Relation = setobject_type_registry.lookup('Relation')
     StrippedModel = setobject_type_registry.lookup('StrippedModel')
     orm.mapper(cls,
         cls.get_table_class(),
         properties={'relation': orm.relation(
             Relation,
             uselist=False,
             primaryjoin = (Relation.get_table_class().c.id == cls.get_table_class().c.fk_p2_relation)),
         'source_model': orm.relation(StrippedModel, uselist=False,
             primaryjoin= (StrippedModel.get_table_class().c.plan_identifier == cls.get_table_class().c.fk_source_model), enable_typechecks=False),
         'target_model': orm.relation(StrippedModel, uselist=False,
             primaryjoin= (StrippedModel.get_table_class().c.plan_identifier == cls.get_table_class().c.fk_target_model), enable_typechecks=False)
         }
     )
 def pre_order_traverse(self):
     if self.form == None:
         raise Exception("Can't finish initialization without the form attribute set.")
     
     # set op_setobject_type from parent form's attributes
     self.op_setobject_type = setobject_type_registry.lookup(self.form.klass)
     
     for span in self.spans.itervalues():
         span.widget = self
         span.op_setobject_type = self.op_setobject_type
Пример #9
0
 def sa_map(cls):
     cardinality_type = setobject_type_registry.lookup(
         'Cardinality'
     )
     orm.mapper(cls,
         cls.get_table_class(),
         properties={'cardinality': orm.relation(
             cardinality_type,
             uselist=False,
         )},
     )
 def _each_collection(self, node, setobject):
     if node.tag == 'obj':
         typename = node.get('type')
         klass = setobject_type_registry.lookup(typename)
         objid = node.get('objid')
         setobject = self.session.query(klass).get(objid)
         assert(setobject != None)
     for child in node:
         self._each_collection(child, setobject)
     # post order processing
     if node.tag == 'obj':
         self.process_collection_ids(node, setobject)
    def do_linkage(self, node, setobject, parent_setobject):
        linked = node.get('linked')
        if linked != None:
            if node.tag != 'obj': raise UnspecificException("Linked node must be of type obj.")
            collection_node = node.getparent() 
            if collection_node.tag != 'coll':
                # Parent is not of type coll.
                # Ignore it.
                return
    
            attr_name = collection_node.get('attr_name')
            span_identifier = collection_node.get('span_identifier')
            linkage = parent_setobject.collections[attr_name]['linkage']
            refkey = linkage.ref_key
 
            if linkage.use_list:
                coll = getattr(parent_setobject, attr_name)
                # Refkey: If there's a refkey the value of the key is searched within the object's properties.
                # If there's no refkey specified, we use the objid itself.
                key = None
                if refkey == None:
                    key = node.get('objid')
                else:
                    key = getattr(setobject, refkey)
                # Do actual linkage
                if linked == 'true':
                    coll[key] = setobject
                elif linked == 'false':
                    if key in coll:
                        del coll[key]
                else:
                    raise UnspecificException("Invalid link state.")
            else:
                if linked == 'true':
                    span_identifier = node.get('span_identifier')
                    if span_identifier is not None:
                        session = getUtility(IDbUtility).Session()
                        span_type = setobject_type_registry.lookup('SpanType')
                        span = session.query(span_type).get(span_identifier)
                        setobject = span.onbefore_set_payload_attribute(
                            setobject=parent_setobject,
                            attribute=attr_name,
                            value=setobject,
                            mode=self.mode
                            )
                    parent_setobject.set_attribute(
                        attribute=attr_name,
                        value=setobject,    
                        mode=self.mode
                    )
            # This flush is necessary. Otherwise it seems that if another reference to THIS object is
            # subsquently deleted via del coll[key], this linkage will not be persisted.
            self.session.flush()
Пример #12
0
    def compute_mapper_properties(cls):
        cls.get_primary_key_column() # make sure we have one! (will throw exception if that is not the case)
        properties = {}
        cls.fetch_linkages()
        for linkage in cls.linkages.itervalues():
            mappedsotype = setobject_type_registry.lookup(
                linkage.target_model.klass)

            if linkage.cardinality.id != 'NONE':
                # TODO: Don't pass properties. This is a nasty hack!
                mapper_properties = linkage.compute_orm_properties(properties)
                properties[linkage.attr_name] = orm.relation(mappedsotype, **mapper_properties)

        cls.mapper_properties = properties
 def __setattr__(self, name, value):
     super(Dropdown, self).__setattr__(name, value)
     if name == 'linkage':
         if self.plan_identifier != None and value != None:
             # Get the table identifier from our plan identifier and set it as the linkage's target class
             table = setobject_table_registry.lookup_by_table('p2_model')
             plan = getUtility(IDbUtility).engine.execute(table.select(table.c.plan_identifier == self.plan_identifier)).first()
             plan_type = plan['so_type']
             table_identifier = setobject_type_registry.lookup(plan_type).get_table_name()
             oldtargetclass = None
             try:
                 oldtargetclass = self.linkage.target_classname
             except AttributeError:
                 pass
             if oldtargetclass == None or oldtargetclass == "":
                 self.linkage.target_classname = table_identifier
    def query_not_joined(self):
        session = getUtility(IDbUtility).Session()
        plan_id = self.relation.plan_identifier
        from p2.datashackle.management.model.model import Model

        plan = session.query(Model).get(plan_id)
        target_type = setobject_type_registry.lookup(plan.klass)
        query = session.query(target_type)
        query = query.add_column(literal_column("'false'").label("linked"))
        if (
            hasattr(self.relation, "filter_clause")
            and self.relation.filter_clause != None
            and len(self.relation.filter_clause) > 0
        ):
            query = query.filter(self.relation.filter_clause)
        return query
 def post_order_traverse(self, mode):
     if mode == 'save':
         from p2.datashackle.management.model.model import Model
         plan_id = self.plan_identifier
         session = Session()
         plan = session.query(Model).filter_by(plan_identifier=plan_id).one()
         source_type = self.op_setobject_type
         target_type = setobject_type_registry.lookup(plan.klass)
 
         # set relation value
         self.relation.source_table = source_type.get_table_name()
         self.relation.target_table = target_type.get_table_name()
         self.relation.create_relation('LIST')
         
         # Set computed linkage values
         self.linkage.source_model = plan
         m = session.query(Model).filter_by(klass=plan.klass).one()
         self.linkage.target_model = m
 def post_order_processing(self, node, setobject, parent_setobject):
     if node.tag == 'root':
         return
     if node.tag == 'obj':
         self.do_linkage(node, setobject, parent_setobject)
     action = node.get('action') 
     if node.tag == 'coll' and node.get('span_identifier') != None:
         span_identifier = node.get('span_identifier')
         session = getUtility(IDbUtility).Session()
         span_type = setobject_type_registry.lookup('SpanType')
         span = session.query(span_type).get(span_identifier)
         span.onbefore_post_order_traverse(setobject, self.mode)
     elif node.tag == 'obj' and node.get('action') != 'delete':
         setobject.post_order_traverse(self.mode)   
     if node.tag == 'obj':
         if self.mode == 'save' and action == 'delete':
             self.session.delete(setobject)
         else:
             self.process_collection_ids(node, setobject)
    def post_order_traverse(self, mode):
        if mode == 'save':
            from p2.datashackle.management.model.model import Model
            plan_id = self.plan_identifier
            session = Session()
            plan = session.query(Model).filter_by(plan_identifier=plan_id).one()
            source_type = self.op_setobject_type
            target_type = setobject_type_registry.lookup(plan.klass)
            
            # Set computed values on inner objects
            m = session.query(Model).filter_by(klass=source_type.__name__).one()
            self.linkage.source_model = m
            m = session.query(Model).filter_by(klass=plan.klass).one()
            self.linkage.target_model = m

            self.linkage.relation.source_table = source_type.get_table_name() 
            self.linkage.relation.target_table = target_type.get_table_name()            

            if self.linkage.relation.cardinality.id != 'NONE':
                self.linkage.relation.create_relation()
 def callback(coll_node):
     if coll_node.get('linkage_id') == collection_id:
         # Check if setobject is already in xml
         found = False
         for child in coll_node:
             if child.get('objid') == setobject_id:
                 found = True
                 break
         if not found:
             if __debug__:
                 klass = setobject_type_registry.lookup(classname)
                 assert(self.session.query(klass).get(setobject_id) != None)
             obj = etree.Element("obj")
             # The setobject MUST already be present in sqlalchemy session. 
             # Through action 'save' it is later queried again.
             obj.set('action', 'save')
             obj.set('objid', setobject_id)
             obj.set('linked', linked)
             obj.set('type', classname)
             coll_node.append(obj)
 def dfs_main(self, node, setobject, callback, parent_setobject=None):
     descend = True
     preceding_setobject = setobject
     if node.tag == 'prop':
         attribute = node.get('name')
         value = node.text
         span_identifier = node.get('span_identifier')
         # Not all props have span_identifiers (e.g. css), because
         # these are not visualized as spans
         if span_identifier is not None:
             session = getUtility(IDbUtility).Session()
             span_type = setobject_type_registry.lookup('SpanType')
             span = session.query(span_type).get(span_identifier)
             assert(span != None)
             value = span.onbefore_set_payload_attribute(setobject, attribute, value, self.mode)
         setobject.set_attribute(attribute, value, self.mode)
     elif node.tag == 'obj':
         # Method sets up a processing scope which results
         # in new assignment of setobject.
         setobject, descend = self.process_object(node, parent_setobject)
     elif node.tag == 'coll':
         if self.mode == 'link':
             callback(node)
         attr_name = node.get('attr_name')
         linkage = setobject.collections[attr_name]['linkage']
         if setobject.action != 'new' and linkage.relation.cardinality.id == 'MANY_TO_ONE':
             # Set the attribute to None. If it's still linked, it will be done
             # so in do_linkage, but if not anymore, the attribute is deleted here.
             setattr(setobject, attr_name, None)
     elif node.tag == 'root':
         pass
     else:
         # Unknown/invalid node.
         raise SetobjectGraphException("Unknown node '" + node.tag + "'")
        
     if descend:
         # Traverse deeper into graph
         for child in node:
             self.dfs_main(child, setobject, callback, preceding_setobject)
    
     self.post_order_processing(node, setobject, preceding_setobject)
 def table_identifier(self):
     """The table on which this plan is operating."""
     klass = setobject_type_registry.lookup(self.klass)
     return klass.get_table_name()
    def query_joined(self, query_mode):
        if query_mode == None:
            if (
                self.relation.linkage.cardinality.id == "ONE(FK)_TO_ONE"
                or self.relation.linkage.cardinality.id == "ONE_TO_ONE(FK)"
            ):
                query_mode = QueryMode.WITH_UNLINKED
            else:
                query_mode = QueryMode.SHARED

        source_type = setobject_type_registry.lookup(self.relation.linkage.source_model.klass)
        target_type = setobject_type_registry.lookup(self.relation.linkage.target_model.klass)
        session = getUtility(IDbUtility).Session()

        if target_type == source_type:
            target_type = aliased(source_type)

        # Check if it is an xref relation
        xref_object = None
        if self.relation.linkage.cardinality.id == "MANY_TO_MANY":
            xref_object = setobject_type_registry.lookup_by_table(self.relation.linkage.xref_table)

        # Compose query for various modes:
        if query_mode == QueryMode.SHARED:
            query = session.query(target_type)

            # For n:m, we need to outerjoin the xref table first:
            if not xref_object == None:
                query = query.outerjoin(
                    (
                        xref_object,
                        target_type.get_primary_key_attr()
                        == getattr(xref_object, self.relation.linkage.relation.foreignkeycol2),
                    )
                )

            # Simply join with our source table from the target table. The join condition ensures we either get linked elements, or the source table's primary key field will be null/None.
            if xref_object == None:
                if (
                    self.relation.linkage.cardinality.id == "ONE_TO_MANY"
                    or self.relation.linkage.cardinality.id == "ONE_TO_ONE(FK)"
                ):
                    joincondition = getattr(source_type, source_type.get_primary_key_attr_name()) == getattr(
                        target_type, self.relation.linkage.relation.foreignkeycol
                    )
                else:
                    joincondition = (
                        getattr(source_type, self.relation.linkage.relation.foreignkeycol)
                        == target_type.get_primary_key_attr()
                    )
            else:
                joincondition = getattr(source_type, source_type.get_primary_key_attr_name()) == getattr(
                    xref_object, self.relation.linkage.relation.foreignkeycol
                )

            query = query.outerjoin((source_type, joincondition))

            # Since the the source table's primary key is either filled for linked elements or None for unlinked, this simple condition to find out what is linked to ourselves is sufficient.
            # Unlinked entries won't match since their source primary key field will be None.
            query = query.add_column(
                func.max(
                    case(
                        [
                            (
                                getattr(source_type, source_type.get_primary_key_attr_name())
                                == self.relation_source.id,
                                "true",
                            )
                        ],
                        else_="false",
                    )
                ).label("linked")
            )

            # For 1:n/1:1(fk), don't allow entries linked to someone else to show up (since they cannot have their foreign key point at two things).
            if xref_object == None and (
                self.relation.linkage.cardinality.id == "ONE_TO_MANY"
                or self.relation.linkage.cardinality.id == "ONE_TO_ONE(FK)"
            ):
                query = query.filter(
                    or_(
                        getattr(source_type, source_type.get_primary_key_attr_name()) == self.relation_source.id,
                        getattr(source_type, source_type.get_primary_key_attr_name()) == None,
                    )
                )

            # Group query
            query = query.group_by(target_type.get_primary_key_attr())
        else:
            if query_mode == QueryMode.EXCLUSIVE:
                # Inner join should be sufficient
                if xref_object is None:
                    # The join condition is also explicitely required here for cases with many relations to the same table
                    if self.relation.linkage.cardinality.id == "ONE_TO_MANY":
                        query = session.query(target_type).join(
                            (
                                source_type,
                                source_type.get_primary_key_attr()
                                == getattr(target_type, self.relation.linkage.relation.foreignkeycol),
                            )
                        )
                    else:
                        query = session.query(target_type).join(
                            (
                                source_type,
                                target_type.get_primary_key_attr()
                                == getattr(source_type, self.relation.linkage.relation.foreignkeycol),
                            )
                        )
                else:
                    # n:m, we need to specify the join condition:
                    query = session.query(target_type).join(
                        (
                            xref_object,
                            target_type.id == getattr(xref_object, self.relation.linkage.relation.foreignkeycol2),
                        )
                    )
                    query = query.join(
                        (
                            source_type,
                            and_(
                                source_type.id == getattr(xref_object, self.relation.linkage.relation.foreignkeycol),
                                source_type.id == self.relation_source.get_primary_key_attr(),
                            ),
                        )
                    )
            elif query_mode == QueryMode.WITH_UNLINKED:
                # we require a full outer join
                if xref_object is None:
                    query = session.query(target_type).outerjoin(source_type)
                else:
                    # n:m, we need to specify the join condition:
                    query = session.query(target_type).outerjoin(
                        (
                            xref_object,
                            target_type.id == getattr(xref_object, self.relation.linkage.relation.foreignkeycol2),
                        )
                    )
                    query = query.join(
                        (
                            source_type,
                            or_(
                                and_(
                                    source_type.id
                                    == getattr(xref_object, self.relation.linkage.relation.foreignkeycol),
                                    source_type.id == self.relation_source.get_primary_key_attr(),
                                ),
                                source_type.id == None,
                            ),
                        )
                    )

            if xref_object is None:
                if self.relation.linkage.cardinality.id == "ONE_TO_MANY":
                    # Foreignkey on target_type side
                    foreignkey_attr = getattr(target_type, self.relation.linkage.relation.foreignkeycol)
                else:
                    # Foreignkey on source_type side
                    foreignkey_attr = getattr(source_type, self.relation.linkage.relation.foreignkeycol)

                query = query.add_column(case([(foreignkey_attr == None, "false")], else_="true").label("linked"))

                if query_mode == QueryMode.WITH_UNLINKED:
                    query = query.filter(
                        or_(source_type.get_primary_key_attr() == self.relation_source.id, foreignkey_attr == None)
                    )
            else:
                # n:m relation
                foreignkeycolumn1 = getattr(xref_object, self.relation.linkage.relation.foreignkeycol)
                foreignkeycolumn2 = getattr(xref_object, self.relation.linkage.relation.foreignkeycol2)
                query = query.add_column(
                    case([((or_(foreignkeycolumn1 == None, foreignkeycolumn2 == None)), "false")], else_="true").label(
                        "linked"
                    )
                )

                if query_mode == QueryMode.WITH_UNLINKED:
                    query = query.filter(
                        or_(
                            source_type.get_primary_key_attr() == self.relation_source.id,
                            foreignkeycolumn1 == None,
                            foreignkeycolumn2 == None,
                        )
                    )

            if query_mode == QueryMode.EXCLUSIVE:
                query = query.filter(
                    getattr(source_type, source_type.get_primary_key_attr_name()) == self.relation_source.id
                )

        # Check for additional constraints on relation widget
        if (
            hasattr(self.relation, "filter_clause")
            and self.relation.filter_clause != None
            and len(self.relation.filter_clause) > 0
        ):
            query = query.filter(self.relation.filter_clause)

        return query
Пример #22
0
    def compute_orm_properties(self, THIS_IS_A_DIRTY_HACK_PROPERTIES_DICT):
        mappedsotype = setobject_type_registry.lookup(self.target_model.klass)
        xref_table_class = None
        sourcetable = setobject_table_registry.lookup_by_class(self.source_model.klass)
        targettable = setobject_table_registry.lookup_by_class(self.target_model.klass)
        if self.cardinality.id == 'MANY_TO_ONE' or \
                self.cardinality.id == 'ONE(FK)_TO_ONE':
            # take primary key on our side
            primaryfk = getattr(sourcetable.c, self.relation.foreignkeycol)
            primaryidentifier = getattr(targettable.c, mappedsotype.get_primary_key_attr_name())
            primaryjoin = (primaryfk == primaryidentifier)
            secondaryjoin = None
        elif self.cardinality.id == 'ONE_TO_MANY' or \
                self.cardinality.id == 'ONE_TO_ONE(FK)':
            # take primary key on other side
            primaryfk = getattr(targettable.c, self.relation.foreignkeycol)
            primaryidentifier = getattr(
                sourcetable.c,
                setobject_type_registry.lookup(self.source_model.klass).get_primary_key_attr_name()
            )
            primaryjoin = (primaryfk == primaryidentifier)
            secondaryjoin = None
        elif self.cardinality.id == 'MANY_TO_MANY':
            # xref! we actually need two clauses here.
            
            # Obtain table class:
            xref_table_class = setobject_table_registry.get_by_table(self.relation.xref_table)
            if xref_table_class is None:
                # Class is not mapped (probably not having a primary key or something like that) -> autoload
                xref_table_class = Table(self.relation.xref_table, metadata, autoload=True, useexisting=True, autoload_with=getUtility(IDbUtility).engine)
            
            # Compose two join clauses
            primaryjoin = (cls.get_primary_key_column() == getattr(xref_table_class.c, self.relation.foreignkeycol))
            secondaryjoin = (mappedsotype.get_primary_key_column() == getattr(xref_table_class.c, self.relation.foreignkeycol2))
        
        # add the obtained setobject to our mapped properties
        if self.cardinality.id == 'MANY_TO_ONE':
            # This mapping should really not happen here and now.
            # Instead, the linkage MUST be persisted into
            # table p2_linkage at save time!

            THIS_IS_A_DIRTY_HACK_PROPERTIES_DICT[self.attr_name] = orm.relation(
                mappedsotype,
                uselist=False,
                cascade=self.cascade,
                back_populates=self.back_populates,
                primaryjoin=primaryjoin,
                post_update=self.post_update
            )
            relationarguments = {
                'uselist' : False,
                'cascade' : self.cascade,
                'back_populates' : self.back_populates,
                'primaryjoin' : primaryjoin,
                'post_update' : self.post_update
            }
        else:
            # the other side has the foreign key, store things as a collection
            
            order_by = None
            collection_class = None
            
            # This is a special case for the spans as they should not be mapped as ordinary
            # dictionary, but rather as an orderable dictionary. This is necessary to retain the insert order
            # as a ordinary dict isn't ordered. Consider this to be implemented in a more generic way if this
            # use case is occuring for user relations as well.
            if self.attr_name == 'spans' and self.source_model.klass == 'WidgetType':
                collection_class=SpanCollectionClass
                span_table = setobject_table_registry.lookup_by_table('p2_span')
                order_by=span_table.c.order
            
            # This is another special case to ensure the widgets being tab ordered
            if self.attr_name == 'widgets' and self.source_model.klass == 'FormType':
                collection_class = WidgetCollectionClass
                widget_table = setobject_table_registry.lookup_by_table('p2_widget')
                order_by=widget_table.c.tab_order
            
            # Get collection class
            if collection_class == None:
                if self.ref_key is None:
                    collection_class = column_mapped_collection(mappedsotype.get_primary_key_column())
                else:
                    mapped_column = mappedsotype.get_column(self.ref_key)
                    collection_class = column_mapped_collection(mapped_column)
            
            # Compute arguments:
            relationarguments = {
                'back_populates' : self.back_populates,
                'collection_class' : collection_class,
                'uselist' : True,
                'primaryjoin': primaryjoin,
                'cascade' : self.cascade,
                'post_update' : self.post_update
                }
            if order_by is not None:
                relationarguments['order_by'] = order_by
        
        # Set xref table if we got one
        if xref_table_class is not None:
            relationarguments['secondary'] = xref_table_class
            if secondaryjoin is not None:
                relationarguments['secondaryjoin'] = secondaryjoin
        
        return relationarguments
 def process_object(self, node, parent_setobject):
     action = node.get('action')
     if not action:
         raise SetobjectGraphException("Mandatory action attribute missing.")
     typename = node.get('type')
     klass = setobject_type_registry.lookup(typename)
     objid = node.get('objid')
     linked = node.get('linked')
         
     setobject = None
     if action == 'new' and node.getparent().tag == 'coll':
         attr_name = node.getparent().get('attr_name')
         linkage = parent_setobject.collections[attr_name]['linkage']
         if not linkage.use_list:
             if linked == 'true' and \
                     getattr(parent_setobject, attr_name, None) != None:
                 setobject = getattr(parent_setobject, attr_name)
                 setobject.id = objid
         else:
             refkey = linkage.ref_key
             coll = getattr(parent_setobject, attr_name)
             key = None
             if refkey == None:
                 key = node.get('objid')
             else:
                 for prop in node:
                     if prop.get('name') == refkey:
                         key = prop.text
                         break;
                 assert(key != None)
             if key in coll:
                 setobject = coll[key]
                 setobject.id = objid
     if setobject == None:
         if action == 'save':
             setobject = self.session.query(klass).filter(klass.get_primary_key_attr() == objid).one()
             self.session.add(setobject)
             notify(ObjectCreatedEvent(setobject))
             self.session.flush()
         elif action == 'new':
             assert(self.session.query(klass).get(objid) is None)
             setobject = klass()
             setobject.id = objid
             self.session.add(setobject)
             self.session.flush()
         elif action == 'delete':
             setobject = self.session.query(klass).filter(klass.get_primary_key_attr() == objid).one()
             # Actual deletion is performed as post order step as it may be necessary
             # to clear linkages prior deleting the object.
             setobject = self.session.query(klass).filter(klass.get_primary_key_attr() == objid).one()
         else:
             raise SetobjectGraphException("Invalid action '" + action + "' for setobject", node.get('objid'))
     
     self.do_linkage(node, setobject, parent_setobject)
     if action != 'delete':
         setobject.pre_order_traverse()
     
     setobject = self.session.query(klass).get(objid)
     assert(setobject != None)
     
     if action == 'delete':
         # Don't need to traverse deeper in tree.
         descend = False
     else:
         descend = True
     return setobject, descend
 def create_widget(cls, widget_type):
     widget_type = setobject_type_registry.lookup(widget_type)
     widget = widget_type()
     return widget
    def do(self, plan, searchterm, group, page, resultsperpage, uservars=[]):
        """ Do a search on the plan based on a generic search term and return the results.
        The results will also be associated with information about which fields actually
        matched the search query and whether there is a next page to the current one. 
        Please note this implementation is most likely SLOW and could need optimization or
        replacement at some point. """

        dbutility = getUtility(IDbUtility)
        
        # change searchterm into LIKE compatible syntax
        searchterm = self.replaceoperators(searchterm)
        
        # list to hold the search values/columns we collect from the widgets
        searchvalues = []
            
        # collect all columns based on the widgets on the form and their mapping
        for form in plan.forms.itervalues():
            for widget in form.widgets.itervalues():
                if widget.widget_type == 'relation' or \
                        widget.widget_type == 'fileupload' or \
                        widget.widget_type == 'dropdown':
                    continue
                for span in widget.spans.itervalues():
                    if hasattr(span, 'attr_name') and span.attr_name != None:
                        # We got a new column to examine.
                        if span.attr_name != 'span_value' and len(span.attr_name) > 0:
                            self.addsearchvalue(searchvalues, span.attr_name, widget.widget_identifier, form.form_identifier)
        
        # do we have some columns to search through?
        #if len(searchvalues) <= 0:
        #    return {'resultset' : None, 'searchfields' : None, 'nextpage': False} # nothing to search for!
        
        # get the table class object
        tableclass = setobject_table_registry.lookup_by_table(plan.table_identifier)
        
        # lists for composing the conditions/columns used in our query
        conditions = []
        columns = []
        
        # we always want to have the primary key column in our results
        klass = setobject_type_registry.lookup(plan.klass)
        columns.append(getattr(tableclass.c, klass.get_primary_key_attr_name()))
        
        # compose the search conditions based on the avilable input fields
        for value in searchvalues:
            if searchterm != '%':
                condition = getattr(tableclass.c, value['field']).like(searchterm, escape='\\')
            else:
                condition1 = getattr(tableclass.c, value['field']).like(searchterm, escape='\\')
                condition2 = (getattr(tableclass.c, value['field']) == None)
                condition = or_(condition1, condition2)
            conditions.append(condition)
            columns.append(getattr(tableclass.c, value['field']))
            columns.append(condition.label("_field_matched_" + value['field']))
        
        # compose our query
        if len(conditions) > 0:
            queryobj = select(columns).where(or_(*conditions)).offset((int(page)-1) * resultsperpage).limit(resultsperpage+1)
        else:
            queryobj = select(columns).offset((int(page)-1) * resultsperpage).limit(resultsperpage+1)
        
        # See if there is a next page to this one
        gotnextpage = False
        resultarray = []
        results = queryobj.execute()
        for result in results:
            if len(resultarray) < resultsperpage:
                resultarray.append(result)
            else:
                gotnextpage = True
        
        return {'resultset' : resultarray, 'searchfields' : searchvalues, 'nextpage' : gotnextpage}
Пример #26
0
 def create_span(cls, span_type_name, span_name):
     span_type = setobject_type_registry.lookup(span_type_name)
     return span_type(span_name)