Merge lp:~stefanor/ibid/upgradeable-db-schema into lp:~ibid-core/ibid/old-trunk-pack-0.92

Proposed by Stefano Rivera
Status: Merged
Approved by: Stefano Rivera
Approved revision: 601
Merged at revision: 594
Proposed branch: lp:~stefanor/ibid/upgradeable-db-schema
Merge into: lp:~ibid-core/ibid/old-trunk-pack-0.92
Diff against target: None lines
To merge this branch: bzr merge lp:~stefanor/ibid/upgradeable-db-schema
Reviewer Review Type Date Requested Status
Jonathan Hitchcock Approve
Michael Gorven Approve
Review via email: mp+5493@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Stefano Rivera (stefanor) wrote :

OK, I (finally) have something workable. To see it in action, take a look at lp:~stefanor/ibid/schema-strings

Known issues:
* Plugins with outdated schemas are simply not loaded. At startup time, this should probably abort startup
* Table upgrade is done with ibid-setup (hit ^C when it prompts you for the initial account). ibid-setup should probably output the upgrade progress (hint: logging) and not prompt for initial accounts, if it detects an upgrade.

Unknown issues:
* please provide :)

Revision history for this message
Stefano Rivera (stefanor) wrote :

To enable schema upgrades on an existing database, you'll have to do something like:

CREATE TABLE schema (
  id INTEGER NOT NULL,
  "table" VARCHAR(32) NOT NULL,
  version INTEGER NOT NULL,
  PRIMARY KEY (id),
  UNIQUE ("table")
);
INSERT INTO schema (id, "table", version) VALUES (1, "account_attributes", 1);
INSERT INTO schema (id, "table", version) VALUES (2, "accounts", 1);
INSERT INTO schema (id, "table", version) VALUES (3, "credentials", 1);
INSERT INTO schema (id, "table", version) VALUES (4, "factoid_names", 1);
INSERT INTO schema (id, "table", version) VALUES (5, "factoid_values", 1);
INSERT INTO schema (id, "table", version) VALUES (6, "factoids", 1);
INSERT INTO schema (id, "table", version) VALUES (7, "feeds", 1);
INSERT INTO schema (id, "table", version) VALUES (8, "identities", 1);
INSERT INTO schema (id, "table", version) VALUES (9, "karma", 1);
INSERT INTO schema (id, "table", version) VALUES (10, "memos", 1);
INSERT INTO schema (id, "table", version) VALUES (11, "permissions", 1);
INSERT INTO schema (id, "table", version) VALUES (12, "seen", 1);
INSERT INTO schema (id, "table", version) VALUES (13, "schema", 1);
INSERT INTO schema (id, "table", version) VALUES (14, "urls", 1);

Also, Known issue to examine tomorrow: Doesn't work in jaunty:
Traceback (most recent call last):
  File "scripts/ibid-setup", line 67, in <module>
    upgrade_schemas(Session)
  File "/home/stefanor/projects/ibid/tibid/ibid/models.py", line 374, in upgrade_schemas
    table.versioned_schema.upgrade_schema(sessionmaker)
  File "/home/stefanor/projects/ibid/tibid/ibid/models.py", line 87, in upgrade_schema
    eval('self.upgrade_%i_to_%i' % (version - 1, version))()
  File "/home/stefanor/projects/ibid/tibid/ibid/plugins/karma.py", line 27, in upgrade_1_to_2
    self.alter_column(Column('subject', Unicode(64), unique=True, nullable=False), length_only=True)
  File "/home/stefanor/projects/ibid/tibid/ibid/models.py", line 161, in alter_column
    if session.bind.dialect.name == 'sqlite':
AttributeError: 'SQLiteDialect' object has no attribute 'name'

599. By Stefano Rivera

Support dialect detection in SQLAlchemy 0.4

Revision history for this message
Stefano Rivera (stefanor) wrote :

> Also, Known issue to examine tomorrow: Doesn't work in jaunty:

Fixed in r599

600. By Stefano Rivera

Use getattr() over eval()

Revision history for this message
Stefano Rivera (stefanor) wrote :

Another known issue: There are no helpers for dealing with indexes yet.

Revision history for this message
Michael Gorven (mgorven) wrote :

I don't like that the MySQL engine is forced to InnoDB, but this otherwise
looks good.
 review approve

review: Approve
601. By Stefano Rivera

Move InnoDB preference into MySQLModeListener, use DatabaseManager in ibid-setup

Revision history for this message
Stefano Rivera (stefanor) wrote :

> I don't like that the MySQL engine is forced to InnoDB

That's configurable (and implemented better) in r601

Revision history for this message
Jonathan Hitchcock (vhata) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'ibid/__init__.py'
--- ibid/__init__.py 2009-03-16 20:55:20 +0000
+++ ibid/__init__.py 2009-04-13 17:36:47 +0000
@@ -93,7 +93,4 @@
93class SourceException(IbidException):93class SourceException(IbidException):
94 pass94 pass
9595
96class ConfigException(Exception):
97 pass
98
99# vi: set et sta sw=4 ts=4:96# vi: set et sta sw=4 ts=4:
10097
=== modified file 'ibid/core.py'
--- ibid/core.py 2009-03-24 10:42:41 +0000
+++ ibid/core.py 2009-04-13 19:09:37 +0000
@@ -172,6 +172,8 @@
172 ibid.processors.append(klass(name))172 ibid.processors.append(klass(name))
173 else:173 else:
174 self.log.debug("Skipping Processor: %s.%s", name, klass.__name__)174 self.log.debug("Skipping Processor: %s.%s", name, klass.__name__)
175
176 ibid.models.check_schema_versions(ibid.databases['ibid'])
175 177
176 except Exception, e:178 except Exception, e:
177 self.log.exception(u"Couldn't instantiate %s processor of %s plugin", classname, name)179 self.log.exception(u"Couldn't instantiate %s processor of %s plugin", classname, name)
@@ -235,13 +237,28 @@
235 for database in ibid.config.databases.keys():237 for database in ibid.config.databases.keys():
236 self.load(database)238 self.load(database)
237239
240 ibid.models.check_schema_versions(self['ibid'])
241
238 def load(self, name):242 def load(self, name):
239 uri = ibid.config.databases[name]243 uri = ibid.config.databases[name]
240 if uri.startswith('sqlite:///'):244 if uri.startswith('sqlite:///'):
241 engine = create_engine('sqlite:///', creator=sqlite_creator(join(ibid.options['base'], expanduser(uri.replace('sqlite:///', '', 1)))), encoding='utf-8', convert_unicode=True, assert_unicode=True, echo=False)245 engine = create_engine('sqlite:///',
246 creator=sqlite_creator(join(ibid.options['base'], expanduser(uri.replace('sqlite:///', '', 1)))),
247 encoding='utf-8', convert_unicode=True, assert_unicode=True, echo=False)
248
242 else:249 else:
243 engine = create_engine(uri, encoding='utf-8', convert_unicode=True, assert_unicode=True)250 engine = create_engine(uri, encoding='utf-8', convert_unicode=True, assert_unicode=True, echo=False)
251
252 if uri.startswith('mysql://'):
253 class MySQLModeListener(object):
254 def connect(self, dbapi_con, con_record):
255 dbapi_con.set_sql_mode("ANSI")
256 engine.pool.add_listener(MySQLModeListener())
257
258 engine.dialect.use_ansiquotes = True
259
244 self[name] = scoped_session(sessionmaker(bind=engine, transactional=False, autoflush=True))260 self[name] = scoped_session(sessionmaker(bind=engine, transactional=False, autoflush=True))
261
245 self.log.info(u"Loaded %s database", name)262 self.log.info(u"Loaded %s database", name)
246263
247 def __getattr__(self, name):264 def __getattr__(self, name):
248265
=== modified file 'ibid/models.py'
--- ibid/models.py 2009-02-18 19:05:10 +0000
+++ ibid/models.py 2009-04-13 19:07:30 +0000
@@ -1,20 +1,254 @@
1from sqlalchemy import Column, Integer, Unicode, DateTime, ForeignKey, UniqueConstraint, MetaData, Table1import logging
2
3from sqlalchemy import Column, Integer, Unicode, DateTime, ForeignKey, UniqueConstraint, MetaData, Table, PassiveDefault, __version__
2from sqlalchemy.orm import relation4from sqlalchemy.orm import relation
3from sqlalchemy.ext.declarative import declarative_base5from sqlalchemy.ext.declarative import declarative_base
4from sqlalchemy.sql import func6from sqlalchemy.sql import func
7from sqlalchemy.sql.expression import text
8from sqlalchemy.exceptions import OperationalError, InvalidRequestError
9
10if __version__ < '0.5':
11 NoResultFound = InvalidRequestError
12else:
13 from sqlalchemy.orm.exc import NoResultFound
514
6metadata = MetaData()15metadata = MetaData()
7Base = declarative_base(metadata=metadata)16Base = declarative_base(metadata=metadata)
17log = logging.getLogger('ibid.models')
18
19class VersionedSchema(object):
20 """For an initial table schema, set
21 table.versioned_schema = VersionedSchema(__table__, 1)
22 Table creation (upgrading to version 1) is implicitly supported.
23
24 When you have upgrades to the schema, instead of using VersionedSchema
25 directly, derive from it and include your own upgrade_x_to_y(self) methods,
26 where y = x + 1
27
28 In the upgrade methods, you can call the helper functions:
29 add_column, drop_column, rename_column, alter_column
30 They try to do the correct thing in most situations, including rebuilding
31 tables in SQLite, which doesn't actually support dropping/altering columns.
32 For column parameters, while you can point to columns in the table
33 definition, it is better style to repeat the Column() specification as the
34 column might be altered in a future version.
35 """
36
37 def __init__(self, table, version):
38 self.table = table
39 self.version = version
40
41 def is_up_to_date(self, session):
42 "Is the table in the database up to date with the schema?"
43
44 if not session.bind.has_table(self.table.name):
45 return False
46
47 try:
48 schema = session.query(Schema).filter(Schema.table==unicode(self.table.name)).one()
49 return schema.version == self.version
50 except NoResultFound:
51 return False
52
53 def upgrade_schema(self, sessionmaker):
54 "Upgrade the table's schema to the latest version."
55
56 for fk in self.table.foreign_keys:
57 dependancy = fk.target_fullname.split('.')[0]
58 log.debug("Upgrading table %s before %s", dependancy, self.table.name)
59 metadata.tables[dependancy].versioned_schema.upgrade_schema(sessionmaker)
60
61 self.upgrade_session = session = sessionmaker()
62 trans = session.begin()
63
64 schema = session.query(Schema).filter(Schema.table==unicode(self.table.name)).first()
65
66 try:
67 if not schema:
68 log.info(u"Creating table %s", self.table.name)
69
70 # If MySQL, we prefer InnoDB:
71 if 'mysql_engine' not in self.table.kwargs:
72 self.table.kwargs['mysql_engine'] = 'InnoDB'
73
74 self.table.create(bind=session.bind)
75
76 schema = Schema(unicode(self.table.name), self.version)
77 session.save_or_update(schema)
78
79 elif self.version > schema.version:
80 self.upgrade_reflected_model = MetaData(session.bind, reflect=True)
81 for version in range(schema.version + 1, self.version + 1):
82 log.info(u"Upgrading table %s to version %i", self.table.name, version)
83
84 trans.commit()
85 trans = session.begin()
86
87 eval('self.upgrade_%i_to_%i' % (version - 1, version))()
88
89 schema.version = version
90 session.save_or_update(schema)
91 del self.upgrade_reflected_model
92
93 trans.commit()
94
95 except:
96 trans.rollback()
97 raise
98
99 session.close()
100 del self.upgrade_session
101
102 def get_reflected_model(self):
103 "Get a reflected table from the current DB's schema"
104
105 return self.upgrade_reflected_model.tables.get(self.table.name, None)
106
107 def add_column(self, col):
108 "Add column col to table"
109
110 session = self.upgrade_session
111 table = self.get_reflected_model()
112
113 log.debug(u"Adding column %s to table %s", col.name, table.name)
114
115 table.append_column(col)
116
117 sg = session.bind.dialect.schemagenerator(session.bind.dialect, session.bind)
118 description = sg.get_column_specification(col)
119
120 session.execute('ALTER TABLE "%s" ADD COLUMN %s;' % (table.name, description))
121
122 def drop_column(self, col_name):
123 "Drop column col_name from table"
124
125 session = self.upgrade_session
126
127 log.debug(u"Dropping column %s from table %s", col_name, self.table.name)
128
129 if session.bind.dialect.name == 'sqlite':
130 self.rebuild_sqlite({col_name: None})
131 else:
132 session.execute('ALTER TABLE "%s" DROP COLUMN "%s";' % (self.table.name, col_name))
133
134 def rename_column(self, col, old_name):
135 "Rename column from old_name to Column col"
136
137 session = self.upgrade_session
138 table = self.get_reflected_model()
139
140 log.debug(u"Rename column %s to %s in table %s", old_name, col.name, table.name)
141
142 if session.bind.dialect.name == 'sqlite':
143 self.rebuild_sqlite({old_name: col})
144 elif session.bind.dialect.name == 'mysql':
145 self.alter_column(col, old_name)
146 else:
147 session.execute('ALTER TABLE "%s" RENAME COLUMN "%s" TO "%s";' % (table.name, old_name, col.name))
148
149 def alter_column(self, col, old_name=None, length_only=False):
150 """Change a column (possibly renaming from old_name) to Column col.
151 Specify length_only if the change is simply a change of data-type length."""
152
153 session = self.upgrade_session
154 table = self.get_reflected_model()
155
156 log.debug(u"Altering column %s in table %s", col.name, table.name)
157
158 sg = session.bind.dialect.schemagenerator(session.bind.dialect, session.bind)
159 description = sg.get_column_specification(col)
160
161 if session.bind.dialect.name == 'sqlite':
162 #TODO: Automatically detect length_only
163 if length_only:
164 # SQLite doesn't enforce value length restrictions, only type changes have a real effect
165 return
166
167 self.rebuild_sqlite({old_name is None and col.name or old_name: col})
168
169 elif session.bind.dialect.name == 'mysql':
170 session.execute('ALTER TABLE "%s" CHANGE "%s" %s;'
171 % (table.name, old_name is not None and old_name or col.name, description))
172
173 else:
174 if old_name is not None:
175 self.rename_column(col, old_name)
176 session.execute('ALTER TABLE "%s" ALTER COLUMN "%s" TYPE %s'
177 % (table.name, col.name, description.split(" ", 1)[1]))
178
179 def rebuild_sqlite(self, colmap):
180 """SQLite doesn't support modification of table schema - must rebuild the table.
181 colmap maps old column names to new Columns (or None for column deletion).
182 Only modified columns need to be listed, unchaged columns are carried over automatically.
183 Specify table in case name has changed in a more recent version."""
184
185 session = self.upgrade_session
186 table = self.get_reflected_model()
187
188 log.debug(u"Rebuilding SQLite table %s", table.name)
189
190 fullcolmap = {}
191 for col in table.c:
192 if col.name in colmap:
193 if colmap[col.name] is not None:
194 fullcolmap[col.name] = colmap[col.name].name
195 else:
196 fullcolmap[col.name] = col.name
197
198 for old, col in colmap.iteritems():
199 del table.c[old]
200 if col is not None:
201 table.append_column(col)
202
203 session.execute('ALTER TABLE "%s" RENAME TO "%s_old";' % (table.name, table.name))
204 table.create()
205 session.execute('INSERT INTO "%s" ("%s") SELECT "%s" FROM "%s_old";'
206 % (table.name, '", "'.join(fullcolmap.values()), '", "'.join(fullcolmap.keys()), table.name))
207 session.execute('DROP TABLE "%s_old";' % table.name)
208
209class Schema(Base):
210 __table__ = Table('schema', Base.metadata,
211 Column('id', Integer, primary_key=True),
212 Column('table', Unicode(32), unique=True, nullable=False),
213 Column('version', Integer, nullable=False),
214 useexisting=True)
215
216 # Upgrades to this table are probably going to be tricky
217 class SchemaSchema(VersionedSchema):
218 def upgrade_schema(self, sessionmaker):
219 session = sessionmaker()
220
221 if not session.bind.has_table(self.table.name):
222 metadata.bind = session.bind
223 self.table.kwargs['mysql_engine'] = 'InnoDB'
224 self.table.create()
225
226 schema = Schema(unicode(self.table.name), self.version)
227 session.save_or_update(schema)
228
229 session.flush()
230 session.close()
231
232 __table__.versioned_schema = SchemaSchema(__table__, 1)
233
234 def __init__(self, table, version=0):
235 self.table = table
236 self.version = version
237
238 def __repr__(self):
239 return '<Schema %s>' % self.table
8240
9class Identity(Base):241class Identity(Base):
10 __table__ = Table('identities', Base.metadata,242 __table__ = Table('identities', Base.metadata,
11 Column('id', Integer, primary_key=True),243 Column('id', Integer, primary_key=True),
12 Column('account_id', Integer, ForeignKey('accounts.id')),244 Column('account_id', Integer, ForeignKey('accounts.id')),
13 Column('source', Unicode(16), nullable=False),245 Column('source', Unicode(16), nullable=False),
14 Column('identity', Unicode(64), nullable=False),246 Column('identity', Unicode(64), nullable=False),
15 Column('created', DateTime, default=func.current_timestamp()),247 Column('created', DateTime, default=func.current_timestamp()),
16 UniqueConstraint('source', 'identity'),248 UniqueConstraint('source', 'identity'),
17 useexisting=True)249 useexisting=True)
250
251 __table__.versioned_schema = VersionedSchema(__table__, 1)
18252
19 def __init__(self, source, identity, account_id=None):253 def __init__(self, source, identity, account_id=None):
20 self.source = source254 self.source = source
@@ -26,12 +260,14 @@
26260
27class Attribute(Base):261class Attribute(Base):
28 __table__ = Table('account_attributes', Base.metadata,262 __table__ = Table('account_attributes', Base.metadata,
29 Column('id', Integer, primary_key=True),263 Column('id', Integer, primary_key=True),
30 Column('account_id', Integer, ForeignKey('accounts.id'), nullable=False),264 Column('account_id', Integer, ForeignKey('accounts.id'), nullable=False),
31 Column('name', Unicode(32), nullable=False),265 Column('name', Unicode(32), nullable=False),
32 Column('value', Unicode(128), nullable=False),266 Column('value', Unicode(128), nullable=False),
33 UniqueConstraint('account_id', 'name'),267 UniqueConstraint('account_id', 'name'),
34 useexisting=True)268 useexisting=True)
269
270 __table__.versioned_schema = VersionedSchema(__table__, 1)
35271
36 def __init__(self, name, value):272 def __init__(self, name, value):
37 self.name = name273 self.name = name
@@ -42,12 +278,14 @@
42278
43class Credential(Base):279class Credential(Base):
44 __table__ = Table('credentials', Base.metadata,280 __table__ = Table('credentials', Base.metadata,
45 Column('id', Integer, primary_key=True),281 Column('id', Integer, primary_key=True),
46 Column('account_id', Integer, ForeignKey('accounts.id'), nullable=False),282 Column('account_id', Integer, ForeignKey('accounts.id'), nullable=False),
47 Column('source', Unicode(16)),283 Column('source', Unicode(16)),
48 Column('method', Unicode(16), nullable=False),284 Column('method', Unicode(16), nullable=False),
49 Column('credential', Unicode(256), nullable=False),285 Column('credential', Unicode(256), nullable=False),
50 useexisting=True)286 useexisting=True)
287
288 __table__.versioned_schema = VersionedSchema(__table__, 1)
51289
52 def __init__(self, method, credential, source=None, account_id=None):290 def __init__(self, method, credential, source=None, account_id=None):
53 self.account_id = account_id291 self.account_id = account_id
@@ -57,13 +295,14 @@
57295
58class Permission(Base):296class Permission(Base):
59 __table__ = Table('permissions', Base.metadata,297 __table__ = Table('permissions', Base.metadata,
60 Column('id', Integer, primary_key=True),298 Column('id', Integer, primary_key=True),
61 Column('account_id', Integer, ForeignKey('accounts.id'), nullable=False),299 Column('account_id', Integer, ForeignKey('accounts.id'), nullable=False),
62 Column('name', Unicode(16), nullable=False),300 Column('name', Unicode(16), nullable=False),
63 Column('value', Unicode(4), nullable=False),301 Column('value', Unicode(4), nullable=False),
64 UniqueConstraint('account_id', 'name'),302 UniqueConstraint('account_id', 'name'),
65 useexisting=True)303 useexisting=True)
66304
305 __table__.versioned_schema = VersionedSchema(__table__, 1)
67306
68 def __init__(self, name=None, value=None, account_id=None):307 def __init__(self, name=None, value=None, account_id=None):
69 self.account_id = account_id308 self.account_id = account_id
@@ -72,9 +311,11 @@
72311
73class Account(Base):312class Account(Base):
74 __table__ = Table('accounts', Base.metadata,313 __table__ = Table('accounts', Base.metadata,
75 Column('id', Integer, primary_key=True),314 Column('id', Integer, primary_key=True),
76 Column('username', Unicode(32), unique=True, nullable=False),315 Column('username', Unicode(32), unique=True, nullable=False),
77 useexisting=True)316 useexisting=True)
317
318 __table__.versioned_schema = VersionedSchema(__table__, 1)
78319
79 identities = relation(Identity, backref='account')320 identities = relation(Identity, backref='account')
80 attributes = relation(Attribute)321 attributes = relation(Attribute)
@@ -87,4 +328,36 @@
87 def __repr__(self):328 def __repr__(self):
88 return '<Account %s>' % self.username329 return '<Account %s>' % self.username
89330
331def check_schema_versions(sessionmaker):
332 """Pass through all tables, log out of date ones,
333 and except if not all up to date"""
334
335 session = sessionmaker()
336 upgrades = []
337 for table in metadata.tables.itervalues():
338 if not hasattr(table, 'versioned_schema'):
339 log.error("Table %s is not versioned.", table.name)
340 continue
341
342 if not table.versioned_schema.is_up_to_date(session):
343 upgrades.append(table.name)
344
345 if not upgrades:
346 return
347
348 raise Exception(u"Tables %s are out of date. Run ibid-setup" % u", ".join(upgrades))
349
350def upgrade_schemas(sessionmaker):
351 "Pass through all tables and update schemas"
352
353 # Make sure schema table is created first
354 metadata.tables['schema'].versioned_schema.upgrade_schema(sessionmaker)
355
356 for table in metadata.tables.itervalues():
357 if not hasattr(table, 'versioned_schema'):
358 log.error("Table %s is not versioned.", table.name)
359 continue
360
361 table.versioned_schema.upgrade_schema(sessionmaker)
362
90# vi: set et sta sw=4 ts=4:363# vi: set et sta sw=4 ts=4:
91364
=== modified file 'ibid/plugins/factoid.py'
--- ibid/plugins/factoid.py 2009-03-17 14:40:03 +0000
+++ ibid/plugins/factoid.py 2009-04-13 19:07:30 +0000
@@ -10,7 +10,7 @@
10from ibid.plugins import Processor, match, handler, authorise, auth_responses, RPC10from ibid.plugins import Processor, match, handler, authorise, auth_responses, RPC
11from ibid.config import Option, IntOption11from ibid.config import Option, IntOption
12from ibid.plugins.identity import get_identities12from ibid.plugins.identity import get_identities
13from ibid.models import Base13from ibid.models import Base, VersionedSchema
1414
15help = {'factoids': u'Factoids are arbitrary pieces of information stored by a key. '15help = {'factoids': u'Factoids are arbitrary pieces of information stored by a key. '
16 u'Factoids beginning with a command such as "<action>" or "<reply>" will supress the "name verb value" output. '16 u'Factoids beginning with a command such as "<action>" or "<reply>" will supress the "name verb value" output. '
@@ -27,6 +27,8 @@
27 Column('time', DateTime, nullable=False, default=func.current_timestamp()),27 Column('time', DateTime, nullable=False, default=func.current_timestamp()),
28 useexisting=True)28 useexisting=True)
2929
30 __table__.versioned_schema = VersionedSchema(__table__, 1)
31
30 def __init__(self, name, identity_id, factoid_id=None):32 def __init__(self, name, identity_id, factoid_id=None):
31 self.name = name33 self.name = name
32 self.factoid_id = factoid_id34 self.factoid_id = factoid_id
@@ -44,6 +46,8 @@
44 Column('time', DateTime, nullable=False, default=func.current_timestamp()),46 Column('time', DateTime, nullable=False, default=func.current_timestamp()),
45 useexisting=True)47 useexisting=True)
4648
49 __table__.versioned_schema = VersionedSchema(__table__, 1)
50
47 def __init__(self, value, identity_id, factoid_id=None):51 def __init__(self, value, identity_id, factoid_id=None):
48 self.value = value52 self.value = value
49 self.factoid_id = factoid_id53 self.factoid_id = factoid_id
@@ -58,6 +62,8 @@
58 Column('time', DateTime, nullable=False, default=func.current_timestamp()),62 Column('time', DateTime, nullable=False, default=func.current_timestamp()),
59 useexisting=True)63 useexisting=True)
6064
65 __table__.versioned_schema = VersionedSchema(__table__, 1)
66
61 names = relation(FactoidName, cascade='all,delete', backref='factoid')67 names = relation(FactoidName, cascade='all,delete', backref='factoid')
62 values = relation(FactoidValue, cascade='all,delete', backref='factoid')68 values = relation(FactoidValue, cascade='all,delete', backref='factoid')
6369
6470
=== modified file 'ibid/plugins/feeds.py'
--- ibid/plugins/feeds.py 2009-03-11 11:11:04 +0000
+++ ibid/plugins/feeds.py 2009-04-13 19:07:30 +0000
@@ -12,7 +12,7 @@
1212
13import ibid13import ibid
14from ibid.plugins import Processor, match, authorise14from ibid.plugins import Processor, match, authorise
15from ibid.models import Base15from ibid.models import Base, VersionedSchema
16from ibid.utils import cacheable_download, get_html_parse_tree16from ibid.utils import cacheable_download, get_html_parse_tree
1717
18help = {'feeds': u'Displays articles from RSS and Atom feeds'}18help = {'feeds': u'Displays articles from RSS and Atom feeds'}
@@ -27,6 +27,8 @@
27 Column('identity_id', Integer, ForeignKey('identities.id'), nullable=False),27 Column('identity_id', Integer, ForeignKey('identities.id'), nullable=False),
28 Column('time', DateTime, nullable=False),28 Column('time', DateTime, nullable=False),
29 useexisting=True)29 useexisting=True)
30
31 __table__.versioned_schema = VersionedSchema(__table__, 1)
30 32
31 feed = None33 feed = None
32 entries = None34 entries = None
3335
=== modified file 'ibid/plugins/karma.py'
--- ibid/plugins/karma.py 2009-03-16 10:43:01 +0000
+++ ibid/plugins/karma.py 2009-04-13 19:07:30 +0000
@@ -7,7 +7,7 @@
7import ibid7import ibid
8from ibid.plugins import Processor, match, handler, authorise8from ibid.plugins import Processor, match, handler, authorise
9from ibid.config import Option, BoolOption, IntOption9from ibid.config import Option, BoolOption, IntOption
10from ibid.models import Base10from ibid.models import Base, VersionedSchema
1111
12help = {'karma': u'Keeps track of karma for people and things.'}12help = {'karma': u'Keeps track of karma for people and things.'}
1313
@@ -22,6 +22,8 @@
22 Column('time', DateTime, nullable=False, default=func.current_timestamp()),22 Column('time', DateTime, nullable=False, default=func.current_timestamp()),
23 useexisting=True)23 useexisting=True)
2424
25 __table__.versioned_schema = VersionedSchema(__table__, 1)
26
25 def __init__(self, subject):27 def __init__(self, subject):
26 self.subject = subject28 self.subject = subject
27 self.changes = 029 self.changes = 0
2830
=== modified file 'ibid/plugins/memo.py'
--- ibid/plugins/memo.py 2009-03-18 11:36:41 +0000
+++ ibid/plugins/memo.py 2009-04-13 19:07:30 +0000
@@ -10,7 +10,7 @@
10from ibid.config import Option10from ibid.config import Option
11from ibid.plugins.auth import permission11from ibid.plugins.auth import permission
12from ibid.plugins.identity import get_identities12from ibid.plugins.identity import get_identities
13from ibid.models import Base, Identity, Account13from ibid.models import Base, VersionedSchema, Identity, Account
14from ibid.utils import ago14from ibid.utils import ago
1515
16help = {'memo': u'Keeps messages for people.'}16help = {'memo': u'Keeps messages for people.'}
@@ -29,6 +29,8 @@
29 Column('time', DateTime, nullable=False, default=func.current_timestamp()),29 Column('time', DateTime, nullable=False, default=func.current_timestamp()),
30 useexisting=True)30 useexisting=True)
3131
32 __table__.versioned_schema = VersionedSchema(__table__, 1)
33
32 def __init__(self, from_id, to_id, memo, private=False):34 def __init__(self, from_id, to_id, memo, private=False):
33 self.from_id = from_id35 self.from_id = from_id
34 self.to_id = to_id36 self.to_id = to_id
3537
=== modified file 'ibid/plugins/seen.py'
--- ibid/plugins/seen.py 2009-03-08 13:16:28 +0000
+++ ibid/plugins/seen.py 2009-04-13 19:07:30 +0000
@@ -7,7 +7,7 @@
7import ibid7import ibid
8from ibid.plugins import Processor, match8from ibid.plugins import Processor, match
9from ibid.config import Option9from ibid.config import Option
10from ibid.models import Base, Identity, Account10from ibid.models import Base, VersionedSchema, Identity, Account,
11from ibid.utils import ago11from ibid.utils import ago
1212
13help = {'seen': u'Records when people were last seen.'}13help = {'seen': u'Records when people were last seen.'}
@@ -24,6 +24,8 @@
24 UniqueConstraint('identity_id', 'type'),24 UniqueConstraint('identity_id', 'type'),
25 useexisting=True)25 useexisting=True)
2626
27 __table__.versioned_schema = VersionedSchema(__table__, 1)
28
27 identity = relation('Identity')29 identity = relation('Identity')
2830
29 def __init__(self, identity_id=None, type='message', channel=None, value=None):31 def __init__(self, identity_id=None, type='message', channel=None, value=None):
3032
=== modified file 'ibid/plugins/url.py'
--- ibid/plugins/url.py 2009-03-25 14:58:06 +0000
+++ ibid/plugins/url.py 2009-04-13 19:07:30 +0000
@@ -9,7 +9,7 @@
9import ibid9import ibid
10from ibid.plugins import Processor, match, handler10from ibid.plugins import Processor, match, handler
11from ibid.config import Option11from ibid.config import Option
12from ibid.models import Base12from ibid.models import Base, VersionedSchema
13from ibid.utils import get_html_parse_tree13from ibid.utils import get_html_parse_tree
1414
15help = {'url': u'Captures URLs seen in channel to database and/or to delicious, and shortens and lengthens URLs'}15help = {'url': u'Captures URLs seen in channel to database and/or to delicious, and shortens and lengthens URLs'}
@@ -25,6 +25,8 @@
25 Column('time', DateTime, nullable=False),25 Column('time', DateTime, nullable=False),
26 useexisting=True)26 useexisting=True)
2727
28 __table__.versioned_schema = VersionedSchema(__table__, 1)
29
28 def __init__(self, url, channel, identity_id):30 def __init__(self, url, channel, identity_id):
29 self.url = url31 self.url = url
30 self.channel = channel32 self.channel = channel
3133
=== modified file 'scripts/ibid-setup'
--- scripts/ibid-setup 2009-03-16 16:52:51 +0000
+++ scripts/ibid-setup 2009-04-13 17:36:47 +0000
@@ -13,7 +13,7 @@
1313
14from ibid.plugins.auth import hash14from ibid.plugins.auth import hash
15from ibid.config import FileConfig15from ibid.config import FileConfig
16from ibid.models import Account, Identity, Permission, Credential, metadata16from ibid.models import Account, Identity, Permission, Credential, metadata, upgrade_schemas
1717
18for module in getModule('ibid.plugins').iterModules():18for module in getModule('ibid.plugins').iterModules():
19 try:19 try:
@@ -63,7 +63,8 @@
63 copyfileobj(resource_stream('ibid', 'logging.ini'), open('logging.ini', 'w'))63 copyfileobj(resource_stream('ibid', 'logging.ini'), open('logging.ini', 'w'))
6464
65engine = create_engine(config.databases['ibid'], encoding='utf-8', convert_unicode=True, assert_unicode=True)65engine = create_engine(config.databases['ibid'], encoding='utf-8', convert_unicode=True, assert_unicode=True)
66metadata.create_all(engine)66Session = sessionmaker(bind=engine, transactional=False)
67upgrade_schemas(Session)
6768
68print u'Database tables created'69print u'Database tables created'
6970
@@ -77,8 +78,8 @@
77 print 'Password do not match'78 print 'Password do not match'
78 exit(1)79 exit(1)
7980
80Session = sessionmaker(bind=engine)
81session = Session()81session = Session()
82session.begin()
82account = Account(identity)83account = Account(identity)
83identity = Identity(source, identity)84identity = Identity(source, identity)
84account.identities.append(identity)85account.identities.append(identity)

Subscribers

People subscribed via source and target branches