Author: luke
Date: 2007-04-25 10:57:47 -0600 (Wed, 25 Apr 2007)
New Revision: 2604
Added:
SQLObject/branches/cache-deps-on-views/sqlobject/materialized/dependency_events.py
SQLObject/branches/cache-deps-on-views/sqlobject/materialized/materialized_events.py
Modified:
SQLObject/branches/cache-deps-on-views/sqlobject/main.py
SQLObject/branches/cache-deps-on-views/sqlobject/materialized/__init__.py
SQLObject/branches/cache-deps-on-views/sqlobject/materialized/dependency.py
SQLObject/branches/cache-deps-on-views/sqlobject/materialized/materialized.py
SQLObject/branches/cache-deps-on-views/sqlobject/materialized/tests/test_materialized.py
SQLObject/branches/cache-deps-on-views/sqlobject/sqlbuilder.py
SQLObject/branches/cache-deps-on-views/sqlobject/views.py
Log:
Checkpoint for materialized, working partially with ViewSQLObject
Modified: SQLObject/branches/cache-deps-on-views/sqlobject/main.py
===================================================================
--- SQLObject/branches/cache-deps-on-views/sqlobject/main.py 2007-04-25 16:56:17 UTC (rev 2603)
+++ SQLObject/branches/cache-deps-on-views/sqlobject/main.py 2007-04-25 16:57:47 UTC (rev 2604)
@@ -934,7 +934,7 @@
try:
val = cls(_SO_fetch_no_create=1)
val._SO_validatorState = SQLObjectState(val)
- val._init(id, connection, selectResults)
+ val._init(id, connection=connection, selectResults=selectResults)
cache.put(id, cls, val)
finally:
cache.finishPut(cls)
Modified: SQLObject/branches/cache-deps-on-views/sqlobject/materialized/__init__.py
===================================================================
--- SQLObject/branches/cache-deps-on-views/sqlobject/materialized/__init__.py 2007-04-25 16:56:17 UTC (rev 2603)
+++ SQLObject/branches/cache-deps-on-views/sqlobject/materialized/__init__.py 2007-04-25 16:57:47 UTC (rev 2604)
@@ -1,2 +1,4 @@
from dependency import *
-from materialized import *
\ No newline at end of file
+import dependency_events
+from materialized import *
+import materialized_events
\ No newline at end of file
Modified: SQLObject/branches/cache-deps-on-views/sqlobject/materialized/dependency.py
===================================================================
--- SQLObject/branches/cache-deps-on-views/sqlobject/materialized/dependency.py 2007-04-25 16:56:17 UTC (rev 2603)
+++ SQLObject/branches/cache-deps-on-views/sqlobject/materialized/dependency.py 2007-04-25 16:57:47 UTC (rev 2604)
@@ -1,23 +1,10 @@
from sqlobject import declarative
from sqlobject import sqlbuilder
-from sqlobject.events import *
-from sqlobject.include.pydispatch import dispatcher
from sqlobject import classregistry
from sqlobject import SQLObject
-from operator import isCallable
import inspect
-def _processDependentOn(new_class_name, bases, new_attrs, post_funcs, early_funcs):
- def f(cls):
- for name, value in new_attrs.items():
- if hasattr(value, '_dependentOn'):
- for dep, maker, source in value._dependentOn:
- dep.add(maker(cls, name, value),source)
- early_funcs.append(f)
-
-listen(_processDependentOn, dispatcher.Any, ClassCreateSignal)
-
class depFromClsAttr(object):
def __call__(self, cls, name, value):
return (cls.__name__, name)
@@ -80,9 +67,12 @@
factory = kw.pop('factory', None)
if factory is None:
factory = self.DependencyClass.DecoratorFactory()
+ if not isinstance(source[0], (list, tuple)):
+ source = (source,)
def decorate(func):
depOn = getattr(func, '_dependentOn', [])
- depOn.append((self, factory, source))
+ for s in source:
+ depOn.append((self, factory, s))
setattr(func, '_dependentOn', depOn)
return func
return decorate
@@ -149,26 +139,11 @@
_toProcess = self.instancesToProcess(inst, attrs)
for (cls, attr), insts in _toProcess.iteritems():
for inst in insts:
- inst._SO_updateCacheObject([attr])
- self.process(inst, [attr])
+ changed = inst._SO_updateCacheObject([attr])
+ if changed:
+ self.process(inst, [attr])
dep = SQLDependencyManager()
dependentOn = dep.dependentOn
-
-
-def _processDepsOnChange(inst, kwargs):
- dep.process(inst, kwargs.keys())
-
-listen(_processDepsOnChange, SQLObject, RowUpdatedSignal)
-listen(_processDepsOnChange, SQLObject, RowCreatedSignal)
-
-def _processDepsOnDelete(inst, post_funcs):
- attrs = ['id'] + inst.sqlmeta.columns.keys()
- toProcess = dep.instancesToProcess(inst, attrs)
- def f(inst, toProcess=toProcess):
- dep.process(inst, attrs, _toProcess=toProcess)
- if toProcess:
- post_funcs.append(f)
-listen(_processDepsOnDelete, SQLObject, RowDestroySignal)
\ No newline at end of file
Added: SQLObject/branches/cache-deps-on-views/sqlobject/materialized/dependency_events.py
===================================================================
--- SQLObject/branches/cache-deps-on-views/sqlobject/materialized/dependency_events.py (rev 0)
+++ SQLObject/branches/cache-deps-on-views/sqlobject/materialized/dependency_events.py 2007-04-25 16:57:47 UTC (rev 2604)
@@ -0,0 +1,28 @@
+from sqlobject import events
+from sqlobject import SQLObject
+from dependency import dep
+
+def _processDependentOn(new_class_name, bases, new_attrs, post_funcs, early_funcs):
+ def f(cls):
+ for name, value in new_attrs.items():
+ if hasattr(value, '_dependentOn'):
+ for dep, maker, source in value._dependentOn:
+ dep.add(maker(cls, name, value),source)
+ early_funcs.append(f)
+
+events.listen(_processDependentOn, events.dispatcher.Any, events.ClassCreateSignal)
+
+def _processDepsOnChange(inst, kwargs):
+ dep.process(inst, kwargs.keys())
+
+events.listen(_processDepsOnChange, SQLObject, events.RowUpdatedSignal)
+events.listen(_processDepsOnChange, SQLObject, events.RowCreatedSignal)
+
+def _processDepsOnDelete(inst, post_funcs):
+ attrs = ['id'] + inst.sqlmeta.columns.keys()
+ toProcess = dep.instancesToProcess(inst, attrs)
+ def f(inst, toProcess=toProcess):
+ dep.process(inst, attrs, _toProcess=toProcess)
+ if toProcess:
+ post_funcs.append(f)
+events.listen(_processDepsOnDelete, SQLObject, events.RowDestroySignal)
\ No newline at end of file
Modified: SQLObject/branches/cache-deps-on-views/sqlobject/materialized/materialized.py
===================================================================
--- SQLObject/branches/cache-deps-on-views/sqlobject/materialized/materialized.py 2007-04-25 16:56:17 UTC (rev 2603)
+++ SQLObject/branches/cache-deps-on-views/sqlobject/materialized/materialized.py 2007-04-25 16:57:47 UTC (rev 2604)
@@ -1,8 +1,5 @@
from sqlobject import SQLObject, SQLObjectNotFound, sqlmeta as _sqlmeta
-from sqlobject import events, col
-from sqlobject.main import makeProperties
-from dependency import dep
-from sqlobject.events import *
+from sqlobject import col
class materialized_sqlmeta(_sqlmeta):
cachedIn = None
@@ -20,7 +17,13 @@
idType = cls.idType
cls.cacheClass = type(cls.soClass.__name__+'Cache', (SQLObject,), {'sqlmeta': cache_sqlmeta})
-
+
+ def addCacheColumn(self, value):
+ self.cachedAttributes[value.name] = value
+ self.cacheClass.sqlmeta.addColumn(value.colType(name=value.name, default=None))
+ self.cacheClass.sqlmeta.addColumn(col.BoolCol(name=value.name+'_dirty', default=True))
+ addCacheColumn = classmethod(addCacheColumn)
+
setClass = classmethod(setClass)
class MaterializedSQLObject(SQLObject):
@@ -37,31 +40,22 @@
def _SO_updateCacheObject(self, attrs):
+ changed = []
for attr in attrs:
cacheAttr = self.sqlmeta.cachedAttributes.get(attr, None)
if cacheAttr:
new_value = cacheAttr.func(self)
- self._SO_cacheObject.set(**{attr+'_dirty': False,
- attr: new_value})
+ if new_value != getattr(self._SO_cacheObject, attr):
+ changed.append(attr)
+ self._SO_cacheObject.set(**{attr+'_dirty': False,
+ attr: new_value})
+ else:
+ # If it's not cached, assume descendents should be notified regardless.
+ # Currently this should be mostly for joins, if we decide to cache joins
+ # then they would appear changed in most cases here anyways (add, delete).
+ changed.append(attr)
+ return changed
-def _addColumn(cls, connection, column_name, column_definition, changeSchema, post_funcs):
- ''' for automatically adding dependencies to foreign keys'''
- def f(cls, col):
- if col.foreignKey:
- dep.add((cls.__name__, col.name), (col.foreignKey, 'id', lambda cls=cls,col=col: getattr(cls.q, col.origName)))
- post_funcs.append(f)
-
-events.listen(_addColumn, MaterializedSQLObject, events.AddColumnSignal)
-
-def _addJoin(cls, join_name, join_definition, post_funcs):
- ''' for automatically adding dependencies to joins'''
- def f(cls, join):
- dep.add((cls.__name__, join.joinMethodName), (join.otherClassName, 'id', lambda cls=cls,join=join: getattr(cls.q, join.joinMethodName)))
- post_funcs.append(f)
-
-events.listen(_addJoin, MaterializedSQLObject, events.AddJoinSignal)
-
-
class MaterializedAttr(object):
def __init__(self, func, colType, name=None):
self.func = func
@@ -89,15 +83,3 @@
def decorate(func):
return MaterializedAttr(func, colType, name=name)
return decorate
-
-
-def _addColumnsToCacheClass(new_class_name, bases, new_attrs, post_funcs, early_funcs):
- def f(cls):
- for name, value in new_attrs.items():
- if isinstance(value, MaterializedAttr):
- cls.sqlmeta.cachedAttributes[value.name] = value
- cls.sqlmeta.cacheClass.sqlmeta.addColumn(value.colType(name=value.name, default=None))
- cls.sqlmeta.cacheClass.sqlmeta.addColumn(col.BoolCol(name=value.name+'_dirty', default=True))
- post_funcs.extend((f,makeProperties))
-
-listen(_addColumnsToCacheClass, MaterializedSQLObject, ClassCreateSignal)
Added: SQLObject/branches/cache-deps-on-views/sqlobject/materialized/materialized_events.py
===================================================================
--- SQLObject/branches/cache-deps-on-views/sqlobject/materialized/materialized_events.py (rev 0)
+++ SQLObject/branches/cache-deps-on-views/sqlobject/materialized/materialized_events.py 2007-04-25 16:57:47 UTC (rev 2604)
@@ -0,0 +1,39 @@
+from materialized import MaterializedSQLObject, MaterializedAttr
+from dependency import dep
+from sqlobject import events, derived
+from sqlobject.main import makeProperties
+
+####
+# auto from columns
+
+def _addColumn(cls, connection, column_name, column_definition, changeSchema, post_funcs):
+ ''' for automatically adding dependencies to foreign keys'''
+ def f(cls, col):
+ if col.foreignKey:
+ dep.add((cls.__name__, col.name), (col.foreignKey, 'id', lambda cls=cls,col=col: getattr(cls.q, col.origName)))
+ if col.derived:
+ pass
+ post_funcs.append(f)
+
+events.listen(_addColumn, MaterializedSQLObject, events.AddColumnSignal)
+
+def _addJoin(cls, join_name, join_definition, post_funcs):
+ ''' for automatically adding dependencies to joins'''
+ def f(cls, join):
+ dep.add((cls.__name__, join.joinMethodName), (join.otherClassName, 'id', lambda cls=cls,join=join: getattr(cls.q, join.joinMethodName)))
+ post_funcs.append(f)
+
+events.listen(_addJoin, MaterializedSQLObject, events.AddJoinSignal)
+
+####
+# cachedAs
+
+def _addColumnsToCacheClass(new_class_name, bases, new_attrs, post_funcs, early_funcs):
+ def f(cls):
+ for name, value in new_attrs.items():
+ if isinstance(value, MaterializedAttr):
+ cls.sqlmeta.addCacheColumn(value)
+ post_funcs.extend((f,makeProperties))
+
+events.listen(_addColumnsToCacheClass, MaterializedSQLObject, events.ClassCreateSignal)
+
Modified: SQLObject/branches/cache-deps-on-views/sqlobject/materialized/tests/test_materialized.py
===================================================================
--- SQLObject/branches/cache-deps-on-views/sqlobject/materialized/tests/test_materialized.py 2007-04-25 16:56:17 UTC (rev 2603)
+++ SQLObject/branches/cache-deps-on-views/sqlobject/materialized/tests/test_materialized.py 2007-04-25 16:57:47 UTC (rev 2604)
@@ -63,7 +63,7 @@
def _get_name3(self):
''' dep on dep '''
return self.name + self.detail
-
+
def setup_module(mod):
setupClass([MaterializedOne, MaterializedTwo, MaterializedOne.sqlmeta.cacheClass, MaterializedTwo.sqlmeta.cacheClass])
mod.ones = inserts(MaterializedOne, (('S',),
Modified: SQLObject/branches/cache-deps-on-views/sqlobject/sqlbuilder.py
===================================================================
--- SQLObject/branches/cache-deps-on-views/sqlobject/sqlbuilder.py 2007-04-25 16:56:17 UTC (rev 2603)
+++ SQLObject/branches/cache-deps-on-views/sqlobject/sqlbuilder.py 2007-04-25 16:57:47 UTC (rev 2604)
@@ -383,27 +383,43 @@
if attr.startswith('__'):
raise AttributeError
if attr == 'id':
- return self.FieldClass(self.tableName, self.soClass.sqlmeta.idName, attr)
+ return self._getattrFromID(attr)
elif attr+'ID' in self.soClass.sqlmeta.columns:
column = self.soClass.sqlmeta.columns[attr+'ID']
- return getattr(self, column.name)==getattr(self.soClass, '_SO_class_'+column.foreignKey).q.id
+ return self._getattrFromForeignKey(column, attr)
elif attr in [x.joinMethodName for x in self.soClass.sqlmeta.joins]:
join = [x for x in self.soClass.sqlmeta.joins if x.joinMethodName == attr][0]
- if hasattr(join, 'otherColumn'):
- return AND(join.otherClass.q.id == Field(join.intermediateTable, join.otherColumn),
- Field(join.intermediateTable, join.joinColumn) == self.soClass.q.id)
- else:
- return getattr(join.otherClass.q, join.joinColumn)==self.soClass.q.id
+ return self._getattrFromJoin(join, attr)
elif attr not in self.soClass.sqlmeta.columns:
raise AttributeError("%s instance has no attribute '%s'" % (self.soClass.__name__, attr))
else:
column = self.soClass.sqlmeta.columns[attr]
if hasattr(column, "dbEncoding"):
- return self.UnicodeFieldClass(self.tableName, column.dbName,
- attr, column)
+ return self._getattrFromUnicodeColumn(column, attr)
else:
- return self.FieldClass(self.tableName, column.dbName, attr)
+ return self._getattrFromColumn(column, attr)
+ def _getattrFromID(self, attr):
+ return self.FieldClass(self.tableName, self.soClass.sqlmeta.idName, attr)
+
+ def _getattrFromForeignKey(self, column, attr):
+ ret = getattr(self, column.name)==getattr(self.soClass, '_SO_class_'+column.foreignKey).q.id
+ print column
+ return ret
+
+ def _getattrFromJoin(self, join, attr):
+ if hasattr(join, 'otherColumn'):
+ return AND(join.otherClass.q.id == Field(join.intermediateTable, join.otherColumn),
+ Field(join.intermediateTable, join.joinColumn) == self.soClass.q.id)
+ else:
+ return getattr(join.otherClass.q, join.joinColumn)==self.soClass.q.id
+
+ def _getattrFromColumn(self, column, attr):
+ return self.FieldClass(self.tableName, column.dbName, attr)
+
+ def _getattrFromUnicodeColumn(self, column, attr):
+ return self.UnicodeFieldClass(self.tableName, column.dbName, attr, column)
+
class TableSpace:
TableClass = Table
Modified: SQLObject/branches/cache-deps-on-views/sqlobject/views.py
===================================================================
--- SQLObject/branches/cache-deps-on-views/sqlobject/views.py 2007-04-25 16:56:17 UTC (rev 2603)
+++ SQLObject/branches/cache-deps-on-views/sqlobject/views.py 2007-04-25 16:57:47 UTC (rev 2604)
@@ -32,25 +32,18 @@
def __getattr__(self, attr):
if attr == 'sqlmeta':
raise AttributeError
- alias = self.soClass.sqlmeta.alias
- if attr.startswith('__'):
- raise AttributeError
- if attr == 'id':
- return self.FieldClass(alias, self.tableName, 'id', attr)
- elif attr not in self.soClass.sqlmeta.columns:
- raise AttributeError("%s instance has no attribute '%s'" % (self.soClass.__name__, attr))
- else:
- column = self.soClass.sqlmeta.columns[attr]
- if hasattr(column, "dbEncoding"):
- return self.UnicodeFieldClass(alias, self.tableName, column.name,
- attr, column)
- else:
- return self.FieldClass(alias, self.tableName, column.name, attr)
+ return SQLObjectTable.__getattr__(self, attr)
-class ViewSQLObjectMeta(sqlmeta):
- pass
+ def _getattrFromID(self, attr):
+ return self.FieldClass(self.soClass.sqlmeta.alias, self.tableName, 'id', attr)
+ def _getattrFromColumn(self, column, attr):
+ return self.FieldClass(self.soClass.sqlmeta.alias, self.tableName, column.name, attr)
+ def _getattrFromUnicodeColumn(self, column, attr):
+ return self.UnicodeFieldClass(self.soClass.sqlmeta.alias, self.tableName, column.name, attr, column)
+
+
class ViewSQLObject(SQLObject):
'''A SQLObject class that derives all it's values from other SQLObject classes.
Columns on subclasses should use SQLBuilder constructs for dbName,
@@ -61,9 +54,6 @@
See test_views.py for simple examples.
'''
- class sqlmeta(ViewSQLObjectMeta):
- pass
-
def __classinit__(cls, new_attrs):
SQLObject.__classinit__(cls, new_attrs)
# like is_base
|