Completed
Push — master ( e4617d...4b6b67 )
by Jasper
10s
created

MongoRepository.search()   A

Complexity

Conditions 3

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
dl 0
loc 7
rs 9.4285
c 1
b 0
f 0
1
import pymongo, copy, bson
2
from datetime import timedelta
3
from niprov.dependencies import Dependencies
4
5
6
class MongoRepository(object):
7
8
    def __init__(self, dependencies=Dependencies()):
9
        self.config = dependencies.getConfiguration()
10
        self.factory = dependencies.getFileFactory()
11
        self.pictures = dependencies.getPictureCache()
12
        self.listener = dependencies.getListener()
13
        client = pymongo.MongoClient(self.config.database_url)
14
        self.db = client.get_default_database()
15
16
    def byLocation(self, locationString):
17
        """Get the provenance for a file at the given location. 
18
19
        In the case of a dicom series, this returns the provenance for the 
20
        series.
21
22
        Args:
23
            locationString (str): Location of the image file.
24
25
        Returns:
26
            dict: Provenance for one image file.
27
        """
28
        record = self.db.provenance.find_one({'location':locationString})
29
        if record is None:
30
            self.listener.unknownFile(locationString)
31
            return
32
        return self.inflate(record)
33
34
    def byLocations(self, listOfLocations):
35
        records = self.db.provenance.find({'location':{'$in':listOfLocations}})
36
        return [self.inflate(record) for record in records]
37
38
    def knowsByLocation(self, locationString):
39
        """Whether the file at this location has provenance associated with it.
40
41
        Returns:
42
            bool: True if provenance is available for that path.
43
        """
44
        return self.db.provenance.find_one(
45
            {'location':locationString}) is not None
46
47
    def knows(self, image):
48
        """Whether this file has provenance associated with it.
49
50
        Returns:
51
            bool: True if provenance is available for this image.
52
        """
53
        return self.knowsByLocation(image.location.toString())
54
55
    def getSeries(self, image):
56
        """Get the object that carries provenance for the series that the image 
57
        passed is in. 
58
59
        Args:
60
            image (:class:`.DicomFile`): File that is part of a series.
61
62
        Returns:
63
            :class:`.DicomFile`: Image object that caries provenance for 
64
                         the series.
65
        """
66
        seriesUid = image.getSeriesId()
67
        record = self.db.provenance.find_one({'seriesuid':seriesUid})
68
        if record is None:
69
            self.listener.unknownFile('seriesuid: '+str(seriesUid))
70
            return
71
        return self.inflate(record)
72
73
    def knowsSeries(self, image):
74
        """Whether this file is part of a series for which provenance 
75
        is available.
76
77
        Args:
78
            image (:class:`.BaseFile`): File for which the series is sought.
79
80
        Returns:
81
            bool: True if provenance is available for this series.
82
        """
83
        seriesUid = image.getSeriesId()
84
        if seriesUid is None:
85
            return False
86
        return self.db.provenance.find_one({'seriesuid':seriesUid}) is not None
87
88
    def add(self, image):
89
        """Add the provenance for one file to storage.
90
91
        Args:
92
            image (:class:`.BaseFile`): Image file to store.
93
        """
94
        self.db.provenance.insert_one(self.deflate(image))
95
96
    def update(self, image):
97
        """Save changed provenance for this file..
98
99
        Args:
100
            image (:class:`.BaseFile`): Image file that has changed.
101
        """
102
        self.db.provenance.update({'location':image.location.toString()}, 
103
            self.deflate(image))
104
105
    def updateApproval(self, locationString, approvalStatus):
106
        self.db.provenance.update({'location':locationString}, 
107
            {'$set': {'approval': approvalStatus}})
108
109
    def all(self):
110
        """Retrieve all known provenance from storage.
111
112
        Returns:
113
            list: List of provenance for known files.
114
        """
115
        records = self.db.provenance.find()
116
        return [self.inflate(record) for record in records]
117
118
    def latest(self):
119
        records = self.db.provenance.find().sort('added', -1).limit(20)
120
        return [self.inflate(record) for record in records]
121
122
    def statistics(self):
123
        grps = self.db.provenance.aggregate(
124
           [{'$group':
125
                 {
126
                   '_id': None,
127
                   'totalsize': { '$sum': '$size' },
128
                   'count': { '$sum': 1 }
129
                 }
130
            }])
131
        groups = list(grps)
132
        if len(list(groups)) == 0:
133
            return {'count':0}
134
        return list(groups)[0]
135
136
    def byId(self, uid):
137
        record = self.db.provenance.find_one({'id':uid})
138
        if record is None:
139
            self.listener.unknownFile('id: '+str(uid))
140
            return
141
        return self.inflate(record)
142
143
    def byParents(self, listOfParentLocations):
144
        records = self.db.provenance.find({'parents':{
145
            '$in':listOfParentLocations}})
146
        return [self.inflate(record) for record in records]
147
148
    def inquire(self, query):
149
        field = query.getFields()[0]
150
        records = self.db.provenance.find({field.name:field.value})
151
        return [self.inflate(record) for record in records]
152
153
    def search(self, text):
154
        searchfields = ['location','user','subject','project','protocol',
155
                  'transformation','technique','modality']
156
        indexspec = [(field, pymongo.TEXT) for field in searchfields]
157
        self.db.provenance.create_index(indexspec)
158
        records = self.db.provenance.find({'$text':{'$search': text}})
159
        return [self.inflate(record) for record in records]
160
161
    def deflate(self, img):
162
        record = copy.deepcopy(img.provenance)
163
        if 'duration' in record:
164
            record['duration'] = record['duration'].total_seconds()
165
        snapshotData = self.pictures.getBytes(for_=img)
166
        if snapshotData:
167
            record['_snapshot-data'] = bson.Binary(snapshotData)
168
        return record
169
170
    def inflate(self, record):
171
        if 'duration' in record:
172
            record['duration'] = timedelta(seconds=record['duration'])
173
        img = self.factory.fromProvenance(record)
174
        if '_snapshot-data' in record:
175
            self.pictures.keep(record['_snapshot-data'], for_=img)
176
        return img
177
178