source: mauRepo/MolesManager/trunk/src/libs/epb.py @ 8358

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/mauRepo/MolesManager/trunk/src/libs/epb.py@8358
Revision 8358, 8.6 KB checked in by mnagni, 7 years ago (diff)

Major refactoring about migration (now handles better create/update, even if the single updates have to be quite fully implemented)
Added the connection pool from SQLAlchemy

Line 
1'''
2BSD Licence
3Copyright (c) 2012, Science & Technology Facilities Council (STFC)
4All rights reserved.
5
6Redistribution and use in source and binary forms, with or without modification,
7are permitted provided that the following conditions are met:
8
9    * Redistributions of source code must retain the above copyright notice,
10        this list of conditions and the following disclaimer.
11    * Redistributions in binary form must reproduce the above copyright notice,
12        this list of conditions and the following disclaimer in the documentation
13        and/or other materials provided with the distribution.
14    * Neither the name of the Science & Technology Facilities Council (STFC)
15        nor the names of its contributors may be used to endorse or promote
16        products derived from this software without specific prior written permission.
17
18THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
22BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
23OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29Created on 10 Jan 2012
30
31@author: Maurizio Nagni
32'''
33from sqlalchemy.orm import subqueryload
34from sqlalchemy.sql.expression import text
35from sqlalchemy.orm.util import identity_key
36
37class EPB(object):
38
39    @classmethod
40    def buildFilter(self, key, keyValue):
41        try:
42            return '%s = \'%s\'' % (key, keyValue)
43        except RuntimeError as er:
44            print er
45
46    @classmethod
47    def search(self, clazz, inst_key, session):
48        """
49            Searches a required instance by id
50            @param clazz: the class type to search for
51            @param inst_key: the instance id for which the search is done. If None return a query object
52            @param session: a session to use for the query
53            @return the required instance
54        """
55        if inst_key:
56            res = session.query(clazz).get(inst_key)
57        else:
58            res = session.query(clazz)
59           
60        if res is None:
61            return None
62        return res           
63       
64
65
66    @classmethod
67    def searchEager(self, clazz, inst_id, session):
68        """
69            Searches a required instance by id loading eagerly ALL its field. Please use carefully because \
70            it could impact the performance
71            @param clazz: the class type to search for
72            @param inst_id: the instance id for which the search is done
73            @param session: a session to use for the query   
74            @return the required instance                   
75        """
76        res = session.query(clazz).options(subqueryload('*')).get(inst_id)
77        if res is None:
78            return None
79           
80        return res
81
82    @classmethod
83    def searchSelectiveLoad(self, clazz, inst_id, attrs, session):
84        """
85            Searches a required instance by id loading \
86            the specified fields. The parameter "attrs" is a single string or a list of attributes
87            owned by the instance of "clazz". Furthermore such list may contain
88            also the children of the main attributes. For example "attrs" may look
89            like
90            ['resultAccumulation', 'identifier.authority', 'resultTime.position.dateTime8601.month', \
91                      'relatedParty.party', 'result.source.function', 'permission', \
92                      'geographicExtent', 'phenomenonTime', 'keywords', 'description', \
93                      'inSupportOf.abstract', 'dataLineage']
94            the first parameter refers to the main class so is equivalent to
95            clazz.resultAccumulation
96            the second parameter is equivalent to invoke
97            clazz.identifier.authority
98            As single string "attrs" could be as well just 'identifier.authority'
99            @param clazz: the class type to search for
100            @param inst_id: the instance id for which the search is done
101            @param attrs: a single string or a list of attributes to load
102            @param session: a session to use for the query
103            @return the required instance             
104        """         
105        if session is None:
106            raise Exception("Session is None!")       
107        res = EPB.search(clazz, inst_id, session)
108        if res is None:
109            return None
110        self._drillData(res, attrs)
111        return res
112
113    @classmethod
114    def loadAttributes(self, instance, attributes, session):
115        """
116            Loads the given instance with the required attributes.
117            The parameter "attributes" is a single string or a list of attributes
118            owned by the instance of "clazz". Furthermore such list may contain
119            also the children of the main attributes. For example "attrs" may look
120            like
121            ['resultAccumulation', 'identifier.authority', 'resultTime.position.dateTime8601.month', \
122                      'relatedParty.party', 'result.source.function', 'permission', \
123                      'geographicExtent', 'phenomenonTime', 'keywords', 'description', \
124                      'inSupportOf.abstract', 'dataLineage']
125            the first parameter refers to the main class so is equivalent to
126            clazz.resultAccumulation
127            the second parameter is equivalent to invoke
128            clazz.identifier.authority
129            As single string "attributes" could be as well just 'identifier.authority'
130            It does not return anything because it does not close the session
131            @param instance: an instance containing the appropriate id
132            @param attributes: a single string or a list of attributes to load
133            @param session: the session to use for the operation                             
134        """
135        if instance is None:
136            raise Exception("Instance is None!")
137        if session is None:
138            raise Exception("Session is None!")
139        session.merge(instance)
140        self._drillData(instance, attributes)                   
141
142
143    @classmethod   
144    def searchOrCreate(self, clazz, session, clazz_id = None):
145        if clazz_id is not None:
146            return EPB.search(clazz, clazz_id, session)
147        else:                       
148            return clazz()
149       
150
151    @classmethod
152    def getAllObjects(self, clazz, session):     
153        res = session.query(clazz)
154        if res is None:
155            return None
156        return res
157
158    @classmethod
159    def persistInstance(self, instance, session):
160        """
161            Adds a new migration object.
162            @param migrationObj: the migration object to add
163            @param session: an sqlalchemy Session object. If None (default) the method creates
164            @return an updated, session independant, object instance reflecting the new persisted object
165        """       
166        session.add(instance)
167        session.commit()
168        id_key = identity_key(instance=instance)
169        instance = EPB.search(id_key[0], id_key[1], session)
170        #instance = ret
171
172    @classmethod
173    def executeNative(self, sqlNative, session):
174        return session.execute(text(sqlNative))     
175
176    @classmethod
177    def _getSession(self, dbManager, session = None):
178        if session:
179            return session       
180        return dbManager.createDbSession()
181
182    @classmethod
183    def _drillData(self, obj, attrs):
184        """
185            @param obj: its an instance already living inside an SQLAlchemy session
186            @param attrs: a list of attributes owned by the obj parameter. It accepts dot separated attributes as childern of obj attributes.
187        """
188        #if is a single field wrap it in a list and recalls itself
189        if not isinstance(attrs, list):
190            self._drillData(obj, [attrs])
191        for item in attrs:
192            attr = item.split('.')[0]           
193            if isinstance(obj, list):
194                for element in obj:
195                    self._drillData(element, [item])
196            else:
197                if hasattr(obj, attr):
198                    nobj = getattr(obj, attr) 
199                    if len(attr) != len(item):
200                        self._drillData(nobj, [item[len(attr) + 1:]])
201
202       
Note: See TracBrowser for help on using the repository browser.