Statistics
| Branch: | Tag: | Revision:

root / pithos / backends / lib / sqlite / xfeatures.py @ 95d47e1a

History | View | Annotate | Download (6.4 kB)

1
# Copyright 2011 GRNET S.A. All rights reserved.
2
# 
3
# Redistribution and use in source and binary forms, with or
4
# without modification, are permitted provided that the following
5
# conditions are met:
6
# 
7
#   1. Redistributions of source code must retain the above
8
#      copyright notice, this list of conditions and the following
9
#      disclaimer.
10
# 
11
#   2. Redistributions in binary form must reproduce the above
12
#      copyright notice, this list of conditions and the following
13
#      disclaimer in the documentation and/or other materials
14
#      provided with the distribution.
15
# 
16
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
# POSSIBILITY OF SUCH DAMAGE.
28
# 
29
# The views and conclusions contained in the software and
30
# documentation are those of the authors and should not be
31
# interpreted as representing official policies, either expressed
32
# or implied, of GRNET S.A.
33

    
34
from collections import defaultdict
35

    
36
from dbworker import DBWorker
37

    
38

    
39
class XFeatures(DBWorker):
40
    """XFeatures are path properties that allow non-nested
41
       inheritance patterns. Currently used for storing permissions.
42
    """
43
    
44
    def __init__(self, **params):
45
        DBWorker.__init__(self, **params)
46
        execute = self.execute
47
        
48
        execute(""" pragma foreign_keys = on """)
49
        
50
        execute(""" create table if not exists xfeatures
51
                          ( feature_id integer primary key,
52
                            path       text ) """)
53
        execute(""" create unique index if not exists idx_features_path
54
                    on xfeatures(path) """)
55

    
56
        execute(""" create table if not exists xfeaturevals
57
                          ( feature_id integer,
58
                            key        integer,
59
                            value      text,
60
                            primary key (feature_id, key, value)
61
                            foreign key (feature_id) references xfeatures(feature_id)
62
                            on delete cascade ) """)
63
    
64
    def xfeature_inherit(self, path):
65
        """Return the (path, feature) inherited by the path, or None."""
66
        
67
        q = ("select path, feature_id from xfeatures "
68
             "where path <= ? "
69
             "order by path desc limit 1")
70
        self.execute(q, (path,))
71
        r = self.fetchone()
72
        if r is not None and path.startswith(r[0]):
73
            return r
74
        return None
75
    
76
    def xfeature_list(self, path):
77
        """Return the list of the (prefix, feature) pairs matching path.
78
           A prefix matches path if either the prefix includes the path,
79
           or the path includes the prefix.
80
        """
81
        
82
        inherited = self.xfeature_inherit(path)
83
        if inherited:
84
            return [inherited]
85
        
86
        q = ("select path, feature_id from xfeatures "
87
             "where path like ? escape '\\' and path != ? order by path")
88
        self.execute(q, (self.escape_like(path) + '%', path,))
89
        return self.fetchall()
90
    
91
    def xfeature_create(self, path):
92
        """Create and return a feature for path.
93
           If the path already inherits a feature or
94
           bestows to paths already inheriting a feature,
95
           create no feature and return None.
96
           If the path has a feature, return it.
97
        """
98
        
99
        prefixes = self.xfeature_list(path)
100
        pl = len(prefixes)
101
        if (pl > 1) or (pl == 1 and prefixes[0][0] != path):
102
            return None
103
        if pl == 1 and prefixes[0][0] == path:
104
            return prefixes[0][1]
105
        q = "insert into xfeatures (path) values (?)"
106
        id = self.execute(q, (path,)).lastrowid
107
        return id
108
    
109
    def xfeature_destroy(self, path):
110
        """Destroy a feature and all its key, value pairs."""
111
        
112
        q = "delete from xfeatures where path = ?"
113
        self.execute(q, (path,))
114
    
115
    def feature_dict(self, feature):
116
        """Return a dict mapping keys to list of values for feature."""
117
        
118
        q = "select key, value from xfeaturevals where feature_id = ?"
119
        self.execute(q, (feature,))
120
        d = defaultdict(list)
121
        for key, value in self.fetchall():
122
            d[key].append(value)
123
        return d
124
    
125
    def feature_set(self, feature, key, value):
126
        """Associate a key, value pair with a feature."""
127
        
128
        q = "insert or ignore into xfeaturevals (feature_id, key, value) values (?, ?, ?)"
129
        self.execute(q, (feature, key, value))
130
    
131
    def feature_setmany(self, feature, key, values):
132
        """Associate the given key, and values with a feature."""
133
        
134
        q = "insert or ignore into xfeaturevals (feature_id, key, value) values (?, ?, ?)"
135
        self.executemany(q, ((feature, key, v) for v in values))
136
    
137
    def feature_unset(self, feature, key, value):
138
        """Disassociate a key, value pair from a feature."""
139
        
140
        q = ("delete from xfeaturevals where "
141
             "feature_id = ? and key = ? and value = ?")
142
        self.execute(q, (feature, key, value))
143
    
144
    def feature_unsetmany(self, feature, key, values):
145
        """Disassociate the key for the values given, from a feature."""
146
        
147
        q = ("delete from xfeaturevals where "
148
             "feature_id = ? and key = ? and value = ?")
149
        self.executemany(q, ((feature, key, v) for v in values))
150
    
151
    def feature_get(self, feature, key):
152
        """Return the list of values for a key of a feature."""
153
        
154
        q = "select value from xfeaturevals where feature_id = ? and key = ?"
155
        self.execute(q, (feature, key))
156
        return [r[0] for r in self.fetchall()]
157
    
158
    def feature_clear(self, feature, key):
159
        """Delete all key, value pairs for a key of a feature."""
160
        
161
        q = "delete from xfeaturevals where feature_id = ? and key = ?"
162
        self.execute(q, (feature, key))