Exemple #1
0
def generate_table_schema_interface(ti):
    '''!+DO_NOT_REORDER_USER_APPLIED_INTERFACES
    def get_domain_interfaces(domain_model):
        """Return the domain bases for an interface as well as a filtered 
        implements only list (base interfaces removed).
        
        Note that for 2nd level (mapped) domain classes i.e. those that inherit
        from another domain class e.g. Event(Doc), Office(Group), 
        OfficeMember(GroupMembership), an IIModelInterface-providing 
        I*TableSchema interface had already been created (for base class) and 
        assigned to the super class--and that interface will match as one of 
        the domain_base interfaces here.
        """
        domain_bases = []
        domain_implements = []
        for iface in interface.implementedBy(domain_model):
            if IIModelInterface.providedBy(iface):
                domain_bases.append(iface)
            else:
                domain_implements.append(iface)
        domain_bases = tuple(domain_bases) or (IAlchemistContent,)
        return domain_bases, domain_implements
    bases, implements = get_domain_interfaces(ti.domain_model)
    '''

    # derived_table_schema:
    # - ALWAYS dynamically generated
    # - directlyProvides IIModelInterface (by virtue of IAlchemistContent)
    type_key = naming.polymorphic_identity(ti.domain_model)
    # use the class's mapper select table as input for the transformation
    table_schema_interface_name = naming.table_schema_interface_name(type_key)
    domain_table = utils.get_local_table(ti.domain_model)

    derived_table_schema = transmute(
        domain_table,
        annotation=ti.descriptor_model,
        interface_name=table_schema_interface_name,
        __module__=INTERFACE_MODULE.__name__,
        #_generated_by="bungeni.alchemist.catalyst.generate_table_schema_interface"
        #bases=bases)
        bases=(IAlchemistContent, ))

    # apply, register on type_info, set on module
    interface.classImplements(ti.domain_model, derived_table_schema)
    utils.inisetattr(ti, "derived_table_schema", derived_table_schema)
    setattr(INTERFACE_MODULE, table_schema_interface_name,
            derived_table_schema)
    log.info("generate_table_schema_interface: %s", derived_table_schema)

    # defensive sanity check - that derived_table_schema is precisely the FIRST
    # resolving IIModelInterface-providing interface implemented by domain_model
    # !+ this failing does not necessarily mean an incorrectness
    for iface in interface.implementedBy(ti.domain_model):
        if IIModelInterface.providedBy(iface):
            assert iface is derived_table_schema, (ti.domain_model, iface,
                                                   id(iface),
                                                   derived_table_schema,
                                                   id(derived_table_schema))
            break
    '''!+DO_NOT_REORDER_USER_APPLIED_INTERFACES
Exemple #2
0
def new_custom_domain_model(type_key, domain_interface, archetype_key):
    domain_model_name = naming.model_name(type_key)
    assert archetype_key, \
        "Custom descriptor %r does not specify an archetype" % (type_key)
    archetype = getattr(MODEL_MODULE, naming.model_name(archetype_key)) # AttributeError
    # !+ assert archetype constraints
    domain_model = type(domain_model_name,
        (archetype,),
        {
            "__module__": MODEL_MODULE.__name__,
            "extended_properties": [],
        }
    )
    # apply domain_interface
    classImplements(domain_model, domain_interface)
    # set on MODEL_MODULE (register on type_info downstream)
    setattr(MODEL_MODULE, domain_model_name, domain_model)
    # db map custom domain class
    from sqlalchemy.orm import mapper
    mapper(domain_model, 
        inherits=archetype,
        polymorphic_on=utils.get_local_table(archetype).c.type,
        polymorphic_identity=type_key, #naming.polymorphic_identity(domain_model),
    )
    log.info("new_custom_domain_model [%s] %s.%s" % (
            type_key, MODEL_MODULE.__name__, domain_model_name))
    return domain_model
Exemple #3
0
def new_custom_domain_model(type_key, domain_interface, archetype_key):
    domain_model_name = naming.model_name(type_key)
    assert archetype_key, \
        "Custom descriptor %r does not specify an archetype" % (type_key)
    archetype = getattr(MODEL_MODULE,
                        naming.model_name(archetype_key))  # AttributeError
    # !+ assert archetype constraints
    domain_model = type(domain_model_name, (archetype, ), {
        "__module__": MODEL_MODULE.__name__,
        "extended_properties": [],
    })
    # apply domain_interface
    classImplements(domain_model, domain_interface)
    # set on MODEL_MODULE (register on type_info downstream)
    setattr(MODEL_MODULE, domain_model_name, domain_model)
    # db map custom domain class
    from sqlalchemy.orm import mapper
    mapper(
        domain_model,
        inherits=archetype,
        polymorphic_on=utils.get_local_table(archetype).c.type,
        polymorphic_identity=
        type_key,  #naming.polymorphic_identity(domain_model),
    )
    log.info("new_custom_domain_model [%s] %s.%s" %
             (type_key, MODEL_MODULE.__name__, domain_model_name))
    return domain_model
def generate_table_schema_interface(ti):
    '''!+DO_NOT_REORDER_USER_APPLIED_INTERFACES
    def get_domain_interfaces(domain_model):
        """Return the domain bases for an interface as well as a filtered 
        implements only list (base interfaces removed).
        
        Note that for 2nd level (mapped) domain classes i.e. those that inherit
        from another domain class e.g. Event(Doc), Office(Group), 
        OfficeMember(GroupMembership), an IIModelInterface-providing 
        I*TableSchema interface had already been created (for base class) and 
        assigned to the super class--and that interface will match as one of 
        the domain_base interfaces here.
        """
        domain_bases = []
        domain_implements = []
        for iface in interface.implementedBy(domain_model):
            if IIModelInterface.providedBy(iface):
                domain_bases.append(iface)
            else:
                domain_implements.append(iface)
        domain_bases = tuple(domain_bases) or (IAlchemistContent,)
        return domain_bases, domain_implements
    bases, implements = get_domain_interfaces(ti.domain_model)
    '''
    
    # derived_table_schema:
    # - ALWAYS dynamically generated
    # - directlyProvides IIModelInterface (by virtue of IAlchemistContent)
    type_key = naming.polymorphic_identity(ti.domain_model)
    # use the class's mapper select table as input for the transformation
    table_schema_interface_name = naming.table_schema_interface_name(type_key)
    domain_table = utils.get_local_table(ti.domain_model)
    
    derived_table_schema = transmute(
        domain_table,
        annotation=ti.descriptor_model,
        interface_name=table_schema_interface_name,
        __module__=INTERFACE_MODULE.__name__,
        #_generated_by="bungeni.alchemist.catalyst.generate_table_schema_interface"
        #bases=bases)
        bases=(IAlchemistContent,))
    
    # apply, register on type_info, set on module
    interface.classImplements(ti.domain_model, derived_table_schema)
    utils.inisetattr(ti, "derived_table_schema", derived_table_schema)
    setattr(INTERFACE_MODULE, table_schema_interface_name, derived_table_schema)
    log.info("generate_table_schema_interface: %s", derived_table_schema)
    
    # defensive sanity check - that derived_table_schema is precisely the FIRST
    # resolving IIModelInterface-providing interface implemented by domain_model
    # !+ this failing does not necessarily mean an incorrectness
    for iface in interface.implementedBy(ti.domain_model):
        if IIModelInterface.providedBy(iface):
            assert iface is derived_table_schema, (ti.domain_model, 
                iface, id(iface), 
                derived_table_schema, id(derived_table_schema))
            break
    
    '''!+DO_NOT_REORDER_USER_APPLIED_INTERFACES
Exemple #5
0
def instrument_extended_properties(cls, object_type=None, from_class=None):
    if object_type is None:
        object_type = utils.get_local_table(cls).name
    if from_class is None:
        from_class = cls
    # ensure cls.__dict__.extended_properties
    cls.extended_properties = cls.extended_properties[:]
    for vp_name, vp_type in from_class.extended_properties:
        if (vp_name, vp_type) not in cls.extended_properties:
            cls.extended_properties.append((vp_name, vp_type))
        setattr(cls, vp_name, vertical_property(object_type, vp_name, vp_type))
        mapper_add_relation_vertical_property(cls, vp_name, vp_type)
Exemple #6
0
def instrument_extended_properties(cls, object_type=None, from_class=None):
    if object_type is None:
        object_type = utils.get_local_table(cls).name
    if from_class is None:
        from_class = cls
    # ensure cls.__dict__.extended_properties
    cls.extended_properties = cls.extended_properties[:]
    for vp_name, vp_type in from_class.extended_properties:
        if (vp_name, vp_type) not in cls.extended_properties:
            cls.extended_properties.append((vp_name, vp_type))
        setattr(cls, vp_name, vertical_property(object_type, vp_name, vp_type))
        mapper_add_relation_vertical_property(cls, vp_name, vp_type)
Exemple #7
0
def instrument_extended_properties(cls, object_type=None):
    if object_type is None:
        object_type = utils.get_local_table(cls).name
    for vp_name, vp_type in cls.extended_properties:
        setattr(cls, vp_name, vertical_property(object_type, vp_name, vp_type))
        mapper_add_relation_vertical_property(cls, vp_name, vp_type)
    def decorate_model(self, model):
        # Assumption: if a domain class is explicitly pre-defined, then it is
        # assumed that all necessary setup is also taken care of.
        # Typically, only the sub-classes of an archetype (mapped to a same
        # table) need dynamic creation/setup.

        def get_audit_class_for(auditable_class):
            audit_cls_name = "%sAudit" % (auditable_class.__name__)
            return getattr(MODEL_MODULE, audit_cls_name, None)

        def get_base_audit_class(model):
            """Identify what should be the BASE audit class for a 
            {model}Audit class to inherit from, and return it.
            """
            assert interfaces.IFeatureAudit.implementedBy(model), model
            ti = capi.get_type_info(model)
            if ti.archetype is None:
                # !+ should this be allowed to ever happen?
                # i.e. require each type to declare an archetype?
                base_audit_class = domain.Audit
            else:
                base_audit_class = get_audit_class_for(ti.archetype)
                if base_audit_class is None:
                    # fallback to get the audit class for the sys archetype
                    base_audit_class = get_audit_class_for(ti.sys_archetype)
                assert base_audit_class is not None, (model, ti.archetype,
                                                      base_audit_class)
            return base_audit_class

        def new_audit_class(model):
            """Create, set on MODEL_MODULE, and map {model}Audit class.
            """
            base_audit_cls = get_base_audit_class(model)
            audit_cls = base_audit_cls.auditFactory(model)
            # set on MODEL_MODULE
            setattr(MODEL_MODULE, audit_cls.__name__, audit_cls)
            # mapper for newly created audit_cls
            mapper(audit_cls,
                   inherits=base_audit_cls,
                   polymorphic_identity=naming.polymorphic_identity(model))
            log.info("GENERATED new_audit_class %s(%s) for type %s", audit_cls,
                     base_audit_cls, model)
            return audit_cls

        # domain - audit class
        audit_cls = get_audit_class_for(model)
        if audit_cls is None:
            audit_cls = new_audit_class(model)

        # auditor - head cls
        import bungeni.core.audit
        bungeni.core.audit.set_auditor(model)

        # mapper - audit class
        # assumption: audit_cls uses single inheritance only (and not only for
        # those created dynamically in feature_audit())
        base_audit_cls = audit_cls.__bases__[0]
        assert issubclass(base_audit_cls, domain.Audit), \
            "Audit class %s is not a proper subclass of %s" % (
                audit_cls, domain.Audit)

        # extended attributes - propagate any on head cls also to its audit_cls
        for vp_name, vp_type in model.extended_properties:
            mapper_add_relation_vertical_property(audit_cls, vp_name, vp_type)
        # !+NOTE: capi.get_type_info(model).descriptor_model is still None

        # model.changes <-> change.audit.audit_head=doc:
        # doc[@TYPE] <-- TYPE_audit <-> audit <-> change

        # get head table for kls, and its audit table.
        tbl = utils.get_local_table(model)
        # NOT mapped_table, as when cls_mapper.single=False (e.g. for
        # the case of the group type) it gves an sa.sql.expression.Join,
        # and not a table object:
        #   principal JOIN "group" ON principal.principal_id = "group".group_id
        audit_tbl = getattr(schema, naming.audit_table_name(tbl.name))
        cls_mapper = class_mapper(model)
        cls_mapper.add_property(
            "changes",
            relation(
                domain.Change,
                # join condition, may be determined by a composite primary key
                primaryjoin=sa.and_(*[
                    pk_col == audit_tbl.c.get(pk_col.name)
                    for pk_col in tbl.primary_key
                ]),
                secondary=audit_tbl,
                secondaryjoin=sa.and_(
                    audit_tbl.c.audit_id == schema.change.c.audit_id, ),
                lazy=True,
                order_by=schema.change.c.audit_id.desc(),
                cascade="all",
                passive_deletes=False,  # SA default
            ))
    def decorate_model(self, model):
        # Assumption: if a domain class is explicitly pre-defined, then it is 
        # assumed that all necessary setup is also taken care of. 
        # Typically, only the sub-classes of an archetype (mapped to a same 
        # table) need dynamic creation/setup.
        
        def get_audit_class_for(auditable_class):
            audit_cls_name = "%sAudit" % (auditable_class.__name__)
            return getattr(MODEL_MODULE, audit_cls_name, None)
        
        def get_base_audit_class(model):
            """Identify what should be the BASE audit class for a 
            {model}Audit class to inherit from, and return it.
            """
            assert interfaces.IFeatureAudit.implementedBy(model), model
            ti = capi.get_type_info(model)
            if ti.archetype is None:
                # !+ should this be allowed to ever happen? 
                # i.e. require each type to declare an archetype?
                base_audit_class = domain.Audit
            else:
                base_audit_class = get_audit_class_for(ti.archetype)
                if base_audit_class is None:
                    # fallback to get the audit class for the sys archetype
                    base_audit_class = get_audit_class_for(ti.sys_archetype)
                assert base_audit_class is not None, (model, ti.archetype, base_audit_class)
            return base_audit_class
        
        def new_audit_class(model):
            """Create, set on MODEL_MODULE, and map {model}Audit class.
            """
            base_audit_cls = get_base_audit_class(model)
            audit_cls = base_audit_cls.auditFactory(model)
            # set on MODEL_MODULE
            setattr(MODEL_MODULE, audit_cls.__name__, audit_cls)
            # mapper for newly created audit_cls
            mapper(audit_cls,
                inherits=base_audit_cls,
                polymorphic_identity=naming.polymorphic_identity(model)
            )
            log.info("GENERATED new_audit_class %s(%s) for type %s",
                audit_cls, base_audit_cls, model)
            return audit_cls
        
        # domain - audit class
        audit_cls = get_audit_class_for(model)
        if audit_cls is None: 
            audit_cls = new_audit_class(model)
        
        # auditor - head cls
        import bungeni.core.audit
        bungeni.core.audit.set_auditor(model)
        
        # mapper - audit class
        # assumption: audit_cls uses single inheritance only (and not only for 
        # those created dynamically in feature_audit())
        base_audit_cls = audit_cls.__bases__[0]
        assert issubclass(base_audit_cls, domain.Audit), \
            "Audit class %s is not a proper subclass of %s" % (
                audit_cls, domain.Audit)
        
        # extended attributes - propagate any on head cls also to its audit_cls
        for vp_name, vp_type in model.extended_properties:
            mapper_add_relation_vertical_property(
                audit_cls, vp_name, vp_type)
        # !+NOTE: capi.get_type_info(model).descriptor_model is still None

        # model.changes <-> change.audit.audit_head=doc:
        # doc[@TYPE] <-- TYPE_audit <-> audit <-> change
                
        # get head table for kls, and its audit table.
        tbl = utils.get_local_table(model)
        # NOT mapped_table, as when cls_mapper.single=False (e.g. for 
        # the case of the group type) it gves an sa.sql.expression.Join,
        # and not a table object:
        #   principal JOIN "group" ON principal.principal_id = "group".group_id
        audit_tbl = getattr(schema, naming.audit_table_name(tbl.name))
        cls_mapper = class_mapper(model)
        cls_mapper.add_property("changes", relation(domain.Change,
                # join condition, may be determined by a composite primary key
                primaryjoin=sa.and_( *[
                    pk_col == audit_tbl.c.get(pk_col.name)
                    for pk_col in tbl.primary_key ]),
                secondary=audit_tbl,
                secondaryjoin=sa.and_(
                    audit_tbl.c.audit_id == schema.change.c.audit_id,
                ),
                lazy=True,
                order_by=schema.change.c.audit_id.desc(),
                cascade="all",
                passive_deletes=False, # SA default
            ))
Exemple #10
0
def instrument_extended_properties(cls, object_type=None):
    if object_type is None:
        object_type = utils.get_local_table(cls).name
    for vp_name, vp_type in cls.extended_properties:
        setattr(cls, vp_name, vertical_property(object_type, vp_name, vp_type))
        mapper_add_relation_vertical_property(cls, vp_name, vp_type)