Completed
Push — master ( e43325...f31dcf )
by
unknown
01:16
created

AtomFeedManager   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 92
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 92
rs 10
wmc 16

8 Methods

Rating   Name   Duplication   Size   Complexity  
A save_object() 0 9 1
A current_feed() 0 5 2
A get_atom_feed_entry() 0 8 1
A __init__() 0 10 1
A get_sibling() 0 19 4
A archive_feed() 0 10 3
A get_from_archive() 0 12 3
A save_new_feed() 0 7 1
1
# -*- coding: utf-8 -*-
2
from oe_utils.data.data_transfer_objects import ResultDTO
3
import os
4
from sqlalchemy.sql import desc
5
6
7
class DataManager(object):
8
    """
9
    A datamanager base class.
10
    """
11
12
    @staticmethod
13
    def process_ranged_query(query, result_range):
14
        """
15
16
        :param query: the query to be processed
17
        :param result_range: :class: 'oe_utils.range_parser.Range'
18
        :return: :class:`oe_utils.data.data_transfer_objects.ResultDTO`
19
        """
20
        total = query.count()
21
        if result_range is not None:
22
            data = query \
23
                .offset(result_range.start) \
24
                .limit(result_range.get_page_size()) \
25
                .all()
26
        else:
27
            data = query.all()
28
        return ResultDTO(data, total)
29
30
    def __init__(self, session, cls):
31
        """
32
33
        :param session: a db session
34
        :param cls: the class of the objects to manage
35
        :return:
36
        """
37
        self.session = session
38
        self.cls = cls
39
40
    def get_one(self, object_id):
41
        """
42
        Retrieve an object by its object_id
43
44
        :param object_id: the objects id.
45
        :return: the requested object
46
        :raises: :class: NoResultFound when the object could not be found
47
        """
48
        return self.session.query(self.cls).filter_by(id=object_id).one()
49
50
    def get(self, object_id, cls=None):
51
        """
52
        Retrieve an object by its object_id
53
54
        :param: object_id: the objects id.
55
        :param: cls: the objects class, if None use the default class from the datamanager
56
        :return: the requested object or None if not found
57
        """
58
        cls = self.cls if cls is None else cls
59
        return self.session.query(cls).get(object_id)
60
61
    def delete(self, object_id):
62
        """
63
        Delete an object by its id
64
65
        :param object_id: the objects id.
66
        :return: the deleted object
67
        :raises: :class: NoResultFound when the object could not be found
68
        """
69
        obj = self.session.query(self.cls).filter_by(id=object_id).one()
70
        self.session.delete(obj)
71
        return obj
72
73
    def save(self, obj):
74
        """
75
        save an object
76
77
        :param obj: the object
78
        :return: the saved object
79
        """
80
        if obj not in self.session:
81
            self.session.add(obj)
82
        else:
83
            obj = self.session.merge(obj)
84
        self.session.flush()
85
        self.session.refresh(obj)
86
        return obj
87
88
89
class FeedArchiveNotFound(Exception):
90
    pass
91
92
93
class AtomFeedManager(object):
94
    """
95
    A data manager for feeds.
96
    """
97
    def __init__(self, session, feed_repository, feed_model, feedentry_model):
98
        """
99
        :param session: a db session
100
        :param feed_repository: a repository to store the archived feeds
101
        """
102
        self.session = session
103
        self.feed_repository = feed_repository
104
        self.feed_model = feed_model
105
        self.feedentry_model = feedentry_model
106
        self._current_feed = None
107
108
    @property
109
    def current_feed(self):
110
        if self._current_feed is None:
111
            self._current_feed = self.session.query(self.feed_model).order_by(desc(self.feed_model.id)).first()
112
        return self._current_feed
113
114
    def get_sibling(self, feed_id, sibling_type):
115
        """
116
        get a previous/next sibling from a feed
117
        :param feed_id: id of the feed
118
        :param sibling_type: sibling type ('previous', 'next')
119
        :return: the sibling
120
        """
121
        if sibling_type == 'previous':
122
            query = self.session.query(self.feed_model).filter(self.feed_model.id < feed_id)
123
            order_clause = desc(self.feed_model.id)
124
        elif sibling_type == 'next':
125
            query = self.session.query(self.feed_model).filter(self.feed_model.id > feed_id)
126
            order_clause = self.feed_model.id
127
        else:
128
            raise Exception('Unhandled sibling relation type')  # pragma no cover
129
        if query.count() > 0:
130
            return query.order_by(order_clause).first()
131
        else:
132
            return None
133
134
    def save_new_feed(self):
135
        """
136
        Save a new feed object to the db
137
        :return: the saved object
138
        """
139
        obj = self.feed_model()
140
        return self.save_object(obj)
141
142
    def save_object(self, obj):
143
        """
144
        Save an object to the db
145
        :param obj: the object to save
146
        :return: the saved object
147
        """
148
        self.session.add(obj)
149
        self.session.flush()
150
        return obj
151
152
    def get_from_archive(self, feed_id):
153
        """
154
        Retrieves feed that was persisted as .xml file by its id (= filename)
155
        Note: No check on feed validity. file content is assumed correct
156
        :param feed_id:
157
        :return: the atom feed as string
158
        """
159
        file_path = self.feed_repository + '/' + str(feed_id) + '.xml'
160
        if not os.path.isfile(file_path):
161
            raise FeedArchiveNotFound()
162
        with open(file_path, 'r') as rec_file:
163
            return rec_file.read()
164
165
    def get_atom_feed_entry(self, feedentry_id):
166
        """
167
        Get a specific feed entry
168
        :param id: id of the feed entry to retrieve
169
        :return: the feed entry
170
        """
171
        return self.session.query(self.feedentry_model).filter(
172
            self.feedentry_model.id == feedentry_id
173
        ).one()
174
175
    def archive_feed(self, feed_id, feed):
176
        """
177
        Archive a feed
178
        :param feed_id: the feed id of the feed to archive
179
        :param feed: the feed to archive
180
        """
181
        with open(self.feed_repository + '/' + str(feed_id) + '.xml', 'w') as rec_file:
182
            rec_file.write(feed.atom_str(pretty=True))
183
        if feed_id == self.current_feed.id:
184
            self._current_feed = None
185