Mercurial > libervia-backend
comparison src/memory/sqlite.py @ 669:ffb716804580
core, bridge: extra parameter is saved in history:
- added extra data in getHistory return value
- extra data is saved in database
/!\ WARNING: DATABASE SCHEMA HAS CHANGED /!\
to update sqlite database: ALTER TABLE history ADD COLUMN extra BLOB;
author | Goffi <goffi@goffi.org> |
---|---|
date | Thu, 07 Nov 2013 15:29:39 +0100 |
parents | 70988f08d0ad |
children | 66633443bcd7 |
comparison
equal
deleted
inserted
replaced
668:7bb50096d225 | 669:ffb716804580 |
---|---|
49 "INSERT INTO message_types VALUES ('chat')", | 49 "INSERT INTO message_types VALUES ('chat')", |
50 "INSERT INTO message_types VALUES ('error')", | 50 "INSERT INTO message_types VALUES ('error')", |
51 "INSERT INTO message_types VALUES ('groupchat')", | 51 "INSERT INTO message_types VALUES ('groupchat')", |
52 "INSERT INTO message_types VALUES ('headline')", | 52 "INSERT INTO message_types VALUES ('headline')", |
53 "INSERT INTO message_types VALUES ('normal')", | 53 "INSERT INTO message_types VALUES ('normal')", |
54 "CREATE TABLE history (id INTEGER PRIMARY KEY ASC, profile_id INTEGER, source TEXT, dest TEXT, source_res TEXT, dest_res TEXT, timestamp DATETIME, message TEXT, type TEXT, FOREIGN KEY(profile_id) REFERENCES profiles(id) ON DELETE CASCADE, FOREIGN KEY(type) REFERENCES message_types(type))", | 54 "CREATE TABLE history (id INTEGER PRIMARY KEY ASC, profile_id INTEGER, source TEXT, dest TEXT, source_res TEXT, dest_res TEXT, timestamp DATETIME, message TEXT, type TEXT, extra BLOB, FOREIGN KEY(profile_id) REFERENCES profiles(id) ON DELETE CASCADE, FOREIGN KEY(type) REFERENCES message_types(type))", |
55 "CREATE TABLE param_gen (category TEXT, name TEXT, value TEXT, PRIMARY KEY (category,name))", | 55 "CREATE TABLE param_gen (category TEXT, name TEXT, value TEXT, PRIMARY KEY (category,name))", |
56 "CREATE TABLE param_ind (category TEXT, name TEXT, profile_id INTEGER, value TEXT, PRIMARY KEY (category,name,profile_id), FOREIGN KEY(profile_id) REFERENCES profiles(id) ON DELETE CASCADE)", | 56 "CREATE TABLE param_ind (category TEXT, name TEXT, profile_id INTEGER, value TEXT, PRIMARY KEY (category,name,profile_id), FOREIGN KEY(profile_id) REFERENCES profiles(id) ON DELETE CASCADE)", |
57 "CREATE TABLE private_gen (namespace TEXT, key TEXT, value TEXT, PRIMARY KEY (namespace, key))", | 57 "CREATE TABLE private_gen (namespace TEXT, key TEXT, value TEXT, PRIMARY KEY (namespace, key))", |
58 "CREATE TABLE private_ind (namespace TEXT, key TEXT, profile_id INTEGER, value TEXT, PRIMARY KEY (namespace, key, profile_id), FOREIGN KEY(profile_id) REFERENCES profiles(id) ON DELETE CASCADE)", | 58 "CREATE TABLE private_ind (namespace TEXT, key TEXT, profile_id INTEGER, value TEXT, PRIMARY KEY (namespace, key, profile_id), FOREIGN KEY(profile_id) REFERENCES profiles(id) ON DELETE CASCADE)", |
59 "CREATE TABLE private_gen_bin (namespace TEXT, key TEXT, value BLOB, PRIMARY KEY (namespace, key))", | 59 "CREATE TABLE private_gen_bin (namespace TEXT, key TEXT, value BLOB, PRIMARY KEY (namespace, key))", |
175 d = self.dbpool.runQuery("REPLACE INTO param_ind(category,name,profile_id,value) VALUES (?,?,?,?)", (category, name, self.profiles[profile], value)) | 175 d = self.dbpool.runQuery("REPLACE INTO param_ind(category,name,profile_id,value) VALUES (?,?,?,?)", (category, name, self.profiles[profile], value)) |
176 d.addErrback(lambda ignore: error(_("Can't set individual parameter (%(category)s/%(name)s) for [%(profile)s] in database" % {"category": category, "name": name, "profile": profile}))) | 176 d.addErrback(lambda ignore: error(_("Can't set individual parameter (%(category)s/%(name)s) for [%(profile)s] in database" % {"category": category, "name": name, "profile": profile}))) |
177 return d | 177 return d |
178 | 178 |
179 #History | 179 #History |
180 def addToHistory(self, from_jid, to_jid, message, _type='chat', timestamp=None, profile=None): | 180 def addToHistory(self, from_jid, to_jid, message, _type='chat', extra=None, timestamp=None, profile=None): |
181 """Store a new message in history | 181 """Store a new message in history |
182 @param from_jid: full source JID | 182 @param from_jid: full source JID |
183 @param to_jid: full dest JID | 183 @param to_jid: full dest JID |
184 @param message: message | 184 @param message: message |
185 @param _type: message type (see RFC 6121 §5.2.2) | 185 @param _type: message type (see RFC 6121 §5.2.2) |
186 @param extra: dictionary (keys and values are unicode) of extra message data | |
186 @param timestamp: timestamp in seconds since epoch, or None to use current time | 187 @param timestamp: timestamp in seconds since epoch, or None to use current time |
187 """ | 188 """ |
188 assert(profile) | 189 assert(profile) |
189 d = self.dbpool.runQuery("INSERT INTO history(source, source_res, dest, dest_res, timestamp, message, type, profile_id) VALUES (?,?,?,?,?,?,?,?)", | 190 if extra is None: |
191 extra = {} | |
192 d = self.dbpool.runQuery("INSERT INTO history(source, source_res, dest, dest_res, timestamp, message, type, extra, profile_id) VALUES (?,?,?,?,?,?,?,?,?)", | |
190 (from_jid.userhost(), from_jid.resource, to_jid.userhost(), to_jid.resource, timestamp or time(), | 193 (from_jid.userhost(), from_jid.resource, to_jid.userhost(), to_jid.resource, timestamp or time(), |
191 message, _type, self.profiles[profile])) | 194 message, _type, pickle.dumps(extra, 0), self.profiles[profile])) |
192 d.addErrback(lambda ignore: error(_("Can't save following message in history: from [%(from_jid)s] to [%(to_jid)s] ==> [%(message)s]" % | 195 d.addErrback(lambda ignore: error(_("Can't save following message in history: from [%(from_jid)s] to [%(to_jid)s] ==> [%(message)s]" % |
193 {"from_jid": from_jid.full(), "to_jid": to_jid.full(), "message": message}))) | 196 {"from_jid": from_jid.full(), "to_jid": to_jid.full(), "message": message}))) |
194 return d | 197 return d |
195 | 198 |
196 def getHistory(self, from_jid, to_jid, limit=0, between=True, profile=None): | 199 def getHistory(self, from_jid, to_jid, limit=0, between=True, profile=None): |
199 @param to_jid: dest JID (full, or bare for catchall | 202 @param to_jid: dest JID (full, or bare for catchall |
200 @param size: maximum number of messages to get, or 0 for unlimited | 203 @param size: maximum number of messages to get, or 0 for unlimited |
201 """ | 204 """ |
202 assert(profile) | 205 assert(profile) |
203 | 206 |
204 def sqliteToDict(query_result): | 207 def sqliteToList(query_result): |
205 query_result.reverse() | 208 query_result.reverse() |
206 result = [] | 209 result = [] |
207 for row in query_result: | 210 for row in query_result: |
208 timestamp, source, source_res, dest, dest_res, message, _type = row | 211 timestamp, source, source_res, dest, dest_res, message, type_, extra_raw = row |
212 try: | |
213 extra = pickle.loads(str(extra_raw or "")) | |
214 except EOFError: | |
215 extra = {} | |
209 result.append((timestamp, "%s/%s" % (source, source_res) if source_res else source, | 216 result.append((timestamp, "%s/%s" % (source, source_res) if source_res else source, |
210 "%s/%s" % (dest, dest_res) if dest_res else dest, | 217 "%s/%s" % (dest, dest_res) if dest_res else dest, |
211 message, _type)) | 218 message, type_, extra)) |
212 return result | 219 return result |
213 | 220 |
214 query_parts = ["SELECT timestamp, source, source_res, dest, dest_res, message, type FROM history WHERE profile_id=? AND"] | 221 query_parts = ["SELECT timestamp, source, source_res, dest, dest_res, message, type, extra FROM history WHERE profile_id=? AND"] |
215 values = [self.profiles[profile]] | 222 values = [self.profiles[profile]] |
216 | 223 |
217 def test_jid(_type, _jid): | 224 def test_jid(type_, _jid): |
218 values.append(_jid.userhost()) | 225 values.append(_jid.userhost()) |
219 if _jid.resource: | 226 if _jid.resource: |
220 values.append(_jid.resource) | 227 values.append(_jid.resource) |
221 return '(%s=? AND %s_res=?)' % (_type, _type) | 228 return '(%s=? AND %s_res=?)' % (type_, type_) |
222 return '%s=?' % (_type, ) | 229 return '%s=?' % (type_, ) |
223 | 230 |
224 if between: | 231 if between: |
225 query_parts.append("(%s OR %s) AND (%s or %s)" % (test_jid('source', from_jid), | 232 query_parts.append("(%s OR %s) AND (%s or %s)" % (test_jid('source', from_jid), |
226 test_jid('source', to_jid), | 233 test_jid('source', to_jid), |
227 test_jid('dest', to_jid), | 234 test_jid('dest', to_jid), |
235 if limit: | 242 if limit: |
236 query_parts.append("LIMIT ?") | 243 query_parts.append("LIMIT ?") |
237 values.append(limit) | 244 values.append(limit) |
238 | 245 |
239 d = self.dbpool.runQuery(" ".join(query_parts), values) | 246 d = self.dbpool.runQuery(" ".join(query_parts), values) |
240 return d.addCallback(sqliteToDict) | 247 return d.addCallback(sqliteToList) |
241 | 248 |
242 #Private values | 249 #Private values |
243 def loadGenPrivates(self, private_gen, namespace): | 250 def loadGenPrivates(self, private_gen, namespace): |
244 """Load general private values | 251 """Load general private values |
245 @param private_gen: dictionary to fill | 252 @param private_gen: dictionary to fill |