source: mauRepo/HPFos/trunk/src/HPFos/moles3epb.py @ 8353

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/mauRepo/HPFos/trunk/src/HPFos/moles3epb.py@8353
Revision 8353, 15.3 KB checked in by mnagni, 7 years ago (diff)

Removed the whole migration folder (was from the cedaManager project)

  • Property svn:mime-type set to text/plain
Line 
1'''
2Created on 10 Jan 2012
3
4@author: mnagni
5'''
6from libs.epb import EPB
7from ea_model.ceda_metadatamodel.ceda_observationcollection.ceda_observationcollection import CEDA_ObservationCollection
8from ea_model.ceda_metadatamodel.ceda_observation.ceda_observation import CEDA_Observation
9from ea_model.iso_19115_2006_metadata_corrigendum.reference_system_information.md_identifier import MD_Identifier
10from ea_model.iso_19115_2006_metadata_corrigendum.citation_and_responsible_party_information.ci_citation import CI_Citation
11from ea_model.moles3_4.observationcollection.mo_observationcollection import MO_ObservationCollection
12from ea_model.moles3_4.observation.mo_observation import MO_Observation
13from ea_model.ceda_metadatamodel.ceda_project.ceda_project import CEDA_Project
14from sqlalchemy import Table, Column, ForeignKey, Integer, String
15from sqlalchemy.orm import mapper
16from ea_model.moles3_4.utilities.mo_responsiblepartyinfo import MO_ResponsiblePartyInfo
17from ea_model.moles3_4.utilities.mo_rolevalue import MO_RoleValue
18from sqlalchemy.orm.collections import InstrumentedList
19from ceda_guid import CedaGUID
20from sqlalchemy.orm.util import identity_key
21
22
23class Moles3EPBFactory(EPB):
24   
25    def __init__(self, dbManager):
26        self._dbManager = dbManager
27        self._initCEDA_Customization()   
28       
29
30    def _initCEDA_Customization(self):
31        self._associateCEDA_GUID()
32        #self._initSearchIndexes()       
33       
34    def _associateCEDA_GUID(self):
35        guid_table = Table('ceda_guid', self._dbManager.metadata, \
36                           Column('id', String, primary_key=True), \
37                           Column('ceda_observationcollection', Integer, ForeignKey('ceda_observationcollection.id')),
38                           Column('ceda_observation', Integer, ForeignKey('ceda_observation.id')))
39        mapper(CedaGUID, guid_table)
40        self._dbManager.metadata.create_all()
41
42    def _initSearchIndexes(self):
43        #To Be Done - CHECK IF THE COLUMN ALREADY EXISTS!
44        # We don't want sqlalchemy to know about this column so we add it externally.
45        try:
46            self._dbManager.engine.execute("alter table md_identifier add column code_search_vector tsvector")                 
47
48            # This indexes the tsvector column
49
50            self._dbManager.engine.execute("create index md_identifier_code_search_index on md_identifier using gin(code_search_vector)")
51
52            # This sets up the trigger that keeps the tsvector column up to date.
53            self._dbManager.engine.execute("create trigger md_identifier_code_search_update before update or insert on md_identifier \
54                for each row execute procedure tsvector_update_trigger('code_search_vector', 'pg_catalog.english', code)")                       
55        except Exception as e:
56            pass
57
58    def _getSession(self):
59        if self._dbManager is not None:
60            return self._dbManager.createDbSession()               
61        return None
62       
63    def createEPB(self):
64        return Moles3EPB(self._getSession())
65
66class Moles3EPB(object):
67
68    def __init__(self, session):
69        self._session = session
70       
71    def close(self):
72        return self._session.close()       
73       
74    def getObservationCollections(self):
75        """
76            Checks if a CEDA_Collection contains a given CEDA_Observation.
77            @param obs_coll_id: the CEDA_ObservationColleciton id
78            @param obs_id: the CEDA_Observation id
79            @return: True if the collection contains the given observation, False otherwise 
80        """
81        return self._session.query(CEDA_ObservationCollection).all()               
82       
83    def searchEager(self, clazz, inst_id):
84        return EPB.searchEager(clazz, inst_id)     
85     
86    def persistInstance(self, instance):
87        """
88            Adds a new migration object.
89            @param migrationObj: the migration object to add
90            @param session: an SQLAlchemy Session object. If not None the session IS NOT closed at the exit,
91            If None (default) a new Session is created from the underlying EPB and closed at the exit.
92            @return an updated, session independent, object instance reflecting the new persisted object
93        """     
94        EPB.persistInstance(instance, self._session)
95       
96     
97    def updateCedaObject(self, ceda_object, cols_to_update):
98        """
99            Update and eventually commit a CEDA Object in MOLES3 db.
100            NOTE: only the returned instance will reflect the update!
101            @param ceda_object: the CEDA object to persist
102            @param dict: a dictionary containing the columns to update for the given ceda_object
103            @param session: the external session to use. If None a new session will be open to add and commit the object and then closed at the exit. The object is committed
104            @return: the given instance with the updated attributes.
105        """
106        coll = None
107        try:
108            coll = self._session.merge(ceda_object)
109        except Exception as e:
110            print e
111        if coll != None:       
112            for k,v in cols_to_update.items():
113                if hasattr(coll, k):
114                    val = None
115                    try:
116                        val = self._session.merge(v)
117                    except Exception:
118                        val = v
119                    coll_k = getattr(coll, k)                       
120                    if type(coll_k) == list or type(coll_k) == InstrumentedList:
121                        if  type(val) == list or type(val) == InstrumentedList:
122                            coll_k.extend(val)
123                        else:
124                            if val in coll_k:
125                                break
126                            coll_k.append(val)
127                    else:
128                        setattr(coll, k, val)
129        EPB.persistInstance(coll, self._session)                                 
130
131    def getInstanceFromGUID(self, guid):
132        """
133            Returns a CEDA_Observation or a CEDA_ObservationCollection from their GUID
134            @param guid: the object guid
135            @return: the associated instance or None
136        """
137        ceda_guid = self.search(CedaGUID, guid)
138        if ceda_guid:
139            if ceda_guid.ceda_observation:
140                return self.search(CEDA_Observation, ceda_guid.ceda_observation)
141            elif ceda_guid.ceda_observationcollection:
142                return self.search(CEDA_ObservationCollection, ceda_guid.ceda_observationcollection)
143        return None
144
145    def retrieveGUIDFromInstance(self, instance):
146        """
147            Returns the CedaGUID object associated with the given instance.
148            @param instance: an instance of CEDA_Observation os CEDA_ObservationCollection 
149        """
150        if instance is None:
151            return None
152        if type(instance) == CEDA_ObservationCollection:
153            return self._session.query(CedaGUID).filter(CedaGUID.ceda_observationcollection==instance.id).first()
154        elif type(instance) == CEDA_Observation:
155            return self._session.query(CedaGUID).filter(CedaGUID.ceda_observation==instance.id).first()       
156   
157    def getObservationFromObservationCollection(self, obs_coll_id):
158        """
159            Checks if a CEDA_Collection contains a given CEDA_Observation.
160            @param obs_coll_id: the CEDA_ObservationColleciton id
161            @return: the associated CEDA_Observation 
162        """
163        return self._session.query(CEDA_ObservationCollection, CEDA_Observation).filter(CEDA_ObservationCollection.id==obs_coll_id).all()
164
165    def observationAuthor(self, obs_id):
166        """
167            Lists the CEDA_Observation author.
168            @param obs_id: the CEDA_Observation id           
169            @return: True if the collection contains the given observation, False otherwise 
170        """
171        ret = self._session.query(MO_ResponsiblePartyInfo).join(MO_Observation). \
172            filter(MO_ResponsiblePartyInfo.role == MO_RoleValue.cl_author). \
173            filter(MO_Observation.id == obs_id)       
174        return ret
175
176    def extractObservationByTitleKeywords(self, keywords):
177        """
178            Loooks for CEDA_Observation containing a specific title (observation.identifier.code)
179            @param keywords: a space separated terms string
180            @return: a tuple containing a CEDA_Observation satisfying the queryllection.idenfitier element having the title 
181        """               
182        # search_vector is a ts_vector column. To search for terms, you use the
183        # @@ operator. plainto_tsquery turns a string into a query that can be
184        # used with @@. So this adds a where clause like "WHERE search_vector
185        # @@ plaint_tsquery(<search string>)"
186        q = self._session.query(CEDA_Observation). \
187            join(MO_Observation).join(MO_ObservationCollection.identifier). \
188            filter('md_identifier.code_search_vector @@ to_tsquery(:terms)')
189        # This binds the :terms placeholder to the searchterms string. User input
190        # should always be put into queries this way to prevent SQL injection.
191        q = q.params(terms=keywords)
192        return q
193
194
195    def extractCollectionIdentifierByTitle(self, i_title):
196        """
197            Searches for an MD_Identifier from a CEDA_ObservationCollection contains a specific title (observation.identifier.code)
198            @param i_title: the CEDA_ObservationCollection.identifier.title value to search for
199            @return: a tuple containing a CEDA_ObservationCollection and the CEDA_ObservationCollection.idenfitier element having the title 
200        """
201        return self._session.query(CEDA_ObservationCollection, MD_Identifier). \
202            join(MO_ObservationCollection).join(MO_ObservationCollection.identifier). \
203            join(MD_Identifier.authority).filter(CI_Citation.title.like('%' + i_title + '%'))
204
205    def extractObservationsForProject(self, project):
206        """
207            Searches for the CEDA_Observation associated with a CEDA_Project
208            @param project: a CEDA_Project instance
209            @return: a tuple containing the associated CEDA_Observation 
210        """
211        return self._session.query(CEDA_Observation). \
212            join(CEDA_Observation, MO_Observation.inSupportOf).filter(CEDA_Project.id == project.id)
213
214    def extractProjectObservationCollections(self, project):
215        """
216            Searches for the Observation_Collections associated with a CEDA_Project
217            @param project: a CEDA_Project instance
218            @return: a tuple containing the associated CEDA_ObservationCollection 
219        """
220        mo_obs = self._session.query(MO_Observation).join(CEDA_Project).filter(CEDA_Project.id == project.id).subquery()     
221        obsers = self._session.query(CEDA_Observation).join(mo_obs, CEDA_Observation.id == mo_obs.c.id).one()
222        #print "obsers: " + str(intSession.query(CEDA_Observation).join(mo_obs, CEDA_Observation.id == mo_obs.c.id).count())
223       
224        cos = self._session.query(CEDA_ObservationCollection).all()
225        co = self._session.query(MO_ObservationCollection).join(MO_ObservationCollection.member).filter(MO_ObservationCollection.member.contains(obsers))
226       
227        observations = self._session.query(MO_ObservationCollection).join(CEDA_Observation). \
228            filter(obsers.any(CEDA_Observation.id==obsers.c.id))
229        print "observation:" + str(observations.count())
230        return observations
231
232    def search(self, clazz, inst_key):
233        """
234            Searches a required instance by id
235            @param clazz: the class type to search for
236            @param inst_key: the instance id for which the search is done. If None return all the instances of the type
237            @return the required instance(s)
238        """       
239        if inst_key:
240            ret = EPB.search(clazz, inst_key, self._session)
241        else:
242            ret = EPB.search(clazz, None, self._session).all()
243        return ret
244     
245    def _search(self, clazz, inst_id):
246        return EPB.search(clazz, inst_id, self._session)     
247     
248    def searchSelectiveLoadByInstance(self, instance, attributes):
249        id_key = identity_key(instance=instance)
250        if id_key:
251            return self.searchSelectiveLoad(id_key[0], id_key[1], attributes)
252        return None
253     
254    def searchSelectiveLoad(self, clazz, inst_id, attributes):
255        """
256            Searches a required instance by id loading selectively \
257            the specified fields. The parameter "attributes" is a single string or a list of attributes
258            owned by the instance of "clazz". Furthermore such list may contain
259            also the children of the main attributes. For example "attrs" may look
260            like
261            ['resultAccumulation', 'identifier.authority', 'resultTime.position.dateTime8601.month', \
262                      'relatedParty.party', 'result.source.function', 'permission', \
263                      'geographicExtent', 'phenomenonTime', 'keywords', 'description', \
264                      'inSupportOf.abstract', 'dataLineage']
265            the first parameter refers to the main class so is equivalent to
266            clazz.resultAccumulation
267            the second parameter is equivalent to invoke
268            clazz.identifier.authority
269            As single string "attributes" could be as well just 'identifier.authority'
270            @param clazz: the class type to search for
271            @param inst_id: the instance id for which the search is done
272            @param attributes: a single string or a list of attributes to load
273            @param session: a session to use for the query. By default a new one is created automatically at start and closed at the end
274            @return the required instance             
275        """               
276        ret = EPB.searchSelectiveLoad(clazz, inst_id, attributes, self._session)
277        return ret   
278   
279    def loadAttributes(self, instance, attributes):
280        """
281            Returns the attribute of an instance. The parameter "attributes" is a single string or a list of attributes
282            owned by the instance of "clazz". Furthermore such list may contain
283            also the children of the main attributes. For example "attrs" may look
284            like
285            ['resultAccumulation', 'identifier.authority', 'resultTime.position.dateTime8601.month', \
286                      'relatedParty.party', 'result.source.function', 'permission', \
287                      'geographicExtent', 'phenomenonTime', 'keywords', 'description', \
288                      'inSupportOf.abstract', 'dataLineage']
289            the first parameter refers to the main class so is equivalent to
290            clazz.resultAccumulation
291            the second parameter is equivalent to invoke
292            clazz.identifier.authority
293            As single string "attributes" could be as well just 'identifier.authority'
294            @param instance: an instance containing the appropriate id
295            @param attributes: the attribute value required
296            @param session: the session to use for the operation
297            @return: the given instance filled with the required attributes.                     
298        """
299        instance = self._session.merge(instance)
300        EPB.loadAttributes(instance, attributes, self._session)                 
301        return instance
302
303    def executeNative(self, sqlNative):
304        return EPB.executeNative(sqlNative, self._session) 
Note: See TracBrowser for help on using the repository browser.