Statistics
| Branch: | Tag: | Revision:

root / snf-pithos-backend / pithos / backends / lib / sqlalchemy / xfeatures.py @ 5f8bbf54

History | View | Annotate | Download (7.6 kB)

1 2e662088 Antony Chazapis
# Copyright 2011-2012 GRNET S.A. All rights reserved.
2 4f917833 Sofia Papagiannaki
# 
3 4f917833 Sofia Papagiannaki
# Redistribution and use in source and binary forms, with or
4 4f917833 Sofia Papagiannaki
# without modification, are permitted provided that the following
5 4f917833 Sofia Papagiannaki
# conditions are met:
6 4f917833 Sofia Papagiannaki
# 
7 4f917833 Sofia Papagiannaki
#   1. Redistributions of source code must retain the above
8 4f917833 Sofia Papagiannaki
#      copyright notice, this list of conditions and the following
9 4f917833 Sofia Papagiannaki
#      disclaimer.
10 4f917833 Sofia Papagiannaki
# 
11 4f917833 Sofia Papagiannaki
#   2. Redistributions in binary form must reproduce the above
12 4f917833 Sofia Papagiannaki
#      copyright notice, this list of conditions and the following
13 4f917833 Sofia Papagiannaki
#      disclaimer in the documentation and/or other materials
14 4f917833 Sofia Papagiannaki
#      provided with the distribution.
15 4f917833 Sofia Papagiannaki
# 
16 4f917833 Sofia Papagiannaki
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 4f917833 Sofia Papagiannaki
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 4f917833 Sofia Papagiannaki
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 4f917833 Sofia Papagiannaki
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 4f917833 Sofia Papagiannaki
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 4f917833 Sofia Papagiannaki
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 4f917833 Sofia Papagiannaki
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 4f917833 Sofia Papagiannaki
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 4f917833 Sofia Papagiannaki
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 4f917833 Sofia Papagiannaki
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 4f917833 Sofia Papagiannaki
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 4f917833 Sofia Papagiannaki
# POSSIBILITY OF SUCH DAMAGE.
28 4f917833 Sofia Papagiannaki
# 
29 4f917833 Sofia Papagiannaki
# The views and conclusions contained in the software and
30 4f917833 Sofia Papagiannaki
# documentation are those of the authors and should not be
31 4f917833 Sofia Papagiannaki
# interpreted as representing official policies, either expressed
32 4f917833 Sofia Papagiannaki
# or implied, of GRNET S.A.
33 4f917833 Sofia Papagiannaki
34 4f917833 Sofia Papagiannaki
from collections import defaultdict
35 4f917833 Sofia Papagiannaki
from sqlalchemy import Table, Column, String, Integer, MetaData, ForeignKey
36 4f917833 Sofia Papagiannaki
from sqlalchemy.sql import select, and_
37 4f917833 Sofia Papagiannaki
from sqlalchemy.schema import Index
38 4f917833 Sofia Papagiannaki
from sqlalchemy.sql.expression import desc
39 4f917833 Sofia Papagiannaki
40 4f917833 Sofia Papagiannaki
from dbworker import DBWorker
41 4f917833 Sofia Papagiannaki
42 4f917833 Sofia Papagiannaki
43 4f917833 Sofia Papagiannaki
class XFeatures(DBWorker):
44 4f917833 Sofia Papagiannaki
    """XFeatures are path properties that allow non-nested
45 4f917833 Sofia Papagiannaki
       inheritance patterns. Currently used for storing permissions.
46 4f917833 Sofia Papagiannaki
    """
47 4f917833 Sofia Papagiannaki
    
48 4f917833 Sofia Papagiannaki
    def __init__(self, **params):
49 4f917833 Sofia Papagiannaki
        DBWorker.__init__(self, **params)
50 4f917833 Sofia Papagiannaki
        metadata = MetaData()
51 4f917833 Sofia Papagiannaki
        columns=[]
52 4f917833 Sofia Papagiannaki
        columns.append(Column('feature_id', Integer, primary_key=True))
53 4f917833 Sofia Papagiannaki
        columns.append(Column('path', String(2048)))
54 8af4c26d Antony Chazapis
        self.xfeatures = Table('xfeatures', metadata, *columns, mysql_engine='InnoDB')
55 4f917833 Sofia Papagiannaki
        # place an index on path
56 9e9615fe Sofia Papagiannaki
        Index('idx_features_path', self.xfeatures.c.path, unique=True)
57 4f917833 Sofia Papagiannaki
        
58 4f917833 Sofia Papagiannaki
        columns=[]
59 4f917833 Sofia Papagiannaki
        columns.append(Column('feature_id', Integer,
60 4f917833 Sofia Papagiannaki
                              ForeignKey('xfeatures.feature_id',
61 4f917833 Sofia Papagiannaki
                                         ondelete='CASCADE'),
62 4f917833 Sofia Papagiannaki
                              primary_key=True))
63 d3be972a Sofia Papagiannaki
        columns.append(Column('key', Integer, primary_key=True,
64 d3be972a Sofia Papagiannaki
                              autoincrement=False))
65 62bf8157 Antony Chazapis
        columns.append(Column('value', String(256), primary_key=True))
66 8af4c26d Antony Chazapis
        self.xfeaturevals = Table('xfeaturevals', metadata, *columns, mysql_engine='InnoDB')
67 4f917833 Sofia Papagiannaki
        
68 4f917833 Sofia Papagiannaki
        metadata.create_all(self.engine)
69 4f917833 Sofia Papagiannaki
    
70 d83c93c9 Antony Chazapis
#     def xfeature_inherit(self, path):
71 d83c93c9 Antony Chazapis
#         """Return the (path, feature) inherited by the path, or None."""
72 d83c93c9 Antony Chazapis
#         
73 d83c93c9 Antony Chazapis
#         s = select([self.xfeatures.c.path, self.xfeatures.c.feature_id])
74 d83c93c9 Antony Chazapis
#         s = s.where(self.xfeatures.c.path <= path)
75 d83c93c9 Antony Chazapis
#         #s = s.where(self.xfeatures.c.path.like(self.escape_like(path) + '%', escape='\\')) # XXX: Implement reverse and escape like...
76 d83c93c9 Antony Chazapis
#         s = s.order_by(desc(self.xfeatures.c.path))
77 d83c93c9 Antony Chazapis
#         r = self.conn.execute(s)
78 d83c93c9 Antony Chazapis
#         l = r.fetchall()
79 d83c93c9 Antony Chazapis
#         r.close()
80 d83c93c9 Antony Chazapis
#         return l
81 4f917833 Sofia Papagiannaki
    
82 cf341da4 Antony Chazapis
    def xfeature_get(self, path):
83 cf341da4 Antony Chazapis
        """Return feature for path."""
84 4f917833 Sofia Papagiannaki
        
85 cf341da4 Antony Chazapis
        s = select([self.xfeatures.c.feature_id])
86 cf341da4 Antony Chazapis
        s = s.where(self.xfeatures.c.path == path)
87 4f917833 Sofia Papagiannaki
        s = s.order_by(self.xfeatures.c.path)
88 4f917833 Sofia Papagiannaki
        r = self.conn.execute(s)
89 cf341da4 Antony Chazapis
        row = r.fetchone()
90 4f917833 Sofia Papagiannaki
        r.close()
91 cf341da4 Antony Chazapis
        if row:
92 cf341da4 Antony Chazapis
            return row[0]
93 cf341da4 Antony Chazapis
        return None
94 4f917833 Sofia Papagiannaki
    
95 4f917833 Sofia Papagiannaki
    def xfeature_create(self, path):
96 4f917833 Sofia Papagiannaki
        """Create and return a feature for path.
97 4f917833 Sofia Papagiannaki
           If the path has a feature, return it.
98 4f917833 Sofia Papagiannaki
        """
99 4f917833 Sofia Papagiannaki
        
100 cf341da4 Antony Chazapis
        feature = self.xfeature_get(path)
101 cf341da4 Antony Chazapis
        if feature is not None:
102 cf341da4 Antony Chazapis
            return feature
103 4f917833 Sofia Papagiannaki
        s = self.xfeatures.insert()
104 4f917833 Sofia Papagiannaki
        r = self.conn.execute(s, path=path)
105 4f917833 Sofia Papagiannaki
        inserted_primary_key = r.inserted_primary_key[0]
106 4f917833 Sofia Papagiannaki
        r.close()
107 4f917833 Sofia Papagiannaki
        return inserted_primary_key
108 4f917833 Sofia Papagiannaki
    
109 4f917833 Sofia Papagiannaki
    def xfeature_destroy(self, path):
110 4f917833 Sofia Papagiannaki
        """Destroy a feature and all its key, value pairs."""
111 4f917833 Sofia Papagiannaki
        
112 4f917833 Sofia Papagiannaki
        s = self.xfeatures.delete().where(self.xfeatures.c.path == path)
113 4f917833 Sofia Papagiannaki
        r = self.conn.execute(s)
114 4f917833 Sofia Papagiannaki
        r.close()
115 4f917833 Sofia Papagiannaki
    
116 8221c89d Sofia Papagiannaki
    def xfeature_destroy_bulk(self, paths):
117 8221c89d Sofia Papagiannaki
        """Destroy features and all their key, value pairs."""
118 8221c89d Sofia Papagiannaki
        
119 8221c89d Sofia Papagiannaki
        s = self.xfeatures.delete().where(self.xfeatures.c.path.in_(paths))
120 8221c89d Sofia Papagiannaki
        r = self.conn.execute(s)
121 8221c89d Sofia Papagiannaki
        r.close()
122 8221c89d Sofia Papagiannaki
    
123 4f917833 Sofia Papagiannaki
    def feature_dict(self, feature):
124 4f917833 Sofia Papagiannaki
        """Return a dict mapping keys to list of values for feature."""
125 4f917833 Sofia Papagiannaki
        
126 4f917833 Sofia Papagiannaki
        s = select([self.xfeaturevals.c.key, self.xfeaturevals.c.value])
127 4f917833 Sofia Papagiannaki
        s = s.where(self.xfeaturevals.c.feature_id == feature)
128 4f917833 Sofia Papagiannaki
        r = self.conn.execute(s)
129 4f917833 Sofia Papagiannaki
        d = defaultdict(list)
130 4f917833 Sofia Papagiannaki
        for key, value in r.fetchall():
131 4f917833 Sofia Papagiannaki
            d[key].append(value)
132 4f917833 Sofia Papagiannaki
        r.close()
133 4f917833 Sofia Papagiannaki
        return d
134 4f917833 Sofia Papagiannaki
    
135 4f917833 Sofia Papagiannaki
    def feature_set(self, feature, key, value):
136 4f917833 Sofia Papagiannaki
        """Associate a key, value pair with a feature."""
137 4f917833 Sofia Papagiannaki
        
138 2ce96391 Sofia Papagiannaki
        s = self.xfeaturevals.select()
139 2ce96391 Sofia Papagiannaki
        s = s.where(self.xfeaturevals.c.feature_id == feature)
140 2ce96391 Sofia Papagiannaki
        s = s.where(self.xfeaturevals.c.key == key)
141 a68d51a4 Sofia Papagiannaki
        s = s.where(self.xfeaturevals.c.value == value)
142 2ce96391 Sofia Papagiannaki
        r = self.conn.execute(s)
143 2ce96391 Sofia Papagiannaki
        xfeaturevals = r.fetchall()
144 4f917833 Sofia Papagiannaki
        r.close()
145 2ce96391 Sofia Papagiannaki
        if len(xfeaturevals) == 0:
146 2ce96391 Sofia Papagiannaki
            s = self.xfeaturevals.insert()
147 2ce96391 Sofia Papagiannaki
            r = self.conn.execute(s, feature_id=feature, key=key, value=value)
148 2ce96391 Sofia Papagiannaki
            r.close()
149 4f917833 Sofia Papagiannaki
    
150 4f917833 Sofia Papagiannaki
    def feature_setmany(self, feature, key, values):
151 4f917833 Sofia Papagiannaki
        """Associate the given key, and values with a feature."""
152 4f917833 Sofia Papagiannaki
        
153 2ce96391 Sofia Papagiannaki
        #TODO: more efficient way to do it
154 2ce96391 Sofia Papagiannaki
        for v in values:
155 2ce96391 Sofia Papagiannaki
            self.feature_set(feature, key, v)
156 4f917833 Sofia Papagiannaki
    
157 4f917833 Sofia Papagiannaki
    def feature_unset(self, feature, key, value):
158 4f917833 Sofia Papagiannaki
        """Disassociate a key, value pair from a feature."""
159 4f917833 Sofia Papagiannaki
        
160 4f917833 Sofia Papagiannaki
        s = self.xfeaturevals.delete()
161 4f917833 Sofia Papagiannaki
        s = s.where(and_(self.xfeaturevals.c.feature_id == feature,
162 4f917833 Sofia Papagiannaki
                     self.xfeaturevals.c.key == key,
163 4f917833 Sofia Papagiannaki
                     self.xfeaturevals.c.value == value))
164 4f917833 Sofia Papagiannaki
        r = self.conn.execute(s)
165 4f917833 Sofia Papagiannaki
        r.close()
166 4f917833 Sofia Papagiannaki
    
167 4f917833 Sofia Papagiannaki
    def feature_unsetmany(self, feature, key, values):
168 4f917833 Sofia Papagiannaki
        """Disassociate the key for the values given, from a feature."""
169 4f917833 Sofia Papagiannaki
        
170 4f917833 Sofia Papagiannaki
        for v in values:
171 4f917833 Sofia Papagiannaki
            conditional = and_(self.xfeaturevals.c.feature_id == feature,
172 4f917833 Sofia Papagiannaki
                               self.xfeaturevals.c.key == key,
173 4f917833 Sofia Papagiannaki
                               self.xfeaturevals.c.value == v)
174 4f917833 Sofia Papagiannaki
            s = self.xfeaturevals.delete().where(conditional)
175 4f917833 Sofia Papagiannaki
            r = self.conn.execute(s)
176 4f917833 Sofia Papagiannaki
            r.close()
177 4f917833 Sofia Papagiannaki
        
178 4f917833 Sofia Papagiannaki
    def feature_get(self, feature, key):
179 4f917833 Sofia Papagiannaki
        """Return the list of values for a key of a feature."""
180 4f917833 Sofia Papagiannaki
        
181 4f917833 Sofia Papagiannaki
        s = select([self.xfeaturevals.c.value])
182 4f917833 Sofia Papagiannaki
        s = s.where(and_(self.xfeaturevals.c.feature_id == feature,
183 4f917833 Sofia Papagiannaki
                     self.xfeaturevals.c.key == key))
184 4f917833 Sofia Papagiannaki
        r = self.conn.execute(s)
185 4f917833 Sofia Papagiannaki
        l = [row[0] for row in r.fetchall()]
186 4f917833 Sofia Papagiannaki
        r.close()
187 4f917833 Sofia Papagiannaki
        return l
188 4f917833 Sofia Papagiannaki
    
189 4f917833 Sofia Papagiannaki
    def feature_clear(self, feature, key):
190 4f917833 Sofia Papagiannaki
        """Delete all key, value pairs for a key of a feature."""
191 4f917833 Sofia Papagiannaki
        
192 4f917833 Sofia Papagiannaki
        s = self.xfeaturevals.delete()
193 4f917833 Sofia Papagiannaki
        s = s.where(and_(self.xfeaturevals.c.feature_id == feature,
194 4f917833 Sofia Papagiannaki
                     self.xfeaturevals.c.key == key))
195 4f917833 Sofia Papagiannaki
        r = self.conn.execute(s)
196 4f917833 Sofia Papagiannaki
        r.close()