Completed
Push — master ( c1aad3...3dbc11 )
by Koen
03:21 queued 02:11
created

QueryBuilder._build_label()   A

Complexity

Conditions 4

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %
Metric Value
cc 4
dl 0
loc 8
rs 9.2
1
# -*- coding: utf8 -*-
2
'''
3
This module contains a few utility functions.
4
'''
5
6
import re
7
8
from pyramid.renderers import JSON
9
10
from skosprovider.skos import (
11
    Concept,
12
    Collection,
13
    Label,
14
    Note,
15
    Source
16
)
17
18
import logging
19
log = logging.getLogger(__name__)
20
21
22
class QueryBuilder:
23
24
    def __init__(self, request, postprocess=False):
25
        self.request = request
26
        self.postprocess = postprocess
27
        self.no_result = False
28
        self.mode = self.request.params.get('mode', 'default')
29
        self.language = self.request.params.get(
30
            'language',
31
            self.request.locale_name
32
        )
33
        self.label = self.request.params.get('label', None)
34
35
    def _build_type(self, query):
36
        type = self.request.params.get('type', None)
37
        if type in ['concept', 'collection']:
38
            query['type'] = type
39
        return query
40
41
    def _build_label(self, query):
42
        if self.label not in [None, '*', '']:
43
            if self.mode == 'dijitFilteringSelect' and '*' in self.label:
44
                self.postprocess = True
45
                query['label'] = self.label.replace('*', '')
46
            else:
47
                query['label'] = self.label
48
        return query
49
50
    def _build_collection(self, query):
51
        coll = self.request.params.get('collection', None)
52
        if coll is not None:
53
            query['collection'] = {'id': coll, 'depth': 'all'}
54
        return query
55
56
    def __call__(self):
57
        if self.mode == 'dijitFilteringSelect' and self.label == '':
58
            self.no_result = True
59
        q = {}
60
        q = self._build_type(q)
61
        q = self._build_label(q)
62
        q = self._build_collection(q)
63
        return q
64
65
66
def parse_range_header(range):
67
    '''
68
    Parse a range header as used by the dojo Json Rest store.
69
70
    :param str range: The content of the range header to be parsed.
71
        eg. `items=0-9`
72
    :returns: A dict with keys start, finish and number or `False` if the
73
        range is invalid.
74
    '''
75
    match = re.match('^items=([0-9]+)-([0-9]+)$', range)
76
    if match:
77
        start = int(match.group(1))
78
        finish = int(match.group(2))
79
        if finish < start:
80
            finish = start
81
        return {
82
            'start': start,
83
            'finish': finish,
84
            'number': finish - start + 1
85
        }
86
    else:
87
        return False
88
89
json_renderer = JSON()
90
91
92
def concept_adapter(obj, request):
93
    '''
94
    Adapter for rendering a :class:`skosprovider.skos.Concept` to json.
95
96
    :param skosprovider.skos.Concept obj: The concept to be rendered.
97
    :rtype: :class:`dict`
98
    '''
99
    p = request.skos_registry.get_provider(obj.concept_scheme.uri)
100
    return {
101
        'id': obj.id,
102
        'type': 'concept',
103
        'uri': obj.uri,
104
        'label': obj.label().label if obj.label() else None,
105
        'concept_scheme': {
106
            'uri': obj.concept_scheme.uri,
107
            'labels': obj.concept_scheme.labels
108
        },
109
        'labels': obj.labels,
110
        'notes': obj.notes,
111
        'sources': obj.sources,
112
        'narrower': _map_relations(obj.narrower, p),
113
        'broader': _map_relations(obj.broader, p),
114
        'related': _map_relations(obj.related, p),
115
        'member_of': _map_relations(obj.member_of, p),
116
        'subordinate_arrays':  _map_relations(obj.subordinate_arrays, p),
117
        'matches': obj.matches
118
    }
119
120
121
def collection_adapter(obj, request):
122
    '''
123
    Adapter for rendering a :class:`skosprovider.skos.Collection` to json.
124
125
    :param skosprovider.skos.Collection obj: The collection to be rendered.
126
    :rtype: :class:`dict`
127
    '''
128
    p = request.skos_registry.get_provider(obj.concept_scheme.uri)
129
    return {
130
        'id': obj.id,
131
        'type': 'collection',
132
        'uri': obj.uri,
133
        'label': obj.label().label if obj.label() else None,
134
        'concept_scheme': {
135
            'uri': obj.concept_scheme.uri,
136
            'labels': obj.concept_scheme.labels
137
        },
138
        'labels': obj.labels,
139
        'notes': obj.notes,
140
        'sources': obj.sources,
141
        'members': _map_relations(obj.members, p),
142
        'member_of': _map_relations(obj.member_of, p),
143
        'superordinates':  _map_relations(obj.superordinates, p),
144
    }
145
146
147
def _map_relations(relations, p):
148
    '''
149
    :param: :class:`list` relations: Relations to be mapped. These are
150
        concept or collection id's.
151
    :param: :class:`skosprovider.providers.VocabularyProvider` p: Provider
152
        to look up id's.
153
    :rtype: :class:`list`
154
    '''
155
    ret = []
156
    for r in relations:
157
        c = p.get_by_id(r)
158
        if c:
159
            ret.append(_map_relation(c))
160
        else:
161
            log.warning(
162
                'A relation references a concept or collection %d in provider %s that can not be found. Please check the integrity of your data.' %
163
                (r, p.get_vocabulary_id())
164
            )
165
    return ret
166
167
168
def _map_relation(c):
169
    """
170
    Map related concept or collection, leaving out the relations.
171
172
    :param c: the concept or collection to map
173
    :rtype: :class:`dict`
174
    """
175
    return {
176
        'id': c.id,
177
        'type': c.type,
178
        'uri': c.uri,
179
        'label': c.label().label if c.label() else None
180
    }
181
182
183
def label_adapter(obj, request):
184
    '''
185
    Adapter for rendering a :class:`skosprovider.skos.Label` to json.
186
187
    :param skosprovider.skos.Label obj: The label to be rendered.
188
    :rtype: :class:`dict`
189
    '''
190
    return {
191
        'label': obj.label,
192
        'type': obj.type,
193
        'language': obj.language
194
    }
195
196
197
def note_adapter(obj, request):
198
    '''
199
    Adapter for rendering a :class:`skosprovider.skos.Note` to json.
200
201
    :param skosprovider.skos.Note obj: The note to be rendered.
202
    :rtype: :class:`dict`
203
    '''
204
    return {
205
        'note': obj.note,
206
        'type': obj.type,
207
        'language': obj.language,
208
        'markup': obj.markup
209
    }
210
211
212
def source_adapter(obj, request):
213
    '''
214
    Adapter for rendering a :class:`skosprovider.skos.Source` to json.
215
216
    :param skosprovider.skos.Source obj: The source to be rendered.
217
    :rtype: :class:`dict`
218
    '''
219
    return {
220
        'citation': obj.citation
221
    }
222
223
224
json_renderer.add_adapter(Concept, concept_adapter)
225
json_renderer.add_adapter(Collection, collection_adapter)
226
json_renderer.add_adapter(Label, label_adapter)
227
json_renderer.add_adapter(Note, note_adapter)
228
json_renderer.add_adapter(Source, source_adapter)
229