Changeset 2987
- Timestamp:
- 01/06/08 00:34:44 (11 months ago)
- Files:
-
- boxdbplugin/0.11/boxdb/api.py (modified) (5 diffs)
- boxdbplugin/0.11/boxdb/model.py (modified) (5 diffs)
- boxdbplugin/0.11/boxdb/_simplejson/decoder.py (modified) (1 diff)
- boxdbplugin/0.11/boxdb/_simplejson/jsonfilter.py (deleted)
- boxdbplugin/0.11/test_data.csv (modified) (1 diff)
- boxdbplugin/0.11/TracBoxDB.egg-info (deleted)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
boxdbplugin/0.11/boxdb/api.py
r2986 r2987 14 14 """Return an iterable of property names this component will handle.""" 15 15 16 def decode_property(name, values):17 """Return a decoded value for a property."""18 19 def encode_property(name, value):20 """Return an encoded string for a property, suitable for storage."""21 22 16 def render_property(name, value): 23 17 """Return a value suitable for display.""" … … 28 22 29 23 renderers = ExtensionPoint(IDocumentPropertyRenderer) 30 24 31 25 implements(IEnvironmentSetupParticipant) 32 26 … … 41 35 self.found_db_version = 0 42 36 self.upgrade_environment(self.env.get_db_cnx()) 43 37 44 38 def environment_needs_upgrade(self, db): 45 39 cursor = db.cursor() … … 53 47 #self.log.debug('WeatherWidgetSystem: Found db version %s, current is %s' % (self.found_db_version, db_default.version)) 54 48 return self.found_db_version < db_default.version 55 49 56 50 def upgrade_environment(self, db): 57 51 db_manager, _ = DatabaseManager(self.env)._get_connector() … … 72 66 if 'OperationalError' not in e.__class__.__name__: 73 67 raise e # If it is an OperationalError, just move on to the next table 74 75 68 69 76 70 for tbl in db_default.tables: 77 71 for sql in db_manager.to_sql(tbl): 78 72 cursor.execute(sql) 79 73 80 74 # Try to reinsert any old data 81 75 if tbl.name in old_data: boxdbplugin/0.11/boxdb/model.py
r2986 r2987 1 1 # Created by on 2008-01-02. 2 2 # Copyright (c) 2008 Noah Kantrowitz. All rights reserved. 3 from datetime import datetime 4 5 from trac.util.datefmt import to_timestamp, utc 6 from trac.util.compat import set 7 8 try: 9 import simplejson 10 except ImportError: 11 import _simplejson as simplejson 3 12 4 13 from boxdb.api import BoxDBSystem … … 11 20 self.env = env 12 21 self.name = name 22 self._old_data = {} 13 23 14 24 if self.name == 'schema': 15 25 self._bootstrap() 16 26 else: 17 data =self._fetch(self.name, db)18 if not data:27 self._fetch(self.name, db) 28 if not self: 19 29 self.type = None 20 30 # Document doesn't exist, return a blank 21 31 return 22 32 33 self._old_data.update(self) 34 23 35 # Decode the document 24 self.type = Document(self.env, data['__type__'][0], db) 25 renderers = BoxDBSystem(self.env).renderers_map 26 for key, value in data.iteritems(): 27 key_type = self.type.get(key, 'string') 28 if key_type not in renderers: 29 key_type = 'string' 30 self[key] = renderers[key_type].decode_property(key, value) 36 self.type = Document(self.env, self.type, db) 37 for key, value in self.iteritems(): 38 self[key] = simplejson.loads(value) 31 39 32 40 def _bootstrap(self): … … 36 44 def _fetch(self, name, db=None): 37 45 """Retrieve the raw data for a given document.""" 38 data = {}39 40 46 db = db or self.env.get_db_cnx() 41 47 cursor = db.cursor() … … 44 50 if type: 45 51 # Fetch and decode collection 46 type = type[0]52 type = simplejson.loads(type[0]) 47 53 if type == self.name: 48 54 raise ValueError('Document cannot be its own type') 55 self.type = type 49 56 50 57 # Process inheritance 51 58 inherit = self._get_db(cursor, name, '__inherit__') 52 59 if inherit: 53 data = self._fetch(inherit[0], db) 60 inherit = simplejson.loads(inherit[0]) 61 self._fetch(inherit, db) 54 62 55 local_data = {}56 63 cursor.execute('SELECT key, value FROM boxdb WHERE name=%s', 57 64 (name,)) 58 65 for key, value in cursor: 59 local_data.setdefault(key, []).append(value) 60 61 data.update(local_data) 62 return data 63 66 self[key] = value 67 64 68 def _get_db(self, cursor, name, key): 65 69 """Get an iterable of raw values for a key in this document.""" 66 70 cursor.execute('SELECT value FROM boxdb WHERE name=%s AND key=%s', 67 71 (name, key)) 68 return [v for v, in cursor]72 return cursor.fetchone() 69 73 70 74 def save(self, db=None): 71 75 """Save the changes to the current document.""" 76 author = 'coderanger' 77 when = None 78 comment = 'This is a comment' 79 80 if when is None: 81 when = datetime.now(utc) 82 when_ts = to_timestamp(when) 83 72 84 handle_commit = False 73 85 if db is None: … … 76 88 cursor = db.cursor() 77 89 78 # Nuke existing data 79 cursor.execute('DELETE FROM boxdb WHERE name=%s', (self.name,)) 90 data = dict([(key, simplejson.dumps(value)) for key, value in self.iteritems()]) 80 91 81 # Check that we haven't changed schemas 82 if self.type is None or self['__type__'] != self.type.name: 83 if self['__type__'] == self.name: 84 raise ValueError('Document cannot be its own type') 85 self.type = Document(self.env, self['__type__'], db) 86 renderers = BoxDBSystem(self.env).renderers_map 92 sql_queue = [('__comment__', simplejson.dumps(comment), '')] 93 for key in set(data.iterkeys()) | set(self._old_data.iterkeys()): 94 if key not in data: 95 # Key deleted 96 cursor.execute('DELETE FROM boxdb WHERE name=%s AND key=%s', 97 (self.name, key)) 98 sql_queue.append((key, self._old_data[key], '')) 99 elif key not in self._old_data: 100 # Key added 101 cursor.execute('INSERT INTO boxdb (name, key, value) VALUES (%s, %s, %s)', 102 (self.name, key, data[key])) 103 sql_queue.append((key, '', data[key])) 104 elif data[key] != self._old_data[key]: 105 # Key changed 106 cursor.execute('UPDATE boxdb SET value=%s WHERE name=%s AND key=%s', 107 (data[key], self.name, key)) 108 sql_queue.append((key, self._old_data[key], data[key])) 87 109 88 data = [] 89 for key, value in self.itervalues(): 90 key_type = self.type.get(key, 'string') 91 if key_type not in renderers: 92 key_type = 'string' 93 for enc in renderers[key_type].encode_property(key, value): 94 data.append((self.name, key, enc)) 95 cursor.executemany('INSERT INTO boxdb (name, key, value) VALUES (%s, %s, %s)', ) 110 for key, old, new in sql_queue: 111 cursor.execute('INSERT INTO boxdb_changes (document, time, author, key, oldvalue, newvalue) VALUES (%s, %s, %s, %s, %s, %s)', 112 (self.name, when_ts, author, key, old, new)) 113 114 if handle_commit: 115 db.commit() 116 117 def get_changelog(self, when=None, db=None): 118 """Return a iterable of the form: 119 (time, author, key, oldvalue, newvalue) 120 """ 121 db = db or self.env.get_db_cnx() 122 cursor = db.cursor() 123 when_ts = when and to_timestamp(when) or 0 124 if when_ts: 125 cursor.execute('SELECT time, author, key, oldvalue, newvalue ' 126 'FROM boxdb_changes ' 127 'WHERE document=%s AND time=%s' 128 'ORDER BY time', 129 (self.name, when_ts)) 130 else: 131 cursor.execute('SELECT time, author, key, oldvalue, newvalue ' 132 'FROM boxdb_changes ' 133 'WHERE document=%s' 134 'ORDER BY time', 135 (self.name,)) 136 for t, author, key, oldvalue, newvalue in cursor: 137 t = datetime.fromtimestamp(int(t), utc) 96 138 97 98 139 if oldvalue: 140 oldvalue = simplejson.loads(oldvalue) 141 else: 142 oldvalue = None 143 144 if newvalue: 145 newvalue = simplejson.loads(newvalue) 146 else: 147 newvalue = None 148 149 yield t, author, key, oldvalue, newvalue boxdbplugin/0.11/boxdb/_simplejson/decoder.py
r2986 r2987 4 4 import re 5 5 6 from _simplejson.scanner import Scanner, pattern6 from scanner import Scanner, pattern 7 7 8 8 FLAGS = re.VERBOSE | re.MULTILINE | re.DOTALL boxdbplugin/0.11/test_data.csv
r2986 r2987 1 equipment,__type__, schema2 equipment,id, string3 equipment,type, string4 computer,__type__, schema5 computer,__inherit__, equipment6 computer,os, string7 computer,id, number8 box,__type__, equipment9 box,id, 01010010110 box,type, cardboard11 tower,__type__, computer12 tower,__inherit__, box13 tower,os, xp14 shuttle,__type__, computer15 shuttle,__inherit__, box16 shuttle,os, me17 shuttle,id, 123451 equipment,__type__,"schema" 2 equipment,id,"string" 3 equipment,type,"string" 4 computer,__type__,"schema" 5 computer,__inherit__,"equipment" 6 computer,os,"string" 7 computer,id,"number" 8 box,__type__,"equipment" 9 box,id,"010100101" 10 box,type,"cardboard" 11 tower,__type__,"computer" 12 tower,__inherit__,"box" 13 tower,os,"xp" 14 shuttle,__type__,"computer" 15 shuttle,__inherit__,"box" 16 shuttle,os,"me" 17 shuttle,id,"12345"
