Example #1
0
class GroupExtra(vdm.sqlalchemy.RevisionedObjectMixin,
                 vdm.sqlalchemy.StatefulObjectMixin,
                 domain_object.DomainObject):
    pass


meta.mapper(
    GroupExtra,
    group_extra_table,
    properties={
        'group':
        orm.relation(
            group.Group,
            backref=orm.backref(
                '_extras',
                collection_class=orm.collections.attribute_mapped_collection(
                    u'key'),
                cascade='all, delete, delete-orphan',
            ),
        )
    },
    order_by=[group_extra_table.c.group_id, group_extra_table.c.key],
    extension=[
        vdm.sqlalchemy.Revisioner(group_extra_revision_table),
    ],
)

vdm.sqlalchemy.modify_base_object_mapper(GroupExtra, core.Revision, core.State)
GroupExtraRevision = vdm.sqlalchemy.create_object_version(
    meta.mapper, GroupExtra, group_extra_revision_table)

Example #2
0
class RatingValueException(Exception):
    pass

# import here to prevent circular import
import tag

meta.mapper(Package, package_table, properties={
    # delete-orphan on cascade does NOT work!
    # Why? Answer: because of way SQLAlchemy/our code works there are points
    # where PackageTag object is created *and* flushed but does not yet have
    # the package_id set (this cause us other problems ...). Some time later a
    # second commit happens in which the package_id is correctly set.
    # However after first commit PackageTag does not have Package and
    # delete-orphan kicks in to remove it!
    'package_tags':orm.relation(tag.PackageTag, backref='package',
        cascade='all, delete', #, delete-orphan',
        ),
    },
    order_by=package_table.c.name,
    extension=[vdm.sqlalchemy.Revisioner(package_revision_table),
               extension.PluginMapperExtension(),
               ],
    )

vdm.sqlalchemy.modify_base_object_mapper(Package, core.Revision, core.State)
PackageRevision = vdm.sqlalchemy.create_object_version(meta.mapper, Package,
        package_revision_table)

def related_packages(self):
    return [self.continuity]
Example #3
0
class Activity(domain_object.DomainObject):

    def __init__(self, user_id, object_id, revision_id, activity_type,
            data=None):
        self.id = _types.make_uuid()
        self.timestamp = datetime.datetime.now()
        self.user_id = user_id
        self.object_id = object_id
        self.revision_id = revision_id
        self.activity_type = activity_type
        if data is None:
            self.data = {}
        else:
            self.data = data

meta.mapper(Activity, activity_table)

class ActivityDetail(domain_object.DomainObject):

    def __init__(self, activity_id, object_id, object_type, activity_type,
            data=None):
        self.activity_id = activity_id
        self.object_id = object_id
        self.object_type = object_type
        self.activity_type = activity_type
        if data is None:
            self.data = {}
        else:
            self.data = data

meta.mapper(ActivityDetail, activity_detail_table, properties = {
Example #4
0
        else:
            query = sqlalchemy_query
        qstr = '%' + querystr + '%'
        filters = [
            cls.name.ilike(qstr),
            cls.fullname.ilike(qstr),
        ]
        # sysadmins can search on user emails
        import ckan.authz as authz
        if user_name and authz.is_sysadmin(user_name):
            filters.append(cls.email.ilike(qstr))

        query = query.filter(or_(*filters))
        return query

    @classmethod
    def user_ids_for_name_or_id(self, user_list=[]):
        '''
        This function returns a list of ids from an input that can be a list of
        names or ids
        '''
        query = meta.Session.query(self.id)
        query = query.filter(or_(self.name.in_(user_list),
                                 self.id.in_(user_list)))
        return [user.id for user in query.all()]


meta.mapper(User, user_table,
    properties={'password': synonym('_password', map_column=True)},
    order_by=user_table.c.name)
Example #5
0
                    Tag.name == tag_name))
        query = query.autoflush(autoflush)
        return query.one()[0]

    def related_packages(self):
        return [self.package]


meta.mapper(
    Tag,
    tag_table,
    properties={
        'package_tags':
        relation(
            PackageTag,
            backref='tag',
            cascade='all, delete, delete-orphan',
        ),
        'vocabulary':
        relation(vocabulary.Vocabulary, order_by=tag_table.c.name)
    },
    order_by=tag_table.c.name,
)

meta.mapper(
    PackageTag,
    package_tag_table,
    properties={
        'pkg':
        relation(
            _package.Package,
Example #6
0
                if not obj_rev.revision in results:
                    results[obj_rev.revision] = []
                results[obj_rev.revision].append(obj_rev)
        result_list = results.items()
        ourcmp = lambda rev_tuple1, rev_tuple2: \
            cmp(rev_tuple2[0].timestamp, rev_tuple1[0].timestamp)
        return sorted(result_list, cmp=ourcmp)

    def __repr__(self):
        return '<Group %s>' % self.name


meta.mapper(
    Group,
    group_table,
    extension=[
        vdm.sqlalchemy.Revisioner(group_revision_table),
    ],
)

vdm.sqlalchemy.modify_base_object_mapper(Group, core.Revision, core.State)
GroupRevision = vdm.sqlalchemy.create_object_version(meta.mapper, Group,
                                                     group_revision_table)

meta.mapper(
    Member,
    member_table,
    properties={
        'group':
        orm.relation(Group,
                     backref=orm.backref('member_all',
Example #7
0
    @classmethod
    def get_count_not_in_view_types(cls, view_types):
        """Returns the count of ResourceView not in the view types list"""
        query = (
            meta.Session.query(ResourceView.view_type, sa.func.count(ResourceView.id))
            .group_by(ResourceView.view_type)
            .filter(sa.not_(ResourceView.view_type.in_(view_types)))
        )

        return query.all()

    @classmethod
    def delete_not_in_view_types(cls, view_types):
        """Delete the Resource Views not in the received view types list"""
        query = meta.Session.query(ResourceView).filter(sa.not_(ResourceView.view_type.in_(view_types)))

        return query.delete(synchronize_session="fetch")

    @classmethod
    def delete_all(cls, view_types=[]):
        """Delete all Resource Views, or all of a particular type"""
        query = meta.Session.query(ResourceView)

        if view_types:
            query = query.filter(ResourceView.view_type.in_(view_types))

        return query.delete(synchronize_session="fetch")


meta.mapper(ResourceView, resource_view_table)
Example #8
0
    assert isinstance(_domain_object, domain_object.DomainObject)
    if isinstance(_domain_object, _package.Package):
        q = meta.Session.query(PackageRole).filter_by(package=_domain_object)
    elif isinstance(_domain_object, group.Group):
        q = meta.Session.query(GroupRole).filter_by(group=_domain_object)
    else:
        raise NotImplementedError()
    user_roles = q.all()
    for user_role in user_roles:
        meta.Session.delete(user_role)


## ======================================
## Mappers

meta.mapper(RoleAction, role_action_table)

meta.mapper(
    UserObjectRole,
    user_object_role_table,
    polymorphic_on=user_object_role_table.c.context,
    polymorphic_identity=u'user_object',
    properties={
        'user':
        orm.relation(_user.User,
                     backref=orm.backref('roles',
                                         cascade='all, delete, delete-orphan'))
    },
    order_by=[user_object_role_table.c.id],
)
Example #9
0
    meta.metadata,
    Column('id', types.UnicodeText, primary_key=True,
           default=_types.make_uuid),
    Column('user_id', types.UnicodeText, ForeignKey('user.id')),
    Column('user_ip_address',
           types.UnicodeText),  # alternative to user_id if not logged in
    Column('package_id', types.UnicodeText, ForeignKey('package.id')),
    Column('rating', types.Float),
    Column('created', types.DateTime, default=datetime.datetime.now),
)


class Rating(domain_object.DomainObject):
    pass


meta.mapper(
    Rating,
    rating_table,
    properties={
        'user':
        orm.relation(user.User,
                     backref=orm.backref(
                         'ratings', cascade='all, delete, delete-orphan')),
        'package':
        orm.relation(_package.Package,
                     backref=orm.backref(
                         'ratings', cascade='all, delete, delete-orphan')),
    },
)
Example #10
0
vdm.sqlalchemy.make_table_stateful(group_extra_table)
group_extra_revision_table = core.make_revisioned_table(group_extra_table)


class GroupExtra(vdm.sqlalchemy.RevisionedObjectMixin, vdm.sqlalchemy.StatefulObjectMixin, domain_object.DomainObject):
    pass


meta.mapper(
    GroupExtra,
    group_extra_table,
    properties={
        "group": orm.relation(
            group.Group,
            backref=orm.backref(
                "_extras",
                collection_class=orm.collections.attribute_mapped_collection(u"key"),
                cascade="all, delete, delete-orphan",
            ),
        )
    },
    order_by=[group_extra_table.c.group_id, group_extra_table.c.key],
    extension=[vdm.sqlalchemy.Revisioner(group_extra_revision_table)],
)

vdm.sqlalchemy.modify_base_object_mapper(GroupExtra, core.Revision, core.State)
GroupExtraRevision = vdm.sqlalchemy.create_object_version(meta.mapper, GroupExtra, group_extra_revision_table)


def _create_extra(key, value):
    return GroupExtra(key=unicode(key), value=value)
Example #11
0
        res_dict = ckan.lib.dictization.table_dictize(self, context={"model": model})
        return activity.ActivityDetail(activity_id, self.id, u"Resource", activity_type, {"resource": res_dict})


## Mappers

meta.mapper(
    Resource,
    resource_table,
    properties={
        "package": orm.relation(
            Package,
            # all resources including deleted
            # formally package_resources_all
            backref=orm.backref(
                "resources_all",
                collection_class=ordering_list("position"),
                cascade="all, delete",
                order_by=resource_table.c.position,
            ),
        )
    },
    order_by=[resource_table.c.package_id],
    extension=[vdm.sqlalchemy.Revisioner(resource_revision_table), extension.PluginMapperExtension()],
)


## VDM

vdm.sqlalchemy.modify_base_object_mapper(Resource, core.Revision, core.State)
ResourceRevision = vdm.sqlalchemy.create_object_version(meta.mapper, Resource, resource_revision_table)
Example #12
0
__all__ = ['Rating', 'MIN_RATING', 'MAX_RATING']

MIN_RATING = 1.0
MAX_RATING = 5.0


rating_table = Table('rating', meta.metadata,
                     Column('id', types.UnicodeText, primary_key=True, default=_types.make_uuid),
                     Column('user_id', types.UnicodeText, ForeignKey('user.id')),
                     Column('user_ip_address', types.UnicodeText), # alternative to user_id if not logged in
                     Column('package_id', types.UnicodeText, ForeignKey('package.id')),
                     Column('rating', types.Float),
                     Column('created', types.DateTime, default=datetime.datetime.now),
                     )

class Rating(domain_object.DomainObject):
    pass

meta.mapper(Rating, rating_table,
       properties={
            'user': orm.relation(user.User,
                backref=orm.backref('ratings',
                cascade='all, delete, delete-orphan'
                )),
            'package': orm.relation(_package.Package,
                backref=orm.backref('ratings',
                cascade='all, delete, delete-orphan'
                )),
            },
       )
Example #13
0
        )
        if capacity:
            q = q.filter(model.Member.capacity == capacity)
            return q.all()

        if "_groups" not in self.__dict__:
            self._groups = q.all()

        groups = self._groups
        if group_type:
            groups = [g for g in groups if g.type == group_type]
        return groups

    @classmethod
    def search(cls, querystr, sqlalchemy_query=None):
        """Search name, fullname, email and openid. """
        if sqlalchemy_query is None:
            query = meta.Session.query(cls)
        else:
            query = sqlalchemy_query
        qstr = "%" + querystr + "%"
        query = query.filter(
            or_(cls.name.ilike(qstr), cls.fullname.ilike(qstr), cls.openid.ilike(qstr), cls.email.ilike(qstr))
        )
        return query


meta.mapper(
    User, user_table, properties={"password": synonym("_password", map_column=True)}, order_by=user_table.c.name
)
Example #14
0
    def deactivate(self, package):
        related_ds = meta.Session.query(RelatedDataset).\
                          filter(RelatedDataset.dataset_id==package.id).\
                          filter(RelatedDataset.status=='active').first()
        if related_ds:
            related_ds.status = 'inactive'
            meta.Session.commit()


# We have avoided using SQLAlchemy association objects see
# http://bit.ly/sqlalchemy_association_object by only having the
# relation be for 'active' related objects.  For non-active states
# the caller will have to use get_for_dataset() in Related.
meta.mapper(RelatedDataset,
            related_dataset_table,
            properties={
                'related': orm.relation(Related),
                'dataset': orm.relation(_package.Package)
            })
meta.mapper(
    Related,
    related_table,
    properties={
        'datasets':
        orm.relation(
            _package.Package,
            backref=orm.backref('related'),
            secondary=related_dataset_table,
            secondaryjoin=and_(
                related_dataset_table.c.dataset_id == _package.Package.id,
                RelatedDataset.status == 'active'))
    })
Example #15
0
                'ckan.extra_resource_group_fields', '').split()
            for field in cls.extra_columns:
                setattr(cls, field, DictProxy(field, 'extras'))
        return cls.extra_columns

        ## Mappers

meta.mapper(Resource, resource_table, properties={
    'resource_group': orm.relation(
        ResourceGroup,
        # all resources including deleted
        # formally package_resources_all
        backref=orm.backref('resources_all',
                            collection_class=ordering_list('position'),
                            cascade='all, delete',
                            order_by=resource_table.c.position,
                            ),
    )
},
order_by=[resource_table.c.resource_group_id],
extension=[vdm.sqlalchemy.Revisioner(resource_revision_table),
           extension.PluginMapperExtension(),
           ],
)

meta.mapper(ResourceGroup, resource_group_table, properties={
    'package': orm.relation(
        _package.Package,
        # all resources including deleted
        backref=orm.backref('resource_groups_all',
                            cascade='all, delete, delete-orphan',
Example #16
0

user_following_user_table = sqlalchemy.Table('user_following_user',
        meta.metadata,
    sqlalchemy.Column('follower_id', sqlalchemy.types.UnicodeText,
        sqlalchemy.ForeignKey('user.id', onupdate='CASCADE',
            ondelete='CASCADE'),
        primary_key=True, nullable=False),
    sqlalchemy.Column('object_id', sqlalchemy.types.UnicodeText,
        sqlalchemy.ForeignKey('user.id', onupdate='CASCADE',
            ondelete='CASCADE'),
        primary_key=True, nullable=False),
    sqlalchemy.Column('datetime', sqlalchemy.types.DateTime, nullable=False),
)

meta.mapper(UserFollowingUser, user_following_user_table)

class UserFollowingDataset(domain_object.DomainObject):
    '''A many-many relationship between users and datasets (packages).

    A relationship between a user (the follower) and a dataset (the object),
    that means that the user is currently following the dataset.

    '''
    def __init__(self, follower_id, object_id):
        self.follower_id = follower_id
        self.object_id = object_id
        self.datetime = datetime.datetime.now()

    @classmethod
    def get(self, follower_id, object_id):
Example #17
0
        return activity.ActivityDetail(activity_id, self.id, u"Resource",
                                       activity_type,
                                       {'resource': res_dict})



## Mappers

meta.mapper(Resource, resource_table, properties={
    'package': orm.relation(
        Package,
        # all resources including deleted
        # formally package_resources_all
        backref=orm.backref('resources_all',
                            collection_class=ordering_list('position'),
                            cascade='all, delete',
                            order_by=resource_table.c.position,
                            ),
    )
},
extension=[vdm.sqlalchemy.Revisioner(resource_revision_table),
           extension.PluginMapperExtension(),
           ],
)


## VDM

vdm.sqlalchemy.modify_base_object_mapper(Resource, core.Revision, core.State)
ResourceRevision = vdm.sqlalchemy.create_object_version(
    meta.mapper, Resource, resource_revision_table)
Example #18
0
    q = q.filter(AuthorizationGroup.users.contains(user))
    return q.count() == 1

def add_user_to_authorization_group(user, authorization_group, role):
    assert not user_in_authorization_group(user, authorization_group)
    from authz import add_user_to_role
    meta.Session.add(authorization_group)
    authorization_group.users.append(user)
    add_user_to_role(user, role, authorization_group)

def remove_user_from_authorization_group(user, authorization_group):
    assert user_in_authorization_group(user, authorization_group)
    from authz import remove_user_from_role, AuthorizationGroupRole
    meta.Session.add(authorization_group)
    authorization_group.users.remove(user)
    q = meta.Session.query(AuthorizationGroupRole)
    q = q.filter_by(authorization_group=authorization_group,
                    user=user)
    for agr in q:
        remove_user_from_role(user, agr.role, authorization_group)



meta.mapper(AuthorizationGroup, authorization_group_table, properties={
       'users': orm.relation(user.User, lazy=True, secondary=authorization_group_user_table,
                         backref=orm.backref('authorization_groups', lazy=True))
       },
       order_by=authorization_group_table.c.name)

meta.mapper(AuthorizationGroupUser, authorization_group_user_table)
Example #19
0
            activity_type = 'deleted'

        data_dict = ckan.lib.dictization.table_dictize(self,
                context={'model': model})
        return activity.ActivityDetail(activity_id, self.id, u"PackageExtra",
                activity_type, {'package_extra': data_dict})

meta.mapper(PackageExtra, package_extra_table, properties={
    'package': orm.relation(_package.Package,
        backref=orm.backref('_extras',
            collection_class=orm.collections.attribute_mapped_collection(u'key'),
            cascade='all, delete, delete-orphan',
            ),
        ),
    'package_no_state': orm.relation(_package.Package,
        backref=orm.backref('extras_list',
            cascade='all, delete, delete-orphan',
            ),
        )
    },
    order_by=[package_extra_table.c.package_id, package_extra_table.c.key],
    extension=[vdm.sqlalchemy.Revisioner(extra_revision_table),
               extension.PluginMapperExtension(),
               ],
)

vdm.sqlalchemy.modify_base_object_mapper(PackageExtra, core.Revision, core.State)
PackageExtraRevision= vdm.sqlalchemy.create_object_version(meta.mapper, PackageExtra,
        extra_revision_table)

PackageExtraRevision.related_packages = lambda self: [self.continuity.package]
Example #20
0

user_following_user_table = sqlalchemy.Table('user_following_user',
        meta.metadata,
    sqlalchemy.Column('follower_id', sqlalchemy.types.UnicodeText,
        sqlalchemy.ForeignKey('user.id', onupdate='CASCADE',
            ondelete='CASCADE'),
        primary_key=True, nullable=False),
    sqlalchemy.Column('object_id', sqlalchemy.types.UnicodeText,
        sqlalchemy.ForeignKey('user.id', onupdate='CASCADE',
            ondelete='CASCADE'),
        primary_key=True, nullable=False),
    sqlalchemy.Column('datetime', sqlalchemy.types.DateTime, nullable=False),
)

meta.mapper(UserFollowingUser, user_following_user_table)

class UserFollowingDataset(ModelFollowingModel):
    '''A many-many relationship between users and datasets (packages).

    A relationship between a user (the follower) and a dataset (the object),
    that means that the user is currently following the dataset.

    '''
    @classmethod
    def _follower_class(cls):
        return ckan.model.User

    @classmethod
    def _object_class(cls):
        return ckan.model.Package
Example #21
0
        qstr = '%' + querystr + '%'
        filters = [
            cls.name.ilike(qstr),
            cls.fullname.ilike(qstr),
            cls.openid.ilike(qstr),
        ]
        # sysadmins can search on user emails
        import ckan.authz as authz
        if user_name and authz.is_sysadmin(user_name):
            filters.append(cls.email.ilike(qstr))

        query = query.filter(or_(*filters))
        return query

    @classmethod
    def user_ids_for_name_or_id(self, user_list=[]):
        '''
        This function returns a list of ids from an input that can be a list of
        names or ids
        '''
        query = meta.Session.query(self.id)
        query = query.filter(
            or_(self.name.in_(user_list), self.id.in_(user_list)))
        return [user.id for user in query.all()]


meta.mapper(User,
            user_table,
            properties={'password': synonym('_password', map_column=True)},
            order_by=user_table.c.name)
Example #22
0
import sqlalchemy

from meta import Table, Column, UnicodeText, ForeignKey, mapper, metadata

__all__ = ['package_search_table']

def setup_db(event, schema_item, engine):
    sql = 'ALTER TABLE package_search ADD COLUMN search_vector tsvector'
    res = engine.execute(sql)
    res.close()

package_search_table = Table('package_search', metadata,
        Column('package_id', UnicodeText, ForeignKey('package.id'), primary_key=True),
        )

class PackageSearch(object):
    pass
# We need this mapper so that Package can delete orphaned package_search rows
mapper(PackageSearch, package_search_table, properties={})

package_search_table.append_ddl_listener('after-create', setup_db)


Example #23
0
    @classmethod
    def reverse_type(cls, forward_or_reverse_type):
        for fwd, rev in cls.types:
            if fwd == forward_or_reverse_type:
                return rev
            if rev == forward_or_reverse_type:
                return fwd        

    @classmethod
    def make_type_printable(cls, type_):
        for i, types in enumerate(cls.types):
            for j in range(2):
                if type_ == types[j]:
                    return cls.types_printable[i][j]
        raise TypeError, type_

meta.mapper(PackageRelationship, package_relationship_table, properties={
    'subject':orm.relation(_package.Package, primaryjoin=\
           package_relationship_table.c.subject_package_id==_package.Package.id,
           backref='relationships_as_subject'),
    'object':orm.relation(_package.Package, primaryjoin=package_relationship_table.c.object_package_id==_package.Package.id,
           backref='relationships_as_object'),
    },
    extension = [vdm.sqlalchemy.Revisioner(package_relationship_revision_table)]
    )

vdm.sqlalchemy.modify_base_object_mapper(PackageRelationship, core.Revision, core.State)
PackageRelationshipRevision = vdm.sqlalchemy.create_object_version(
    meta.mapper, PackageRelationship, package_relationship_revision_table)
Example #24
0
)


class Dashboard(object):
    '''Saved data used for the user's dashboard.'''

    def __init__(self, user_id):
        self.user_id = user_id
        self.activity_stream_last_viewed = datetime.datetime.utcnow()
        self.email_last_sent = datetime.datetime.utcnow()

    @classmethod
    def get(cls, user_id):
        '''Return the Dashboard object for the given user_id.

        If there's no dashboard row in the database for this user_id, a fresh
        one will be created and returned.

        '''
        query = meta.Session.query(Dashboard)
        query = query.filter(Dashboard.user_id == user_id)
        try:
            row = query.one()
        except sqlalchemy.orm.exc.NoResultFound:
            row = Dashboard(user_id)
            meta.Session.add(row)
            meta.Session.commit()
        return row

meta.mapper(Dashboard, dashboard_table)
Example #25
0
# import here to prevent circular import
import tag

meta.mapper(
    Package,
    package_table,
    properties={
        # delete-orphan on cascade does NOT work!
        # Why? Answer: because of way SQLAlchemy/our code works there are points
        # where PackageTag object is created *and* flushed but does not yet have
        # the package_id set (this cause us other problems ...). Some time later a
        # second commit happens in which the package_id is correctly set.
        # However after first commit PackageTag does not have Package and
        # delete-orphan kicks in to remove it!
        'package_tags':
        orm.relation(
            tag.PackageTag,
            backref='package',
            cascade='all, delete',  #, delete-orphan',
        ),
    },
    order_by=package_table.c.name,
    extension=[
        vdm.sqlalchemy.Revisioner(package_revision_table),
        extension.PluginMapperExtension(),
    ],
)

vdm.sqlalchemy.modify_base_object_mapper(Package, core.Revision, core.State)
PackageRevision = vdm.sqlalchemy.create_object_version(meta.mapper, Package,
                                                       package_revision_table)
Example #26
0
        self.user_id = user_id
        self.activity_stream_last_viewed = datetime.datetime.now()

    @classmethod
    def get_activity_stream_last_viewed(cls, user_id):
        query = meta.Session.query(Dashboard)
        query = query.filter(Dashboard.user_id == user_id)
        try:
            row = query.one()
            return row.activity_stream_last_viewed
        except sqlalchemy.orm.exc.NoResultFound:
            # No dashboard row has been created for this user so they have no
            # activity_stream_last_viewed date. Return the oldest date we can
            # (i.e. all activities are new to this user).
            return datetime.datetime.min

    @classmethod
    def update_activity_stream_last_viewed(cls, user_id):
        query = meta.Session.query(Dashboard)
        query = query.filter(Dashboard.user_id == user_id)
        try:
            row = query.one()
            row.activity_stream_last_viewed = datetime.datetime.now()
        except sqlalchemy.orm.exc.NoResultFound:
            row = Dashboard(user_id)
            meta.Session.add(row)
        meta.Session.commit()


meta.mapper(Dashboard, dashboard_table)
Example #27
0
class Activity(domain_object.DomainObject):
    def __init__(self, user_id, object_id, revision_id, activity_type, data=None):
        self.id = _types.make_uuid()
        self.timestamp = datetime.datetime.now()
        self.user_id = user_id
        self.object_id = object_id
        self.revision_id = revision_id
        self.activity_type = activity_type
        if data is None:
            self.data = {}
        else:
            self.data = data


meta.mapper(Activity, activity_table)


class ActivityDetail(domain_object.DomainObject):
    def __init__(self, activity_id, object_id, object_type, activity_type, data=None):
        self.activity_id = activity_id
        self.object_id = object_id
        self.object_type = object_type
        self.activity_type = activity_type
        if data is None:
            self.data = {}
        else:
            self.data = data

    @classmethod
    def by_activity_id(cls, activity_id):
Example #28
0
    Column('name',
           types.Unicode(VOCABULARY_NAME_MAX_LENGTH),
           nullable=False,
           unique=True),
)


class Vocabulary(domain_object.DomainObject):
    def __init__(self, name):
        self.id = _types.make_uuid()
        self.name = name

    @classmethod
    def get(cls, id_or_name):
        '''Return a Vocabulary object referenced by its id or name, or
        None if there is no vocabulary with the given id or name. '''
        query = meta.Session.query(Vocabulary)
        query = query.filter(Vocabulary.id == id_or_name)
        vocab = query.first()
        if vocab is None:
            vocab = Vocabulary.by_name(id_or_name)
        return vocab

    @property
    def tags(self):
        query = meta.Session.query(tag.Tag)
        return query.filter(tag.Tag.vocabulary_id == self.id)


meta.mapper(Vocabulary, vocabulary_table)
Example #29
0
from meta import Table, Column, UnicodeText, ForeignKey, mapper, metadata

__all__ = ['package_search_table', 'PackageSearch']


def setup_db(event, schema_item, engine):
    sql = 'ALTER TABLE package_search ADD COLUMN search_vector tsvector'
    res = engine.execute(sql)
    res.close()


package_search_table = Table(
    'package_search',
    metadata,
    Column('package_id',
           UnicodeText,
           ForeignKey('package.id'),
           primary_key=True),
)


class PackageSearch(object):
    pass


# We need this mapper so that Package can delete orphaned package_search rows
mapper(PackageSearch, package_search_table, properties={})

package_search_table.append_ddl_listener('after-create', setup_db)
Example #30
0
    @classmethod
    def get_count_not_in_view_types(cls, view_types):
        '''Returns the count of ResourceView not in the view types list'''
        query = meta.Session.query(ResourceView.view_type,
                                   sa.func.count(ResourceView.id)) \
                    .group_by(ResourceView.view_type) \
                    .filter(sa.not_(ResourceView.view_type.in_(view_types)))

        return query.all()

    @classmethod
    def delete_not_in_view_types(cls, view_types):
        '''Delete the Resource Views not in the received view types list'''
        query = meta.Session.query(ResourceView) \
                    .filter(sa.not_(ResourceView.view_type.in_(view_types)))

        return query.delete(synchronize_session='fetch')

    @classmethod
    def delete_all(cls, view_types=[]):
        '''Delete all Resource Views, or all of a particular type'''
        query = meta.Session.query(ResourceView)

        if view_types:
            query = query.filter(ResourceView.view_type.in_(view_types))

        return query.delete(synchronize_session='fetch')


meta.mapper(ResourceView, resource_view_table)
Example #31
0
            obj_revisions = meta.Session.query(rev_class).\
                filter_by(group_id=self.id).all()
            for obj_rev in obj_revisions:
                if not obj_rev.revision in results:
                    results[obj_rev.revision] = []
                results[obj_rev.revision].append(obj_rev)
        result_list = results.items()
        ourcmp = lambda rev_tuple1, rev_tuple2: \
            cmp(rev_tuple2[0].timestamp, rev_tuple1[0].timestamp)
        return sorted(result_list, cmp=ourcmp)

    def __repr__(self):
        return '<Group %s>' % self.name


meta.mapper(Group, group_table,
            extension=[vdm.sqlalchemy.Revisioner(group_revision_table), ], )

vdm.sqlalchemy.modify_base_object_mapper(Group, core.Revision, core.State)
GroupRevision = vdm.sqlalchemy.create_object_version(meta.mapper, Group,
                                                     group_revision_table)

meta.mapper(Member, member_table, properties={
    'group': orm.relation(Group,
                          backref=orm.backref('member_all',
                                              cascade='all, delete-orphan')),
},
    extension=[vdm.sqlalchemy.Revisioner(member_revision_table), ],
)


vdm.sqlalchemy.modify_base_object_mapper(Member, core.Revision, core.State)
Example #32
0
extra_revision_table = \
    core.make_revisioned_table(package_extra_table, frozen=True)


class PackageExtra(
        core.StatefulObjectMixin,
        domain_object.DomainObject):

    def related_packages(self):
        return [self.package]


meta.mapper(PackageExtra, package_extra_table, properties={
    'package': orm.relation(_package.Package,
        backref=orm.backref('_extras',
            collection_class=orm.collections.attribute_mapped_collection(u'key'),
            cascade='all, delete, delete-orphan',
            ),
        ),
    },
    order_by=[package_extra_table.c.package_id, package_extra_table.c.key],
    extension=[extension.PluginMapperExtension()],
)


def _create_extra(key, value):
    return PackageExtra(key=text_type(key), value=value)

_package.Package.extras = association_proxy(
    '_extras', 'value', creator=_create_extra)
Example #33
0
import domain_object

__all__ = ['TaskStatus', 'task_status_table']

task_status_table = Table(
    'task_status', meta.metadata,
    Column('id', types.UnicodeText, primary_key=True,
           default=_types.make_uuid),
    Column('entity_id', types.UnicodeText, nullable=False),
    Column('entity_type', types.UnicodeText, nullable=False),
    Column('task_type', types.UnicodeText, nullable=False),
    Column('key', types.UnicodeText, nullable=False),
    Column('value', types.UnicodeText, nullable=False),
    Column('state', types.UnicodeText), Column('error', types.UnicodeText),
    Column('last_updated', types.DateTime, default=datetime.now),
    UniqueConstraint('entity_id', 'task_type', 'key'))


class TaskStatus(domain_object.DomainObject):
    @classmethod
    def get(cls, reference):
        '''Returns a task status object referenced by its id.'''
        if not reference:
            return None

        task = meta.Session.query(cls).get(reference)
        return task


meta.mapper(TaskStatus, task_status_table)
Example #34
0
    def add_package_by_name(self, package_name):
        if not package_name:
            return
        package = _package.Package.by_name(package_name)
        assert package
        if not package in self.packages():
            member = Member(group=self,
                            table_id=package.id,
                            table_name='package')
            meta.Session.add(member)

    def __repr__(self):
        return '<Group %s>' % self.name


meta.mapper(Group, group_table)

meta.mapper(Member,
            member_table,
            properties={
                'group':
                orm.relation(Group,
                             backref=orm.backref(
                                 'member_all', cascade='all, delete-orphan')),
            })

# Should there arise a bug that allows loops in the group hierarchy, then it
# will lead to infinite recursion, tieing up postgres processes at 100%, and
# the server will suffer. To avoid ever failing this badly, we put in this
# limit on recursion.
MAX_RECURSES = 8
Example #35
0
import meta
import types as _types
import domain_object

__all__ = ['TaskStatus', 'task_status_table']

task_status_table = Table('task_status', meta.metadata,
    Column('id', types.UnicodeText, primary_key=True, default=_types.make_uuid),
    Column('entity_id', types.UnicodeText, nullable=False),
    Column('entity_type', types.UnicodeText, nullable=False),
    Column('task_type', types.UnicodeText, nullable=False),
    Column('key', types.UnicodeText, nullable=False),
    Column('value', types.UnicodeText, nullable=False),
    Column('state', types.UnicodeText),
    Column('error', types.UnicodeText),
    Column('last_updated', types.DateTime, default=datetime.now),
    UniqueConstraint('entity_id', 'task_type', 'key')
)

class TaskStatus(domain_object.DomainObject):
    @classmethod
    def get(cls, reference):
        '''Returns a task status object referenced by its id.'''
        if not reference:
            return None

        task = meta.Session.query(cls).get(reference)
        return task

meta.mapper(TaskStatus, task_status_table)
Example #36
0
        """
        query = meta.Session.query(RelatedDataset).\
                filter(RelatedDataset.dataset_id==package.id).\
                filter(RelatedDataset.status==status).all()
        return query

    def deactivate(self, package):
        related_ds = meta.Session.query(RelatedDataset).\
                          filter(RelatedDataset.dataset_id==package.id).\
                          filter(RelatedDataset.status=='active').first()
        if related_ds:
            related_ds.status = 'inactive'
            meta.Session.commit()


# We have avoided using SQLAlchemy association objects see
# http://bit.ly/sqlalchemy_association_object by only having the
# relation be for 'active' related objects.  For non-active states
# the caller will have to use get_for_dataset() in Related.
meta.mapper(RelatedDataset, related_dataset_table, properties={
    'related': orm.relation(Related),
    'dataset': orm.relation(_package.Package)
})
meta.mapper(Related, related_table, properties={
'datasets': orm.relation(_package.Package,
    backref=orm.backref('related'),
    secondary=related_dataset_table,
    secondaryjoin=and_(related_dataset_table.c.dataset_id==_package.Package.id,
                          RelatedDataset.status=='active'))
})
Example #37
0
                    .filter(Tag.name==tag_name))
        else:
            query = (meta.Session.query(PackageTag)
                    .filter(_package.Package.name==package_name)
                    .filter(Tag.name==tag_name))
        query = query.autoflush(autoflush)
        return query.one()[0]

    def related_packages(self):
        return [self.package]

meta.mapper(Tag, tag_table, properties={
    'package_tags': relation(PackageTag, backref='tag',
        cascade='all, delete, delete-orphan',
        ),
    'vocabulary': relation(vocabulary.Vocabulary,
        order_by=tag_table.c.name)
    },
    order_by=tag_table.c.name,
    )

meta.mapper(PackageTag, package_tag_table, properties={
    'pkg':relation(_package.Package, backref='package_tag_all',
        cascade='none',
        )
    },
    order_by=package_tag_table.c.id,
    extension=[vdm.sqlalchemy.Revisioner(package_tag_revision_table),
               _extension.PluginMapperExtension(),
               ],
    )
Example #38
0
    Column('value', types.UnicodeText),
    Column('state', types.UnicodeText, default=core.State.ACTIVE),
)

# Define the group_extra_revision table, but no need to map it, as it is only
# used by migrate_package_activity.py
group_extra_revision_table = \
    core.make_revisioned_table(group_extra_table, frozen=True)


class GroupExtra(core.StatefulObjectMixin,
                 domain_object.DomainObject):
    pass

meta.mapper(GroupExtra, group_extra_table, properties={
    'group': orm.relation(group.Group,
        backref=orm.backref('_extras',
            collection_class=orm.collections.attribute_mapped_collection(u'key'),
            cascade='all, delete, delete-orphan',
            ),
        )
    },
    order_by=[group_extra_table.c.group_id, group_extra_table.c.key],
)

def _create_extra(key, value):
    return GroupExtra(key=text_type(key), value=value)

group.Group.extras = association_proxy(
    '_extras', 'value', creator=_create_extra)
Example #39
0
    assert isinstance(_domain_object, domain_object.DomainObject)
    if isinstance(_domain_object, _package.Package):
        q = meta.Session.query(PackageRole).filter_by(package=_domain_object)
    elif isinstance(_domain_object, group.Group):
        q = meta.Session.query(GroupRole).filter_by(group=_domain_object)
    else:
        raise NotImplementedError()
    user_roles = q.all()
    for user_role in user_roles:
        meta.Session.delete(user_role)


## ======================================
## Mappers

meta.mapper(RoleAction, role_action_table)
       
meta.mapper(UserObjectRole, user_object_role_table,
    polymorphic_on=user_object_role_table.c.context,
    polymorphic_identity=u'user_object',
    properties={
        'user': orm.relation(_user.User,
            backref=orm.backref('roles',
                cascade='all, delete, delete-orphan'
            )
        ),
        'authorized_group': orm.relation(auth_group.AuthorizationGroup,
            backref=orm.backref('authorized_roles',
                cascade='all, delete, delete-orphan'
            )
        )
Example #40
0
system_info_revision_table = core.make_revisioned_table(system_info_table)


class SystemInfo(vdm.sqlalchemy.RevisionedObjectMixin,
                 core.StatefulObjectMixin, domain_object.DomainObject):
    def __init__(self, key, value):

        super(SystemInfo, self).__init__()

        self.key = key
        self.value = text_type(value)


meta.mapper(SystemInfo,
            system_info_table,
            extension=[
                vdm.sqlalchemy.Revisioner(system_info_revision_table),
            ])

vdm.sqlalchemy.modify_base_object_mapper(SystemInfo, core.Revision, core.State)
SystemInfoRevision = vdm.sqlalchemy.create_object_version(
    meta.mapper, SystemInfo, system_info_revision_table)


def get_system_info(key, default=None):
    ''' get data from system_info table '''
    from sqlalchemy.exc import ProgrammingError
    try:
        obj = meta.Session.query(SystemInfo).filter_by(key=key).first()
        if obj:
            return obj.value
Example #41
0
    Column('count', types.Integer, nullable=False),
    Column('running_total', types.Integer, nullable=False),
    Column('recent_views', types.Integer, nullable=False),
    Column('tracking_date', types.DateTime),
)


class TrackingSummary(domain_object.DomainObject):
    @classmethod
    def get_for_package(cls, package_id):
        obj = meta.Session.query(cls).autoflush(False)
        obj = obj.filter_by(package_id=package_id)
        if meta.Session.query(obj.exists()).scalar():
            data = obj.order_by(text('tracking_date desc')).first()
            return {'total': data.running_total, 'recent': data.recent_views}

        return {'total': 0, 'recent': 0}

    @classmethod
    def get_for_resource(cls, url):
        obj = meta.Session.query(cls).autoflush(False)
        data = obj.filter_by(url=url).order_by(
            text('tracking_date desc')).first()
        if data:
            return {'total': data.running_total, 'recent': data.recent_views}

        return {'total': 0, 'recent': 0}


meta.mapper(TrackingSummary, tracking_summary_table)
Example #42
0
        Column('id', types.Integer(),  primary_key=True, nullable=False),
        Column('key', types.Unicode(100), unique=True, nullable=False),
        Column('value', types.UnicodeText),
    )

system_info_revision_table = core.make_revisioned_table(system_info_table)


class SystemInfo(domain_object.DomainObject):

    def __init__(self, key, value):
        self.key = key
        self.value = unicode(value)


meta.mapper(SystemInfo, system_info_table)


def get_system_info(key, default=None):
    ''' get data from system_info table '''
    obj = meta.Session.query(SystemInfo).filter_by(key=key).first()
    if obj:
        return obj.value
    else:
        return default


def delete_system_info(key, default=None):
    ''' delete data from system_info table '''
    obj = meta.Session.query(SystemInfo).filter_by(key=key).first()
    if obj:
Example #43
0
        ## Mappers


meta.mapper(
    Resource,
    resource_table,
    properties={
        'resource_group':
        orm.relation(
            ResourceGroup,
            # all resources including deleted
            # formally package_resources_all
            backref=orm.backref(
                'resources_all',
                collection_class=ordering_list('position'),
                cascade='all, delete',
                order_by=resource_table.c.position,
            ),
        )
    },
    order_by=[resource_table.c.resource_group_id],
    extension=[
        vdm.sqlalchemy.Revisioner(resource_revision_table),
        extension.PluginMapperExtension(),
    ],
)

meta.mapper(
    ResourceGroup,
    resource_group_table,
Example #44
0
        return activity.ActivityDetail(activity_id, self.id, u"Resource",
                                       activity_type,
                                       {'resource': res_dict})



## Mappers

meta.mapper(Resource, resource_table, properties={
    'package': orm.relation(
        Package,
        # all resources including deleted
        # formally package_resources_all
        backref=orm.backref('resources_all',
                            collection_class=ordering_list('position'),
                            cascade='all, delete',
                            order_by=resource_table.c.position,
                            ),
    )
},
extension=[vdm.sqlalchemy.Revisioner(resource_revision_table),
           extension.PluginMapperExtension(),
           ],
)


## VDM

vdm.sqlalchemy.modify_base_object_mapper(Resource, core.Revision, core.State)
ResourceRevision = vdm.sqlalchemy.create_object_version(
    meta.mapper, Resource, resource_revision_table)
Example #45
0

class SystemInfo(vdm.sqlalchemy.RevisionedObjectMixin,
                 vdm.sqlalchemy.StatefulObjectMixin,
                 domain_object.DomainObject):

    def __init__(self, key, value):

        super(SystemInfo, self).__init__()

        self.key = key
        self.value = unicode(value)


meta.mapper(SystemInfo, system_info_table,
            extension=[
                vdm.sqlalchemy.Revisioner(system_info_revision_table),
                ])

vdm.sqlalchemy.modify_base_object_mapper(SystemInfo, core.Revision, core.State)
SystemInfoRevision = vdm.sqlalchemy.create_object_version(meta.mapper,
                                                          SystemInfo,
                                                          system_info_revision_table)


def get_system_info(key, default=None):
    ''' get data from system_info table '''
    from sqlalchemy.exc import ProgrammingError
    try:
        obj = meta.Session.query(SystemInfo).filter_by(key=key).first()
        if obj:
            return obj.value
Example #46
0
        self.timestamp = datetime.datetime.utcnow()
        self.user_id = user_id
        self.last_run = None
        self.search_string = search_string
        self.last_results = []


saved_search_table = Table(
    'saved_search', meta.metadata,
    Column('id', types.UnicodeText, primary_key=True,
           default=_types.make_uuid), Column('timestamp', types.DateTime),
    Column('user_id', types.UnicodeText), Column('last_run', types.DateTime),
    Column('search_string', types.UnicodeText),
    Column('last_results', ARRAY(TEXT)))

meta.mapper(SavedSearch, saved_search_table)


def _make_parameters(query_string):
    parts = query_string.split("&")
    res = {}
    for part in parts:
        s = part.split("=")
        if len(s) > 1:
            res[s[0]] = s[1]
    return res


def user_saved_searches_list(user_id):
    '''Return an SQLAlchemy query for all saved searches from user_id.'''
    import ckan.model as model
Example #47
0
meta.mapper(
    PackageExtra,
    package_extra_table,
    properties={
        'package':
        orm.relation(
            _package.Package,
            backref=orm.backref(
                '_extras',
                collection_class=orm.collections.attribute_mapped_collection(
                    u'key'),
                cascade='all, delete, delete-orphan',
            ),
        ),
        'package_no_state':
        orm.relation(
            _package.Package,
            backref=orm.backref(
                'extras_list',
                cascade='all, delete, delete-orphan',
            ),
        )
    },
    order_by=[package_extra_table.c.package_id, package_extra_table.c.key],
    extension=[
        vdm.sqlalchemy.Revisioner(extra_revision_table),
        extension.PluginMapperExtension(),
    ],
)
Example #48
0
    @classmethod
    def forward_to_reverse_type(cls, forward_type):
        for fwd, rev in cls.types:
            if fwd == forward_type:
                return rev

    @classmethod
    def reverse_type(cls, forward_or_reverse_type):
        for fwd, rev in cls.types:
            if fwd == forward_or_reverse_type:
                return rev
            if rev == forward_or_reverse_type:
                return fwd

    @classmethod
    def make_type_printable(cls, type_):
        for i, types in enumerate(cls.types):
            for j in range(2):
                if type_ == types[j]:
                    return cls.types_printable[i][j]
        raise TypeError(type_)

meta.mapper(PackageRelationship, package_relationship_table, properties={
    'subject':orm.relation(_package.Package, primaryjoin=\
           package_relationship_table.c.subject_package_id==_package.Package.id,
           backref='relationships_as_subject'),
    'object':orm.relation(_package.Package, primaryjoin=package_relationship_table.c.object_package_id==_package.Package.id,
           backref='relationships_as_object'),
    })
Example #49
0
                 revision_id,
                 activity_type,
                 data=None):
        self.id = _types.make_uuid()
        self.timestamp = datetime.datetime.now()
        self.user_id = user_id
        self.object_id = object_id
        self.revision_id = revision_id
        self.activity_type = activity_type
        if data is None:
            self.data = {}
        else:
            self.data = data


meta.mapper(Activity, activity_table)


class ActivityDetail(domain_object.DomainObject):
    def __init__(self,
                 activity_id,
                 object_id,
                 object_type,
                 activity_type,
                 data=None):
        self.activity_id = activity_id
        self.object_id = object_id
        self.object_type = object_type
        self.activity_type = activity_type
        if data is None:
            self.data = {}
Example #50
0
__all__ = ["Rating", "MIN_RATING", "MAX_RATING"]

MIN_RATING = 1.0
MAX_RATING = 5.0


rating_table = Table(
    "rating",
    meta.metadata,
    Column("id", types.UnicodeText, primary_key=True, default=_types.make_uuid),
    Column("user_id", types.UnicodeText, ForeignKey("user.id")),
    Column("user_ip_address", types.UnicodeText),  # alternative to user_id if not logged in
    Column("package_id", types.UnicodeText, ForeignKey("package.id")),
    Column("rating", types.Float),
    Column("created", types.DateTime, default=datetime.datetime.now),
)


class Rating(domain_object.DomainObject):
    pass


meta.mapper(
    Rating,
    rating_table,
    properties={
        "user": orm.relation(user.User, backref=orm.backref("ratings", cascade="all, delete, delete-orphan")),
        "package": orm.relation(_package.Package, backref=orm.backref("ratings", cascade="all, delete, delete-orphan")),
    },
)
Example #51
0
    "vocabulary",
    meta.metadata,
    Column("id", types.UnicodeText, primary_key=True, default=_types.make_uuid),
    Column("name", types.Unicode(VOCABULARY_NAME_MAX_LENGTH), nullable=False, unique=True),
)


class Vocabulary(domain_object.DomainObject):
    def __init__(self, name):
        self.id = _types.make_uuid()
        self.name = name

    @classmethod
    def get(cls, id_or_name):
        """Return a Vocabulary object referenced by its id or name, or
        None if there is no vocabulary with the given id or name. """
        query = meta.Session.query(Vocabulary)
        query = query.filter(Vocabulary.id == id_or_name)
        vocab = query.first()
        if vocab is None:
            vocab = Vocabulary.by_name(id_or_name)
        return vocab

    @property
    def tags(self):
        query = meta.Session.query(tag.Tag)
        return query.filter(tag.Tag.vocabulary_id == self.id)


meta.mapper(Vocabulary, vocabulary_table)
Example #52
0
    Column('state', types.UnicodeText, default=core.State.ACTIVE),
)


class SystemInfo(core.StatefulObjectMixin,
                 domain_object.DomainObject):

    def __init__(self, key, value):

        super(SystemInfo, self).__init__()

        self.key = key
        self.value = text_type(value)


meta.mapper(SystemInfo, system_info_table)


def get_system_info(key, default=None):
    ''' get data from system_info table '''
    from sqlalchemy.exc import ProgrammingError
    try:
        obj = meta.Session.query(SystemInfo).filter_by(key=key).first()
        if obj:
            return obj.value
    except ProgrammingError:
        meta.Session.rollback()
    return default


Example #53
0
        Column('running_total', types.Integer, nullable=False),
        Column('recent_views', types.Integer, nullable=False),
        Column('tracking_date', types.DateTime),
    )

class TrackingSummary(domain_object.DomainObject):

    @classmethod
    def get_for_package(cls, package_id):
        obj = meta.Session.query(cls).autoflush(False)
        obj = obj.filter_by(package_id=package_id)
        data = obj.order_by('tracking_date desc').first()
        if data:
            return {'total' : data.running_total,
                    'recent': data.recent_views}

        return {'total' : 0, 'recent' : 0}


    @classmethod
    def get_for_resource(cls, url):
        obj = meta.Session.query(cls).autoflush(False)
        data = obj.filter_by(url=url).order_by('tracking_date desc').first()
        if data:
            return {'total' : data.running_total,
                    'recent': data.recent_views}

        return {'total' : 0, 'recent' : 0}

meta.mapper(TrackingSummary, tracking_summary_table)
Example #54
0
        for class_ in [Member, GroupExtra]:
            rev_class = class_.__revision_class__
            obj_revisions = meta.Session.query(rev_class).filter_by(group_id=self.id).all()
            for obj_rev in obj_revisions:
                if not obj_rev.revision in results:
                    results[obj_rev.revision] = []
                results[obj_rev.revision].append(obj_rev)
        result_list = results.items()
        ourcmp = lambda rev_tuple1, rev_tuple2: cmp(rev_tuple2[0].timestamp, rev_tuple1[0].timestamp)
        return sorted(result_list, cmp=ourcmp)

    def __repr__(self):
        return "<Group %s>" % self.name


meta.mapper(Group, group_table, extension=[vdm.sqlalchemy.Revisioner(group_revision_table)])

vdm.sqlalchemy.modify_base_object_mapper(Group, core.Revision, core.State)
GroupRevision = vdm.sqlalchemy.create_object_version(meta.mapper, Group, group_revision_table)

meta.mapper(
    Member,
    member_table,
    properties={"group": orm.relation(Group, backref=orm.backref("member_all", cascade="all, delete-orphan"))},
    extension=[vdm.sqlalchemy.Revisioner(member_revision_table)],
)


vdm.sqlalchemy.modify_base_object_mapper(Member, core.Revision, core.State)
MemberRevision = vdm.sqlalchemy.create_object_version(meta.mapper, Member, member_revision_table)