Exemplo n.º 1
0
def sqlrelations_collect(self, source, target):
    """Finds all associations, prepares them and adds them to the corrsponding
    classes.
    """

    detail = source.memberEnds[0]
    detailclass = detail.type
    master = source.memberEnds[1]
    masterclass = master.type

    if not masterclass.stereotype('sql:sql_content'):
        return
    if not detailclass.stereotype('sql:sql_content'):
        return

    mastertok = token(str(masterclass.uuid), True, outgoing_relations=[],incoming_relations=[])
    detailtok = token(str(detailclass.uuid), True, outgoing_relations=[],incoming_relations=[])
    
    if IAssociationClass.providedBy(source):
        detailtok.outgoing_relations.append(detail)
        mastertok.outgoing_relations.append(master)
    elif detail.aggregationkind in ['composite','aggregation','shared'] or \
            IAssociationClass.providedBy(source):
        #for aggregations the arrow points from the master to the detail
        detailtok.incoming_relations.append(detail)
        mastertok.outgoing_relations.append(master)
    else:
        #simple FK relation, so other direction
        mastertok.incoming_relations.append(master)
Exemplo n.º 2
0
def sqlrelations_foreignkeys(self, source, target):
    """Generate foreign key attributes.
    """
    if source.stereotype('pyegg:stub'):
        return
    if not source.stereotype('sql:sql_content'):
        return

    targetclass = read_target_node(source, target.target)
    module=targetclass.parent
    # get the last attribute and append there the foreignkeys
    attrs = targetclass.attributes()
    attrnames = [att.targets[0] for att in attrs]

    incoming_relations = token(str(source.uuid),
                               True, incoming_relations=[]).incoming_relations
                               
    for relend in incoming_relations:
        klass = relend.type
        
        #no foreign keys needed for Association Classes
        if IAssociationClass.providedBy(relend.association):
            continue
        
        #fetch the opposite relation end
        if relend==relend.association.memberEnds[0]:
            otherend = relend.association.memberEnds[1]
        else:
            otherend = relend.association.memberEnds[0]
        otherclass = otherend.type
        
        nullable = not relend.aggregationkind=='composite'

        joins=calculate_joins(source, targetclass, otherclass, otherend.name, nullable = nullable)
        token(str(otherend.uuid), True, joins=joins)
Exemplo n.º 3
0
def sqlrelations_relations(self, source, target):
    """generate relations.
    """
    if source.stereotype('pyegg:stub'):
        return
    if not source.stereotype('sql:sql_content'):
        return

    targetclass = read_target_node(source, target.target)
    module = targetclass.parent
    directory = module.parent
    # get the last attribute and append there the relations
    attrs = targetclass.attributes()
    attrnames = [att.targets[0] for att in attrs]
    try:
        lastattr = targetclass.attributes()[-1]
    except IndexError:
        lastattr = None

    outgoing_relations = token(str(source.uuid),
                               True, outgoing_relations=[]).outgoing_relations
    imps = Imports(module)

    if outgoing_relations:
        imps.set('sqlalchemy.orm', [['relationship', None]])

    for relend in outgoing_relations:
        assoc = relend.association
        if relend==relend.association.memberEnds[0]:
            otherend = relend.association.memberEnds[1]
        else:
            otherend = relend.association.memberEnds[0]

        #Association classes are handled seperately
        #once we support association tables, we have to handle it here
        tgv = TaggedValues(assoc)
        if IAssociationClass.providedBy(assoc):
            # tgv = TaggedValues(otherend) We need to build support for tgvs on 
            # member ends later
            klass = relend.type
            otherclass = relend.association
            relname = token(str(otherend.uuid), True, relname=otherend.name+'_associations').relname
        else:
            klass = relend.type
            otherclass = otherend.type
            relname = otherend.name

        if relname not in attrnames:
            attr = Attribute()
            attr.__name__ = str(attr.uuid)
            if lastattr:
                targetclass.insertafter(attr, lastattr)
            else:
                targetclass.insertfirst(attr)

            attr.targets = [relname]
            options = {}
            # collect options for relationship
            if otherend.aggregationkind == 'composite':
                options['cascade'] = "'all, delete-orphan'"
            if assoc.stereotype('sql:ordered'):
                order_by = tgv.direct('order_by', 'sql:ordered', None)
                if not order_by:
                    msg = 'when setting a relation ordered you have to ' +\
                          'specify order_by!'
                    raise ValueError(msg)
                # if not prefixed, lets prefix it
                if not '.' in order_by:
                    order_by = '%s.%s' % (otherclass.name, order_by)
                options['order_by'] = "'%s'" % order_by
            if assoc.stereotype('sql:attribute_mapped'):
                keyname = tgv.direct('key', 'sql:attribute_mapped', None)
                if not keyname:
                    msg = 'when defining attribute_mapped you have to ' + \
                          'specify a key'
                    raise ValueError(msg)
                if assoc.stereotype('sql:ordered'):
                    # support for ordered mapped collection
                    # in this case we have to provide our own collection
                    # see http://docs.sqlalchemy.org/en/rel_0_7/orm/collections.html,
                    # secion 'Custom Dictionary-Based Collections'
                    fname = 'orderedcollection.py'
                    if fname not in directory:
                        src = JinjaTemplate()
                        src.template = templatepath(fname + '.jinja')
                        src.params = {}
                        directory[fname] = src
                        # XXX: so that emptymoduleremoval doesnt kick the
                        # template out better would be that jinjatemplates
                        # dont get removed at all
                        token('pymodules', True, modules=set()).modules.add(src)
                    options['collection_class'] = \
                        "ordered_attribute_mapped_collection('%s')" % keyname
                    imps.set('orderedcollection',
                             [['ordered_attribute_mapped_collection', None]])
                # unordered
                else:
                    options['collection_class'] = \
                        "attribute_mapped_collection('%s')" % keyname
                    imps.set('sqlalchemy.orm.collections',
                             [['attribute_mapped_collection', None]])

            # make the primaryjoin stmt
            if 1 or not IAssociationClass.providedBy(relend.association):
                tok = token(str(relend.uuid), True, joins=[])
                if tok.joins:
                    options['primaryjoin'] = "'%s'" % ','.join(tok.joins)

            # XXX: .navigable isn't yet correctly parsed from uml, thus the
            # hardcoding
            if True or relend.navigable:
                options['backref'] = "'%s'" % relend.name.lower()
            if assoc.stereotype('sql:lazy'):
                laziness = tgv.direct('laziness', 'sql:lazy', 'dynamic')
                options['lazy'] = "'%s'" % laziness

            #convert options into keyword params
            oparray = []
            for k in options:
                oparray.append('%s = %s' % (k, options[k]))

            attr.value = "relationship('%s', %s)" % (
                otherclass.name, ', '.join(oparray))