Setting tag sfa-2.0-10
[sfa.git] / sfa / storage / table.py
1 #
2 # implements support for SFA records stored in db tables
3 #
4 # TODO: Use existing PLC database methods? or keep this separate?
5
6 from types import StringTypes
7
8 from sfa.util.config import Config
9
10 from sfa.storage.parameter import Parameter
11 from sfa.storage.filter import Filter
12 from sfa.storage.PostgreSQL import PostgreSQL
13 from sfa.storage.record import SfaRecord, AuthorityRecord, NodeRecord, SliceRecord, UserRecord
14
15 class SfaTable(list):
16
17     SFA_TABLE_PREFIX = "records"
18
19     def __init__(self, record_filter = None):
20
21         # pgsql doesn't like table names with "." in them, to replace it with "$"
22         self.tablename = SfaTable.SFA_TABLE_PREFIX
23         self.config = Config()
24         self.db = PostgreSQL(self.config)
25
26         if record_filter:
27             records = self.find(record_filter)
28             for record in records:
29                 self.append(record)             
30
31     def db_fields(self, obj=None):
32         
33         db_fields = self.db.fields(self.SFA_TABLE_PREFIX)
34         return dict( [ (key,value) for (key, value) in obj.iteritems() \
35                         if key in db_fields and
36                         self.is_writable(key, value, SfaRecord.fields)] )      
37
38     @staticmethod
39     def is_writable (key,value,dict):
40         # if not mentioned, assume it's writable (e.g. deleted ...)
41         if key not in dict: return True
42         # if mentioned but not linked to a Parameter object, idem
43         if not isinstance(dict[key], Parameter): return True
44         # if not marked ro, it's writable
45         if not dict[key].ro: return True
46
47         return False
48
49
50     def clear (self):
51         self.db.do("DELETE from %s"%self.tablename)
52         self.db.commit()
53
54     # what sfa-nuke does
55     def nuke (self):
56         self.clear()
57
58     def remove(self, record):
59         params = {'record_id': record['record_id']}
60         template = "DELETE FROM %s " % self.tablename
61         sql = template + "WHERE record_id = %(record_id)s"
62         self.db.do(sql, params)
63         
64         # if this is a site, remove all records where 'authority' == the 
65         # site's hrn
66         if record['type'] == 'authority':
67             params = {'authority': record['hrn']}
68             sql = template + "WHERE authority = %(authority)s"
69             self.db.do(sql, params)
70         self.db.commit() 
71
72     def insert(self, record):
73         db_fields = self.db_fields(record)
74         keys = db_fields.keys()
75         values = [self.db.param(key, value) for (key, value) in db_fields.iteritems()]
76         query_str = "INSERT INTO " + self.tablename + \
77                        "(" + ",".join(keys) + ") " + \
78                        "VALUES(" + ",".join(values) + ")"
79         self.db.do(query_str, db_fields)
80         self.db.commit()
81         result = self.find({'hrn': record['hrn'], 'type': record['type'], 'peer_authority': record['peer_authority']})
82         if not result:
83             record_id = None
84         elif isinstance(result, list):
85             record_id = result[0]['record_id']
86         else:
87             record_id = result['record_id']
88
89         return record_id
90
91     def update(self, record):
92         db_fields = self.db_fields(record)
93         keys = db_fields.keys()
94         values = [self.db.param(key, value) for (key, value) in db_fields.iteritems()]
95         columns = ["%s = %s" % (key, value) for (key, value) in zip(keys, values)]
96         query_str = "UPDATE %s SET %s WHERE record_id = %s" % \
97                     (self.tablename, ", ".join(columns), record['record_id'])
98         self.db.do(query_str, db_fields)
99         self.db.commit()
100
101     def quote_string(self, value):
102         return str(self.db.quote(value))
103
104     def quote(self, value):
105         return self.db.quote(value)
106
107     def find(self, record_filter = None, columns=None):
108         if not columns:
109             columns = "*"
110         else:
111             columns = ",".join(columns)
112         sql = "SELECT %s FROM %s WHERE True " % (columns, self.tablename)
113         
114         if isinstance(record_filter, (list, tuple, set)):
115             ints = filter(lambda x: isinstance(x, (int, long)), record_filter)
116             strs = filter(lambda x: isinstance(x, StringTypes), record_filter)
117             record_filter = Filter(SfaRecord.all_fields, {'record_id': ints, 'hrn': strs})
118             sql += "AND (%s) %s " % record_filter.sql("OR") 
119         elif isinstance(record_filter, dict):
120             record_filter = Filter(SfaRecord.all_fields, record_filter)        
121             sql += " AND (%s) %s" % record_filter.sql("AND")
122         elif isinstance(record_filter, StringTypes):
123             record_filter = Filter(SfaRecord.all_fields, {'hrn':[record_filter]})    
124             sql += " AND (%s) %s" % record_filter.sql("AND")
125         elif isinstance(record_filter, int):
126             record_filter = Filter(SfaRecord.all_fields, {'record_id':[record_filter]})    
127             sql += " AND (%s) %s" % record_filter.sql("AND")
128
129         results = self.db.selectall(sql)
130         if isinstance(results, dict):
131             results = [results]
132         return results
133
134     def findObjects(self, record_filter = None, columns=None):
135         
136         results = self.find(record_filter, columns) 
137         result_rec_list = []
138         for result in results:
139             if result['type'] in ['authority']:
140                 result_rec_list.append(AuthorityRecord(dict=result))
141             elif result['type'] in ['node']:
142                 result_rec_list.append(NodeRecord(dict=result))
143             elif result['type'] in ['slice']:
144                 result_rec_list.append(SliceRecord(dict=result))
145             elif result['type'] in ['user']:
146                 result_rec_list.append(UserRecord(dict=result))
147             else:
148                 result_rec_list.append(SfaRecord(dict=result))
149         return result_rec_list
150
151