Exemple #1
0
    def _identify_relationships(self):
        ''' Identify relationships in relations
            
            Identify relationships by the following steps
            (1) The relation must have more than one disjoint foreign keys  
                which referencing to identifiers of Entities
                Let such fkey be E_fkey
            (2) Examining primary key
                1). if pkey has NO E_fkey
                    pkey is a 1:m attribute of A Relationship, whose Identifier is 
                    other E_fkey in this relation.
                    The attribute will be assign to the Relationship if exists
                    otherwise the relation unassigned
                2). pkey has ONLY E_fkeys
                    if other E_fkeys exists in relation, 
                    then relation represents m : 1 Relationship
                    m: Entities whose identifiers are in pkey
                    1: other E_fkeys
                    If other attributes exists as nonprimes of relation
                    they are m:1 attributes of Relationship
                    If other keys which are not identifiers of Entitiy exists
                    they are 1:1 attributes of Relationship
                3). pkey has E_fkeys and other attributes
                    if all-key relation
                    then this represents m:m Relationship with multivalued attributes
                    else unassigned

        '''

        def examine_pkey(pkey, E_fkeys, R):
            ''' examine pkey, partition pkey into those in E_fkeys and others '''

            idr_in_pkey ={fk: R.fkeys[fk].refed_key for fk in E_fkeys if fk.issubset(pkey)}
            otr_attr = pkey.difference(set([a for fk in idr_in_pkey for a in fk]))
            return idr_in_pkey, otr_attr

        # The following assume all identifiers are disjoint
        # this assumption would be a probem if exists relations referencing to IDD entites
        # find all Identifiers of Entitnies 
        # relaxed universal assumption, all identifiers are unique
        all_identifiers = {ent.identifier.elements: name for name, ent in self._entities.items()}

        # unassigned_attributes
        unassigned_attributes = {}

        for name, R in self._R_relations.items():
            # find the E_fkeys of relation R
            pkey = R.pkey
            E_fkeys = [fk_name for fk_name, fk  in R.fkeys.items() if fk.refed_key in all_identifiers]
            dsj_fkey_count = self._count_disjoint_keys(E_fkeys)

            # 1) more than one fkeys referencing Entitites
            if dsj_fkey_count > 1:
                idr_in_pkey, otr_attr = examine_pkey(pkey, E_fkeys, R) 
                if not idr_in_pkey:
                    # pkey has NO E_fkey
                    R_identifier = frozenset([npa for npa in R.non_primes if frozenset([npa]) in all_identifiers])
                    otr_non_primes = R.non_primes.difference(R_identifier)
                    if not otr_non_primes:
                        unassigned_attributes.update({R_identifer: pkey})

                elif not otr_attr:
                    # 2) only E_fkeys
                    rel = Relationship(name, RelationshipType.regular, frozenset(pkey))
                    for idr, E_name in all_identifiers.items():
                        if idr in idr_in_pkey.values():
                            rel.add_participating_entity(E_name, 'm')

                    for npa in R.non_primes:
                        key = frozenset([npa])
                        if key in all_identifiers:
                            rel.add_participating_entity(all_identifiers[key], '1')
                        else:
                            attr = Attribute(npa, key, Cardinality.many2one)
                            rel.add_attribute(attr)

                    self._add_relationship(rel, RelationshipType.regular)

                else:
                    # 3) pkey has other attributes
                    if R.attributes == pkey:
                        # all key relation
                        rel = Relationship(name, RelationshipType.regular, frozenset(pkey))
                        for idr, E_name in all_identifiers.items():
                            if idr in idr_in_pkey.values():
                                rel.add_participating_entity(E_name, 'm')
                        for npa in otr_attr:
                            key = frozenset([npa])
                            attr = Attribute(npa, key, Cardinality.many2many)
                            rel.add_attribute(attr)

                        self._add_relationship(rel, RelationshipType.regular)
                    else:
                        self._unassigned_relations.append(R)

        # After determine the main relationships 
        # try to comibine with other E_relations left
        self._combine_relationship()