sqlobject-cvs Mailing List for SQLObject (Page 188)
SQLObject is a Python ORM.
Brought to you by:
ianbicking,
phd
You can subscribe to this list here.
2003 |
Jan
|
Feb
|
Mar
(9) |
Apr
(74) |
May
(29) |
Jun
(16) |
Jul
(28) |
Aug
(10) |
Sep
(57) |
Oct
(9) |
Nov
(29) |
Dec
(12) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2004 |
Jan
(7) |
Feb
(14) |
Mar
(6) |
Apr
(3) |
May
(12) |
Jun
(34) |
Jul
(9) |
Aug
(29) |
Sep
(22) |
Oct
(2) |
Nov
(15) |
Dec
(52) |
2005 |
Jan
(47) |
Feb
(78) |
Mar
(14) |
Apr
(35) |
May
(33) |
Jun
(16) |
Jul
(26) |
Aug
(63) |
Sep
(40) |
Oct
(96) |
Nov
(96) |
Dec
(123) |
2006 |
Jan
(159) |
Feb
(144) |
Mar
(64) |
Apr
(31) |
May
(88) |
Jun
(48) |
Jul
(16) |
Aug
(64) |
Sep
(87) |
Oct
(92) |
Nov
(56) |
Dec
(76) |
2007 |
Jan
(94) |
Feb
(103) |
Mar
(126) |
Apr
(123) |
May
(85) |
Jun
(11) |
Jul
(130) |
Aug
(47) |
Sep
(65) |
Oct
(70) |
Nov
(12) |
Dec
(11) |
2008 |
Jan
(30) |
Feb
(55) |
Mar
(88) |
Apr
(20) |
May
(50) |
Jun
|
Jul
(38) |
Aug
(1) |
Sep
(9) |
Oct
(5) |
Nov
(6) |
Dec
(39) |
2009 |
Jan
(8) |
Feb
(16) |
Mar
(3) |
Apr
(33) |
May
(44) |
Jun
(1) |
Jul
(10) |
Aug
(33) |
Sep
(74) |
Oct
(22) |
Nov
|
Dec
(15) |
2010 |
Jan
(28) |
Feb
(22) |
Mar
(46) |
Apr
(29) |
May
(1) |
Jun
(1) |
Jul
(27) |
Aug
(8) |
Sep
(5) |
Oct
(33) |
Nov
(24) |
Dec
(41) |
2011 |
Jan
(4) |
Feb
(12) |
Mar
(35) |
Apr
(29) |
May
(19) |
Jun
(16) |
Jul
(32) |
Aug
(25) |
Sep
(5) |
Oct
(11) |
Nov
(21) |
Dec
(12) |
2012 |
Jan
(3) |
Feb
(4) |
Mar
(20) |
Apr
(4) |
May
(25) |
Jun
(13) |
Jul
|
Aug
|
Sep
(2) |
Oct
(25) |
Nov
(9) |
Dec
(1) |
2013 |
Jan
(6) |
Feb
(8) |
Mar
|
Apr
(10) |
May
(31) |
Jun
(7) |
Jul
(18) |
Aug
(33) |
Sep
(4) |
Oct
(16) |
Nov
|
Dec
(27) |
2014 |
Jan
(2) |
Feb
|
Mar
|
Apr
(11) |
May
(39) |
Jun
(8) |
Jul
(11) |
Aug
(4) |
Sep
|
Oct
(27) |
Nov
|
Dec
(71) |
2015 |
Jan
(17) |
Feb
(47) |
Mar
(33) |
Apr
|
May
|
Jun
(9) |
Jul
(7) |
Aug
|
Sep
|
Oct
|
Nov
|
Dec
(8) |
2016 |
Jan
(4) |
Feb
(4) |
Mar
|
Apr
|
May
(12) |
Jun
(7) |
Jul
(9) |
Aug
(31) |
Sep
(8) |
Oct
(3) |
Nov
(15) |
Dec
(1) |
2017 |
Jan
(13) |
Feb
(7) |
Mar
(14) |
Apr
(8) |
May
(10) |
Jun
(4) |
Jul
(2) |
Aug
(1) |
Sep
|
Oct
(8) |
Nov
(4) |
Dec
(5) |
2018 |
Jan
(2) |
Feb
(8) |
Mar
|
Apr
(4) |
May
|
Jun
(6) |
Jul
|
Aug
(1) |
Sep
|
Oct
|
Nov
(1) |
Dec
|
2019 |
Jan
(1) |
Feb
(16) |
Mar
(1) |
Apr
(3) |
May
(5) |
Jun
(1) |
Jul
|
Aug
|
Sep
(2) |
Oct
|
Nov
(1) |
Dec
(3) |
2020 |
Jan
|
Feb
|
Mar
|
Apr
(1) |
May
(1) |
Jun
|
Jul
|
Aug
(1) |
Sep
|
Oct
(2) |
Nov
|
Dec
(2) |
2021 |
Jan
|
Feb
(2) |
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(1) |
Nov
(1) |
Dec
|
2022 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
(6) |
Oct
(1) |
Nov
(1) |
Dec
(4) |
2023 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
(1) |
Aug
(3) |
Sep
(2) |
Oct
(2) |
Nov
(4) |
Dec
|
2024 |
Jan
|
Feb
(2) |
Mar
|
Apr
|
May
|
Jun
|
Jul
(1) |
Aug
|
Sep
(1) |
Oct
|
Nov
|
Dec
(9) |
2025 |
Jan
|
Feb
(4) |
Mar
(2) |
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: <ian...@us...> - 2003-05-30 02:49:39
|
Update of /cvsroot/sqlobject/SQLObject/SQLObject In directory sc8-pr-cvs1:/tmp/cvs-serv3787 Modified Files: Join.py SQLObject.py Log Message: * More addNeedSet jazz * foreignKey objects inherit the connection Index: Join.py =================================================================== RCS file: /cvsroot/sqlobject/SQLObject/SQLObject/Join.py,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** Join.py 26 May 2003 21:48:54 -0000 1.1 --- Join.py 30 May 2003 02:22:51 -0000 1.2 *************** *** 94,108 **** intermediateTable=None, **kw): SOMultipleJoin.__init__(self, **kw) ! if not otherColumn: ! self.otherColumn = self.soClass._style.pythonClassToDBTableReference(self.otherClassName) ! else: ! self.otherColumn = otherColumn ! if not intermediateTable: names = [self.soClass._table, ! self.soClass._style.pythonClassToDBTable(self.otherClassName)] names.sort() self.intermediateTable = '%s_%s' % (names[0], names[1]) ! else: ! self.intermediateTable = intermediateTable def hasIntermediateTable(self): --- 94,111 ---- intermediateTable=None, **kw): SOMultipleJoin.__init__(self, **kw) ! self.intermediateTable = intermediateTable ! self.otherColumn = otherColumn ! SQLObject.addNeedSet(self, self.otherClassName, ! self.soClass._registry, '_setOtherClass') ! ! def _setOtherClass(self, otherClass): ! if not self.intermediateTable: names = [self.soClass._table, ! otherClass._table] names.sort() self.intermediateTable = '%s_%s' % (names[0], names[1]) ! if not self.otherColumn: ! self.otherColumn = self.soClass._style.tableReference(otherClass._table) ! def hasIntermediateTable(self): Index: SQLObject.py =================================================================== RCS file: /cvsroot/sqlobject/SQLObject/SQLObject/SQLObject.py,v retrieving revision 1.41 retrieving revision 1.42 diff -C2 -d -r1.41 -r1.42 *** SQLObject.py 30 May 2003 02:18:45 -0000 1.41 --- SQLObject.py 30 May 2003 02:22:51 -0000 1.42 *************** *** 727,730 **** --- 727,732 ---- if id is None: return None + elif self._SO_perConnection: + return joinClass(id, connection=self._connection) else: return joinClass(id) |
From: <ian...@us...> - 2003-05-30 02:39:32
|
Update of /cvsroot/sqlobject/SQLObject/docs In directory sc8-pr-cvs1:/tmp/cvs-serv2648 Modified Files: Authors.txt News.txt Log Message: Noted bugfix Added author attribution Index: Authors.txt =================================================================== RCS file: /cvsroot/sqlobject/SQLObject/docs/Authors.txt,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** Authors.txt 19 Apr 2003 00:02:57 -0000 1.1 --- Authors.txt 30 May 2003 02:20:22 -0000 1.2 *************** *** 7,11 **** Contributions have been made by: ! Frank Barknecht <fb...@fo...> ! Bud P. Bruegger <bu...@si...> ! David M. Cook <da...@da...> --- 7,12 ---- Contributions have been made by: ! * Frank Barknecht <fb...@fo...> ! * Bud P. Bruegger <bu...@si...> ! * David M. Cook <da...@da...> ! * Luke Opperman <lu...@me...> Index: News.txt =================================================================== RCS file: /cvsroot/sqlobject/SQLObject/docs/News.txt,v retrieving revision 1.6 retrieving revision 1.7 diff -C2 -d -r1.6 -r1.7 *** News.txt 25 May 2003 06:03:45 -0000 1.6 --- News.txt 30 May 2003 02:20:22 -0000 1.7 *************** *** 24,27 **** --- 24,29 ---- _columns = [Col('someColumn')] + Ditto joins. + * Cache objects have a clear method, which empties all objects. However, weak references to objects *are* maintained, so the *************** *** 125,128 **** --- 127,133 ---- * Trying to use ``Col('id')`` or ``id = Col()`` will raise an exception, instead of just acting funky. + + * ``ForeignKey`` columns return None if the associated column is + NULL in the database (used to just act weird). Internal |
From: <ian...@us...> - 2003-05-30 02:19:34
|
Update of /cvsroot/sqlobject/SQLObject/SQLObject In directory sc8-pr-cvs1:/tmp/cvs-serv1697 Modified Files: SQLObject.py Log Message: * Minor fixed to addNeedSet stuff * foreignKey columns return None when the associated ID column is NULL Index: SQLObject.py =================================================================== RCS file: /cvsroot/sqlobject/SQLObject/SQLObject/SQLObject.py,v retrieving revision 1.40 retrieving revision 1.41 diff -C2 -d -r1.40 -r1.41 *** SQLObject.py 26 May 2003 21:48:54 -0000 1.40 --- SQLObject.py 30 May 2003 02:18:45 -0000 1.41 *************** *** 85,104 **** cls = findClass(needClass, registry=registryName) for obj, attr in q: ! setattr(obj, attr, cls) except KeyError: newNeedClassDict[needClass] = q needSet[registryName] = newNeedClassDict - - - - def addNeedSet(needClass, setCls): - needSet.setdefault(needClass.__name__, []).append( - (needClass.__name__, setCls)) - def addNeedSet(obj, setCls, registry, attr): try: cls = findClass(setCls, registry=registry) ! setattr(obj, attr, cls) return except KeyError: --- 85,103 ---- cls = findClass(needClass, registry=registryName) for obj, attr in q: ! if callable(getattr(obj, attr, None)): ! getattr(obj, attr)(cls) ! else: ! setattr(obj, attr, cls) except KeyError: newNeedClassDict[needClass] = q needSet[registryName] = newNeedClassDict def addNeedSet(obj, setCls, registry, attr): try: cls = findClass(setCls, registry=registry) ! if callable(getattr(obj, attr, None)): ! getattr(obj, attr)(cls) ! else: ! setattr(obj, attr, cls) return except KeyError: *************** *** 470,474 **** # self._SO_class_className is a reference # to the class in question. ! getter = eval('lambda self: self._SO_class_%s(self.%s)' % (column.foreignKey, instanceName(name))) else: # Same non-caching version as above. --- 469,473 ---- # self._SO_class_className is a reference # to the class in question. ! getter = eval('lambda self: self._SO_foreignKey(self.%s and self._SO_class_%s)' % (column.foreignKey, instanceName(name))) else: # Same non-caching version as above. *************** *** 724,727 **** --- 723,732 ---- % (self.__class__.__name__, self.id) return results[0] + + def _SO_foreignKey(self, id, joinClass): + if id is None: + return None + else: + return joinClass(id) def new(cls, **kw): |
From: <ian...@us...> - 2003-05-26 21:48:58
|
Update of /cvsroot/sqlobject/SQLObject/SQLObject In directory sc8-pr-cvs1:/tmp/cvs-serv3682 Modified Files: Col.py SQLObject.py __init__.py Added Files: Join.py Log Message: * Moved joins to their own module * Created SOJoin/Join distinction * Joins can be defined like columns, i.e., without using _joins. --- NEW FILE: Join.py --- from SQLBuilder import NoDefault import Style import SQLObject __all__ = ['MultipleJoin', 'RelatedJoin'] class Join(object): def __init__(self, otherClass=None, **kw): kw['otherClass'] = otherClass kw['joinDef'] = self self.kw = kw def setName(self, value): assert self.kw.get('joinMethodName') is None or self.kw['joinMethodName'] == value, "You have already given an explicit joinMethodName (%s), and you are now setting it to %s" % (self.kw['joinMethodName'], value) self.kw['joinMethodName'] = value def withClass(self, soClass): return self.baseClass(soClass=soClass, **self.kw) # A join is separate from a foreign key, i.e., it is # many-to-many, or one-to-many where the *other* class # has the foreign key. class SOJoin(object): def __init__(self, soClass=None, otherClass=None, joinColumn=None, joinMethodName=None, orderBy=NoDefault, joinDef=None): self.soClass = soClass self.otherClassName = otherClass SQLObject.addNeedSet(self, otherClass, soClass._registry, 'otherClass') self.joinColumn = joinColumn self.joinMethodName = joinMethodName self.orderBy = orderBy if not self.joinColumn: # Here we set up the basic join, which is # one-to-many, where the other class points to # us. self.joinColumn = Style.getStyle(self.soClass).tableReference(self.soClass._table) def hasIntermediateTable(self): return False def _applyOrderBy(self, results, defaultSortClass): if self.orderBy is NoDefault: self.orderBy = defaultSortClass._defaultOrder if self.orderBy is not None: def sorter(a, b, attr=self.orderBy): return cmp(getattr(a, attr), getattr(b, attr)) results.sort(sorter) return results # This is a one-to-many class SOMultipleJoin(SOJoin): def __init__(self, addRemoveName=None, **kw): # addRemovePrefix is something like @@ SOJoin.__init__(self, **kw) # Here we generate the method names if not self.joinMethodName: name = self.otherClassName[0].lower() + self.otherClassName[1:] if name.endswith('s'): name = name + "es" else: name = name + "s" self.joinMethodName = name if not addRemoveName: self.addRemoveName = capitalize(self.otherClassName) else: self.addRemoveName = addRemoveName def performJoin(self, inst): ids = inst._connection._SO_selectJoin( self.otherClass, self.joinColumn, inst.id) return self._applyOrderBy([self.otherClass(id) for (id,) in ids], self.otherClass) class MultipleJoin(Join): baseClass = SOMultipleJoin # This is a many-to-many join, with an intermediary table class SORelatedJoin(SOMultipleJoin): def __init__(self, otherColumn=None, intermediateTable=None, **kw): SOMultipleJoin.__init__(self, **kw) if not otherColumn: self.otherColumn = self.soClass._style.pythonClassToDBTableReference(self.otherClassName) else: self.otherColumn = otherColumn if not intermediateTable: names = [self.soClass._table, self.soClass._style.pythonClassToDBTable(self.otherClassName)] names.sort() self.intermediateTable = '%s_%s' % (names[0], names[1]) else: self.intermediateTable = intermediateTable def hasIntermediateTable(self): return True def performJoin(self, inst): ids = inst._connection._SO_intermediateJoin( self.intermediateTable, self.otherColumn, self.joinColumn, inst.id) return self._applyOrderBy([self.otherClass(id) for (id,) in ids], self.otherClass) def remove(self, inst, other): inst._connection._SO_intermediateDelete( self.intermediateTable, self.joinColumn, SQLObject.getID(inst), self.otherColumn, SQLObject.getID(other)) def add(self, inst, other): inst._connection._SO_intermediateInsert( self.intermediateTable, self.joinColumn, SQLObject.getID(inst), self.otherColumn, SQLObject.getID(other)) class RelatedJoin(MultipleJoin): baseClass = SORelatedJoin def capitalize(name): return name[0].capitalize() + name[1:] Index: Col.py =================================================================== RCS file: /cvsroot/sqlobject/SQLObject/SQLObject/Col.py,v retrieving revision 1.21 retrieving revision 1.22 diff -C2 -d -r1.21 -r1.22 *** Col.py 12 May 2003 01:58:21 -0000 1.21 --- Col.py 26 May 2003 21:48:54 -0000 1.22 *************** *** 177,181 **** def setName(self, value): ! assert self.kw['name'] is None, "You cannot change a name after it has already been set" self.kw['name'] = value --- 177,181 ---- def setName(self, value): ! assert self.kw['name'] is None, "You cannot change a name after it has already been set (from %s to %s)" % (self.kw['name'], value) self.kw['name'] = value Index: SQLObject.py =================================================================== RCS file: /cvsroot/sqlobject/SQLObject/SQLObject/SQLObject.py,v retrieving revision 1.39 retrieving revision 1.40 diff -C2 -d -r1.39 -r1.40 *** SQLObject.py 25 May 2003 02:39:45 -0000 1.39 --- SQLObject.py 26 May 2003 21:48:54 -0000 1.40 *************** *** 28,31 **** --- 28,32 ---- import types import warnings + import Join import sys *************** *** 75,78 **** --- 76,94 ---- newNeedList.append((needClass, setCls)) needSet[registryName] = newNeedList + + def setNeedSet(): + global needSet + for registryName, needClassDict in needSet.items(): + newNeedClassDict = {} + for needClass, q in needClassDict.items(): + try: + cls = findClass(needClass, registry=registryName) + for obj, attr in q: + setattr(obj, attr, cls) + except KeyError: + newNeedClassDict[needClass] = q + needSet[registryName] = newNeedClassDict + + def addNeedSet(needClass, setCls): *************** *** 80,83 **** --- 96,111 ---- (needClass.__name__, setCls)) + + def addNeedSet(obj, setCls, registry, attr): + try: + cls = findClass(setCls, registry=registry) + setattr(obj, attr, cls) + return + except KeyError: + pass + q = needSet.setdefault(registry, {}).setdefault(setCls, []) + q.append((obj, attr)) + + # This is the metaclass. It essentially takes a dictionary # of all the attributes (and thus methods) defined in the *************** *** 103,106 **** --- 131,135 ---- implicitColumns = [] + implicitJoins = [] for attr, value in d.items(): if isinstance(value, Col.Col): *************** *** 108,111 **** --- 137,146 ---- implicitColumns.append(value) del d[attr] + continue + if isinstance(value, Join.Join): + value.setName(attr) + implicitJoins.append(value) + del d[attr] + continue # We *don't* want to inherit _table, so we make sure it *************** *** 134,137 **** --- 169,175 ---- newClass._columns = newClass._columns[:] newClass._columns.extend(implicitColumns) + if not d.has_key('_joins'): + newClass._joins = newClass._joins[:] + newClass._joins.extend(implicitJoins) ###################################################### *************** *** 201,204 **** --- 239,243 ---- # putting them in this list. newClass._SO_joinList = [] + newClass._SO_joinDict = {} for join in newClass._joins: *************** *** 278,282 **** def findClass(name, registry=None): ! assert classRegistry.get(registry, {}).has_key(name), "No class by the name %s found (I have %s)" % (repr(name), ', '.join(classRegistry.keys())) return classRegistry[registry][name] --- 317,321 ---- def findClass(name, registry=None): ! #assert classRegistry.get(registry, {}).has_key(name), "No class by the name %s found (I have %s)" % (repr(name), ', '.join(map(str, classRegistry.keys()))) return classRegistry[registry][name] *************** *** 454,458 **** # some point. See needSet at the top of the # file for more on this. ! addNeedSet(cls, column.foreignKey) if column.alternateMethodName: --- 493,498 ---- # some point. See needSet at the top of the # file for more on this. ! addNeedSet(cls, column.foreignKey, cls._registry, ! '_SO_class_%s' % column.foreignKey) if column.alternateMethodName: *************** *** 516,539 **** delColumn = classmethod(delColumn) ! def addJoin(cls, join): # The name of the method we'll create. If it's # automatically generated, it's generated by the # join class. meth = join.joinMethodName - if join not in cls._joins: - cls._joins.append(join) - - # The method name for adding a joined object: - appendMeth = meth[0].upper() + meth[1:] - - # The join sometimes needs to know who we are, - # mostly to generate some internal names: - join.initCallingClass(cls) - - # Now that the join is set up, we add it to our - # list of joins: cls._SO_joinList.append(join) index = len(cls._SO_joinList)-1 # The function fetches the join by index, and --- 556,571 ---- delColumn = classmethod(delColumn) ! def addJoin(cls, joinDef): # The name of the method we'll create. If it's # automatically generated, it's generated by the # join class. + join = joinDef.withClass(cls) meth = join.joinMethodName + cls._SO_joinDict[joinDef] = join cls._SO_joinList.append(join) index = len(cls._SO_joinList)-1 + if joinDef not in cls._joins: + cls._joins.append(joinDef) # The function fetches the join by index, and *************** *** 555,561 **** # standard naming trick. func = eval('lambda self, obj: self._SO_joinList[%i].remove(self, obj)' % index) ! setattr(cls, '_SO_remove' + join.addRemovePrefix, func) ! if not hasattr(cls, 'remove' + appendMeth): ! setattr(cls, 'remove' + join.addRemovePrefix, func) cls._SO_plainJoinRemovers[meth] = 1 --- 587,593 ---- # standard naming trick. func = eval('lambda self, obj: self._SO_joinList[%i].remove(self, obj)' % index) ! setattr(cls, '_SO_remove' + join.addRemoveName, func) ! if not hasattr(cls, 'remove' + join.addRemoveName): ! setattr(cls, 'remove' + join.addRemoveName, func) cls._SO_plainJoinRemovers[meth] = 1 *************** *** 565,571 **** # And again... func = eval('lambda self, obj: self._SO_joinList[%i].add(self, obj)' % (len(cls._SO_joinList)-1)) ! setattr(cls, '_SO_add' + join.addRemovePrefix, func) ! if not hasattr(cls, 'add' + appendMeth): ! setattr(cls, 'add' + join.addRemovePrefix, func) cls._SO_plainJoinAdders[meth] = 1 --- 597,603 ---- # And again... func = eval('lambda self, obj: self._SO_joinList[%i].add(self, obj)' % (len(cls._SO_joinList)-1)) ! setattr(cls, '_SO_add' + join.addRemoveName, func) ! if not hasattr(cls, 'add' + join.addRemoveName): ! setattr(cls, 'add' + join.addRemoveName, func) cls._SO_plainJoinAdders[meth] = 1 *************** *** 575,583 **** addJoin = classmethod(addJoin) ! def delJoin(cls, join): meth = join.joinMethodName ! cls._joins.remove(join) for i in range(len(cls._SO_joinList)): ! if cls._SO_joinList[i] is join: cls._SO_joinList[i] = None delattr(cls, rawGetterName(meth)) --- 607,619 ---- addJoin = classmethod(addJoin) ! def delJoin(cls, joinDef): ! join = cls._SO_joinDict[joinDef] meth = join.joinMethodName ! cls._joins.remove(joinDef) ! del cls._SO_joinDict[joinDef] for i in range(len(cls._SO_joinList)): ! if cls._SO_joinList[i] is joinDef: ! # Have to leave None, because we refer to joins ! # by index. cls._SO_joinList[i] = None delattr(cls, rawGetterName(meth)) *************** *** 825,829 **** def createJoinTables(cls, ifNotExists=False): ! for join in cls._joins: if not join.hasIntermediateTable(): continue --- 861,867 ---- def createJoinTables(cls, ifNotExists=False): ! for join in cls._SO_joinList: ! if not join: ! continue if not join.hasIntermediateTable(): continue *************** *** 832,836 **** # arbitrarily create it while we're creating the # alphabetically earlier class. ! if join.callingClass > join.otherClass: continue if ifNotExists and \ --- 870,874 ---- # arbitrarily create it while we're creating the # alphabetically earlier class. ! if join.soClass.__name__ > join.otherClass.__name__: continue if ifNotExists and \ *************** *** 842,849 **** def dropJoinTables(cls, ifExists=False): ! for join in cls._joins: if not join.hasIntermediateTable(): continue ! if join.callingClass > join.otherClass: continue if ifExists and \ --- 880,889 ---- def dropJoinTables(cls, ifExists=False): ! for join in cls._SO_joinList: ! if not join: ! continue if not join.hasIntermediateTable(): continue ! if join.soClass.__name__ > join.otherClass.__name__: continue if ifExists and \ *************** *** 904,1035 **** - ######################################## - ## Joins - ######################################## - - # A join is separate from a foreign key, i.e., it is - # many-to-many, or one-to-many where the *other* class - # has the foreign key. - class Join(object): - - def __init__(self, otherClass, joinColumn=None, joinMethodName=None, - orderBy=NoDefault): - self.otherClass = otherClass - self.joinColumn = joinColumn - self.joinMethodName = joinMethodName - self.orderBy = orderBy - - def initCallingClass(self, callingClass): - # Since some of the automatic generation of the names - # depends on the class/table to which this join belongs, - # we can only resolve some of this after the class - # has been created, which is after this join has - # been created. - self.callingClass = callingClass - self.callingClassDBName = callingClass._table - if not self.joinColumn: - # Here we set up the basic join, which is - # one-to-many, where the other class points to - # us. - self.joinColumn = Style.getStyle(callingClass).tableReference(callingClass._table) - - def hasIntermediateTable(self): - return False - - def _applyOrderBy(self, results, defaultSortClass): - if self.orderBy is NoDefault: - self.orderBy = defaultSortClass._defaultOrder - if self.orderBy is not None: - def sorter(a, b, attr=self.orderBy): - return cmp(getattr(a, attr), - getattr(b, attr)) - results.sort(sorter) - return results - - # This is a one-to-many - class MultipleJoin(Join): - - def __init__(self, *args, **kw): - # addRemovePrefix is something like @@ - if kw.has_key('addRemovePrefix'): - self.addRemovePrefix = kw['addRemovePrefix'] - del kw['addRemovePrefix'] - else: - self.addRemovePrefix = None - Join.__init__(self, *args, **kw) - - # Here we generate the method names - if not self.joinMethodName: - name = self.otherClass[0].lower() + self.otherClass[1:] - if name.endswith('s'): - name = name + "es" - else: - name = name + "s" - self.joinMethodName = name - if not self.addRemovePrefix: - self.addRemovePrefix = capitalize(self.otherClass) - - def performJoin(self, inst): - # We only have names of classes a lot of the time, - # so we have to fetch the actual class definition: - cls = findClass(self.otherClass, registry=inst._registry) - ids = inst._connection._SO_selectJoin( - cls, - self.joinColumn, - inst.id) - return self._applyOrderBy([cls(id) for (id,) in ids], cls) - - # This is a many-to-many join, with an intermediary table - class RelatedJoin(MultipleJoin): - - def __init__(self, otherClass, - otherColumn=None, - intermediateTable=None, **kw): - MultipleJoin.__init__(self, otherClass, **kw) - self.intermediateTable = intermediateTable - self.otherColumn = otherColumn - - def hasIntermediateTable(self): - return True - - def initCallingClass(self, callingClass): - MultipleJoin.initCallingClass(self, callingClass) - if not self.otherColumn: - self.otherColumn = Style.getStyle( - callingClass.__name__).pythonClassToDBTableReference(self.otherClass) - if not self.intermediateTable: - names = [callingClass._table, - Style.getStyle(callingClass).pythonClassToDBTable(self.otherClass)] - names.sort() - self.intermediateTable = "%s_%s" % (names[0], names[1]) - - def performJoin(self, inst): - cls = findClass(self.otherClass, registry=inst._registry) - me = self.callingClass - ids = inst._connection._SO_intermediateJoin( - self.intermediateTable, - self.otherColumn, - self.joinColumn, - inst.id) - return self._applyOrderBy([cls(id) for (id,) in ids], cls) - - def remove(self, inst, other): - me = self.callingClass - inst._connection._SO_intermediateDelete( - self.intermediateTable, - self.joinColumn, - getID(inst), - self.otherColumn, - getID(other)) - - def add(self, inst, other): - me = self.callingClass - inst._connection._SO_intermediateInsert( - self.intermediateTable, - self.joinColumn, - getID(inst), - self.otherColumn, - getID(other)) - class SelectResults(object): --- 944,947 ---- *************** *** 1162,1165 **** __all__ = ['NoDefault', 'SQLObject', ! 'MultipleJoin', 'RelatedJoin', 'getID', 'getObject', 'SQLObjectNotFound'] --- 1074,1077 ---- __all__ = ['NoDefault', 'SQLObject', ! 'getID', 'getObject', 'SQLObjectNotFound'] Index: __init__.py =================================================================== RCS file: /cvsroot/sqlobject/SQLObject/SQLObject/__init__.py,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** __init__.py 21 Apr 2003 22:50:09 -0000 1.3 --- __init__.py 26 May 2003 21:48:54 -0000 1.4 *************** *** 4,5 **** --- 4,6 ---- from DBConnection import * from Style import * + from Join import * |
From: <ian...@us...> - 2003-05-25 06:03:49
|
Update of /cvsroot/sqlobject/SQLObject/docs In directory sc8-pr-cvs1:/tmp/cvs-serv21723 Modified Files: News.txt Log Message: Documented the new features. Index: News.txt =================================================================== RCS file: /cvsroot/sqlobject/SQLObject/docs/News.txt,v retrieving revision 1.5 retrieving revision 1.6 diff -C2 -d -r1.5 -r1.6 *** News.txt 7 Apr 2003 20:11:28 -0000 1.5 --- News.txt 25 May 2003 06:03:45 -0000 1.6 *************** *** 8,11 **** --- 8,138 ---- .. _start: + SQLObject 0.4 + ============= + + Features + -------- + + * You can specify columns in a new, preferred manner:: + + class SomeObject(SQLObject): + someColumn = Col() + + Equivalent to:: + + class SomeObject(SQLObject): + _columns = [Col('someColumn')] + + * Cache objects have a clear method, which empties all objects. + However, weak references to objects *are* maintained, so the + integrity of the cache can be ensured. + + * SQLObject subclasses can be further subclassed, adding or removing + column definitions (as well as changing settings like connection, + style, etc). Each class still refers to a single concrete table in + the database -- the class hierarchy is not represented in the + database. + + * Each SQLObject subclass can have an associated style, as given in + the `_style` attribute. This object is used to map between Python + and database names (e.g., the column name for a Python attribute). + Some samples are available in the `Style` module. + + * Postgres support for `_fromDatabase` (reading a table definition from + the database, and creating a class from that). + + * Postgres id columns more permissive, you don't have to create a + specially named sequence (or implicitly create that sequence through + ``SERIAL``). lastoid is used instead. + + * MySQL uses ``localhost`` as the default host, and the empty string + as the default password. + + * Added functions for use with queries: `ISNULL`, `ISNOTNULL`. ``==`` + and ``!=`` can be used with None, and is translated into `ISNULL`, + `ISNOTNULL`. + + * Classes can be part of a specific registry. Since classes are + referred to by name in several places, the names have to be unique. + This can be problematic, so you can add a class variable `_registry`, + the value of which should be a string. Classes references are + assumed to be inside that registry, and class names need only be + unique among classes in that registry. + + * ``SomeClass.select()`` selects all, instead of using + ``SomeClass.select('all')``. You can also use None instead of + ``'all'``. + + * Trying to fetch non-existent objects raises `SQLObjectNotFound`, + which is a subclass of the builtin exception `LookupError`. + This may not be raised if `_cacheValues` is False and you use + the ID to fetch an object (but alternateID fetches will raise + the exception in either case). + + Col and Join + ~~~~~~~~~~~~ + + * `Join` constructors have an argument `orderBy`, which is the name + of a Python attribute to sort results by. If not given, the + appropriate class's `_defaultOrder` will be used. None implies + no sorting (and ``orderBy=None`` will override `_defaultOrder`). + + * `ForeignKey` class (subclass of `Col`), for somewhat easier/clearer + declaration of foreign keys. + + * `Col` (and subclasses) can take a `sqlType` argument, which is used + in table definitions. E.g., ``Col(sqlType="BOOLEAN")`` can be used + to create a ``BOOLEAN`` column, even though no `BooleanCol` exists. + + * `alternateID` (a specifier for columns) implies ``NOT NULL``. Also + implies ``UNIQUE``. + + * `unique` (a specifier for columns) added. + + * `DecimalCol` and `CurrencyCol` added. + + * `EnumCol` uses constraints on Postgres (if you use `createTable`). + + Bugs + ---- + + * `DateTimeCol` uses ``TIMESTAMP`` for Postgres. Note that the + Python type name is used for column names, not necessarily the + SQL standard name. + + * Foreign key column names are slightly more permissive. They still + need to end in ``id``, but it's case insensitive. + + * _defaultOrder should be the python attribute's name, not the database + name. + + * SomeClass.q.colName uses proper Python attributes for colName, and + proper database names when executed in the database. + + * SQLite select results back to being proper iterator. + + * SomeClass.q.colName now does proper translation to database names, + using dbName, etc., instead of being entirely algorithm-driven. + + * Raise `TypeError` if you pass an unknown argument to the `new` + method. + + * You can override the _get_* or _set_* version of a property without + overriding the other. + + * Python 2.3 compatible. + + * Trying to use ``Col('id')`` or ``id = Col()`` will raise an + exception, instead of just acting funky. + + Internal + -------- + + * `Col` class separated into `Col` and `SOCol` (and same for all other + `*Col` classes). `Col` defines a column, `SOCol` is that definition + bound to a particular SQLObject class. + + * Instance variable ``_SO_columns`` holds the `SOCol` instances. + SQLObject 0.3 ============= |
From: <ian...@us...> - 2003-05-25 02:39:48
|
Update of /cvsroot/sqlobject/SQLObject/SQLObject In directory sc8-pr-cvs1:/tmp/cvs-serv26546/SQLObject Modified Files: SQLObject.py Log Message: Used proper DB name mappings, not the style, for orderBy Index: SQLObject.py =================================================================== RCS file: /cvsroot/sqlobject/SQLObject/SQLObject/SQLObject.py,v retrieving revision 1.38 retrieving revision 1.39 diff -C2 -d -r1.38 -r1.39 *** SQLObject.py 24 May 2003 21:17:17 -0000 1.38 --- SQLObject.py 25 May 2003 02:39:45 -0000 1.39 *************** *** 1052,1056 **** orderBy = self.ops['orderBy'] if orderBy is not None: ! self.ops['dbOrderBy'] = sourceClass._style.pythonAttrToDBColumn(orderBy) def clone(self, **newOps): --- 1052,1057 ---- orderBy = self.ops['orderBy'] if orderBy is not None: ! if sourceClass._SO_columnDict.has_key(orderBy): ! self.ops['dbOrderBy'] = sourceClass._SO_columnDict[orderBy].dbName def clone(self, **newOps): |
From: <ian...@us...> - 2003-05-24 21:24:04
|
Update of /cvsroot/sqlobject/SQLObject/SQLObject In directory sc8-pr-cvs1:/tmp/cvs-serv12102/SQLObject Modified Files: DBConnection.py SQLObject.py Log Message: * Joins now take an orderBy argument, and use the class's _defaultOrder if no argument is given. * defaultOrder/orderBy takes python attribute names, not DB names. Index: DBConnection.py =================================================================== RCS file: /cvsroot/sqlobject/SQLObject/SQLObject/DBConnection.py,v retrieving revision 1.33 retrieving revision 1.34 diff -C2 -d -r1.33 -r1.34 *** DBConnection.py 6 May 2003 22:43:34 -0000 1.33 --- DBConnection.py 24 May 2003 21:17:17 -0000 1.34 *************** *** 189,194 **** if order and ops.get('groupBy'): q = "%s GROUP BY %s" % (q, ", ".join(clauseList(ops['groupBy']))) ! if order and ops.get('orderBy'): ! q = "%s ORDER BY %s" % (q, ", ".join(clauseList(ops['orderBy']))) start = ops.get('start', 0) --- 189,194 ---- if order and ops.get('groupBy'): q = "%s GROUP BY %s" % (q, ", ".join(clauseList(ops['groupBy']))) ! if order and ops.get('dbOrderBy'): ! q = "%s ORDER BY %s" % (q, ", ".join(clauseList(ops['dbOrderBy']))) start = ops.get('start', 0) Index: SQLObject.py =================================================================== RCS file: /cvsroot/sqlobject/SQLObject/SQLObject/SQLObject.py,v retrieving revision 1.37 retrieving revision 1.38 diff -C2 -d -r1.37 -r1.38 *** SQLObject.py 24 May 2003 20:53:36 -0000 1.37 --- SQLObject.py 24 May 2003 21:17:17 -0000 1.38 *************** *** 913,920 **** class Join(object): ! def __init__(self, otherClass, joinColumn=None, joinMethodName=None): self.otherClass = otherClass self.joinColumn = joinColumn self.joinMethodName = joinMethodName def initCallingClass(self, callingClass): --- 913,922 ---- class Join(object): ! def __init__(self, otherClass, joinColumn=None, joinMethodName=None, ! orderBy=NoDefault): self.otherClass = otherClass self.joinColumn = joinColumn self.joinMethodName = joinMethodName + self.orderBy = orderBy def initCallingClass(self, callingClass): *************** *** 935,938 **** --- 937,950 ---- return False + def _applyOrderBy(self, results, defaultSortClass): + if self.orderBy is NoDefault: + self.orderBy = defaultSortClass._defaultOrder + if self.orderBy is not None: + def sorter(a, b, attr=self.orderBy): + return cmp(getattr(a, attr), + getattr(b, attr)) + results.sort(sorter) + return results + # This is a one-to-many class MultipleJoin(Join): *************** *** 966,970 **** self.joinColumn, inst.id) ! return [cls(id) for (id,) in ids] # This is a many-to-many join, with an intermediary table --- 978,982 ---- self.joinColumn, inst.id) ! return self._applyOrderBy([cls(id) for (id,) in ids], cls) # This is a many-to-many join, with an intermediary table *************** *** 1000,1004 **** self.joinColumn, inst.id) ! return [cls(id) for (id,) in ids] def remove(self, inst, other): --- 1012,1016 ---- self.joinColumn, inst.id) ! return self._applyOrderBy([cls(id) for (id,) in ids], cls) def remove(self, inst, other): *************** *** 1038,1041 **** --- 1050,1056 ---- if self.ops.get('orderBy', NoDefault) is NoDefault: self.ops['orderBy'] = sourceClass._defaultOrder + orderBy = self.ops['orderBy'] + if orderBy is not None: + self.ops['dbOrderBy'] = sourceClass._style.pythonAttrToDBColumn(orderBy) def clone(self, **newOps): |
From: <ian...@us...> - 2003-05-24 20:53:40
|
Update of /cvsroot/sqlobject/SQLObject/SQLObject In directory sc8-pr-cvs1:/tmp/cvs-serv3719/SQLObject Modified Files: SQLObject.py Log Message: * Use the instance's connection in joins. * Allow connection option to selects. Index: SQLObject.py =================================================================== RCS file: /cvsroot/sqlobject/SQLObject/SQLObject/SQLObject.py,v retrieving revision 1.36 retrieving revision 1.37 diff -C2 -d -r1.36 -r1.37 *** SQLObject.py 24 May 2003 20:48:50 -0000 1.36 --- SQLObject.py 24 May 2003 20:53:36 -0000 1.37 *************** *** 995,999 **** cls = findClass(self.otherClass, registry=inst._registry) me = self.callingClass ! ids = me._connection._SO_intermediateJoin( self.intermediateTable, self.otherColumn, --- 995,999 ---- cls = findClass(self.otherClass, registry=inst._registry) me = self.callingClass ! ids = inst._connection._SO_intermediateJoin( self.intermediateTable, self.otherColumn, *************** *** 1004,1008 **** def remove(self, inst, other): me = self.callingClass ! me._connection._SO_intermediateDelete( self.intermediateTable, self.joinColumn, --- 1004,1008 ---- def remove(self, inst, other): me = self.callingClass ! inst._connection._SO_intermediateDelete( self.intermediateTable, self.joinColumn, *************** *** 1013,1017 **** def add(self, inst, other): me = self.callingClass ! me._connection._SO_intermediateInsert( self.intermediateTable, self.joinColumn, --- 1013,1017 ---- def add(self, inst, other): me = self.callingClass ! inst._connection._SO_intermediateInsert( self.intermediateTable, self.joinColumn, *************** *** 1051,1054 **** --- 1051,1057 ---- return self.clone(groupBy=groupBy) + def connection(self, conn): + return self.clone(connection=conn) + def limit(self, limit): return self[:limit] *************** *** 1098,1105 **** def __iter__(self): ! return self.sourceClass._connection.iterSelect(self) def __len__(self): ! count = self.sourceClass._connection.countSelect(self) if self.ops.get('start'): count -= self.ops['start'] --- 1101,1110 ---- def __iter__(self): ! conn = self.ops.get('connection', self.sourceClass._connection) ! return conn.iterSelect(self) def __len__(self): ! conn = self.ops.get('connection', self.sourceClass._connection) ! count = conn.countSelect(self) if self.ops.get('start'): count -= self.ops['start'] |
From: <ian...@us...> - 2003-05-24 20:52:37
|
Update of /cvsroot/sqlobject/SQLObject/SQLObject In directory sc8-pr-cvs1:/tmp/cvs-serv1901/SQLObject Modified Files: SQLObject.py Log Message: Added registries for classes, so that class names only have to be unique within their registry. Index: SQLObject.py =================================================================== RCS file: /cvsroot/sqlobject/SQLObject/SQLObject/SQLObject.py,v retrieving revision 1.35 retrieving revision 1.36 diff -C2 -d -r1.35 -r1.36 *** SQLObject.py 12 May 2003 01:59:42 -0000 1.35 --- SQLObject.py 24 May 2003 20:48:50 -0000 1.36 *************** *** 47,59 **** # actual classes. ! # Here we keep a dictionary of class names to classes -- note # that the classes might be spread among different modules, so # since we pile them together names need to be globally unique, # not just module unique. classRegistry = {} ! # This is the list of (cls, needClass) pairs, where cls has ! # a reference to the class named needClass. ! needSet = [] # Here's what we call after each class is created, to fix up --- 47,62 ---- # actual classes. ! # Here we keep a dictionaries of class names to classes -- note # that the classes might be spread among different modules, so # since we pile them together names need to be globally unique, # not just module unique. + # Like needSet below, the container dictionary is keyed by the + # "class registry". classRegistry = {} ! # This contains the list of (cls, needClass) pairs, where cls has ! # a reference to the class named needClass. It is keyed by "class ! # registries", which are disjunct sets of classes. ! needSet = {} # Here's what we call after each class is created, to fix up *************** *** 62,72 **** def setNeedSet(): global needSet ! newNeedSet = [] ! for needClass, setCls in needSet: ! if classRegistry.has_key(setCls): ! setattr(findClass(needClass), '_SO_class_%s' % setCls, findClass(setCls)) ! else: ! newNeedSet.append((needClass, setCls)) ! needSet = newNeedSet # This is the metaclass. It essentially takes a dictionary --- 65,82 ---- def setNeedSet(): global needSet ! for registryName, needList in needSet.items(): ! newNeedList = [] ! for needClass, setCls in needList: ! if classRegistry.get(registryName, {}).has_key(setCls): ! setattr(findClass(needClass, registry=registryName), ! '_SO_class_%s' % setCls, ! findClass(setCls, registry=registryName)) ! else: ! newNeedList.append((needClass, setCls)) ! needSet[registryName] = newNeedList ! ! def addNeedSet(needClass, setCls): ! needSet.setdefault(needClass.__name__, []).append( ! (needClass.__name__, setCls)) # This is the metaclass. It essentially takes a dictionary *************** *** 104,116 **** d['_table'] = None - # needSet stuff (see top of module) would get messed - # up if more than one SQLObject class has the same - # name. - assert not classRegistry.has_key(className), "A database object by the name %s has already been created" % repr(className) - # We actually create the class. newClass = type.__new__(cls, className, bases, d) newClass._SO_finishedClassCreation = False # We append to _columns, but we don't want to change the # superclass's _columns list, so we make a copy if necessary --- 114,132 ---- d['_table'] = None # We actually create the class. newClass = type.__new__(cls, className, bases, d) newClass._SO_finishedClassCreation = False + # needSet stuff (see top of module) would get messed + # up if more than one SQLObject class has the same + # name. + registry = newClass._registry + assert not classRegistry.get(registry, {}).has_key(className), "A database object by the name %s has already been created" % repr(className) + + # Register it, for use with needSet + if not classRegistry.has_key(registry): + classRegistry[registry] = {} + classRegistry[registry][className] = newClass + # We append to _columns, but we don't want to change the # superclass's _columns list, so we make a copy if necessary *************** *** 194,199 **** makeProperties(newClass) - # Register it, for use with needSet - classRegistry[className] = newClass # Call needSet setNeedSet() --- 210,213 ---- *************** *** 263,269 **** break ! def findClass(name): ! assert classRegistry.has_key(name), "No class by the name %s found (I have %s)" % (repr(name), ', '.join(classRegistry.keys())) ! return classRegistry[name] --- 277,283 ---- break ! def findClass(name, registry=None): ! assert classRegistry.get(registry, {}).has_key(name), "No class by the name %s found (I have %s)" % (repr(name), ', '.join(classRegistry.keys())) ! return classRegistry[registry][name] *************** *** 311,314 **** --- 325,330 ---- _style = None + _registry = None + def __new__(cls, id, connection=None, selectResults=None): *************** *** 438,442 **** # some point. See needSet at the top of the # file for more on this. ! needSet.append((cls.__name__, column.foreignKey)) if column.alternateMethodName: --- 454,458 ---- # some point. See needSet at the top of the # file for more on this. ! addNeedSet(cls, column.foreignKey) if column.alternateMethodName: *************** *** 945,949 **** # We only have names of classes a lot of the time, # so we have to fetch the actual class definition: ! cls = findClass(self.otherClass) ids = inst._connection._SO_selectJoin( cls, --- 961,965 ---- # We only have names of classes a lot of the time, # so we have to fetch the actual class definition: ! cls = findClass(self.otherClass, registry=inst._registry) ids = inst._connection._SO_selectJoin( cls, *************** *** 977,981 **** def performJoin(self, inst): ! cls = findClass(self.otherClass) me = self.callingClass ids = me._connection._SO_intermediateJoin( --- 993,997 ---- def performJoin(self, inst): ! cls = findClass(self.otherClass, registry=inst._registry) me = self.callingClass ids = me._connection._SO_intermediateJoin( |
From: <ian...@us...> - 2003-05-24 20:52:35
|
Update of /cvsroot/sqlobject/SQLObject/tests In directory sc8-pr-cvs1:/tmp/cvs-serv1901/tests Modified Files: test.py Log Message: Added registries for classes, so that class names only have to be unique within their registry. Index: test.py =================================================================== RCS file: /cvsroot/sqlobject/SQLObject/tests/test.py,v retrieving revision 1.14 retrieving revision 1.15 diff -C2 -d -r1.14 -r1.15 *** test.py 12 May 2003 01:58:21 -0000 1.14 --- test.py 24 May 2003 20:48:51 -0000 1.15 *************** *** 261,267 **** return import sys - reg = sys.modules[SQLObject.__module__].classRegistry - if reg.has_key('AutoTest'): - del reg['AutoTest'] class AutoTest(SQLObject): _fromDatabase = True --- 261,264 ---- *************** *** 275,278 **** --- 272,277 ---- happy='N', created=DateTime.now()) + reg = sys.modules[SQLObject.__module__].classRegistry[AutoTest._registry] + del reg['AutoTest'] ######################################## |
From: <ian...@us...> - 2003-05-12 01:59:45
|
Update of /cvsroot/sqlobject/SQLObject/SQLObject In directory sc8-pr-cvs1:/tmp/cvs-serv23391/SQLObject Modified Files: SQLObject.py Log Message: make SomeClass.select() mean select all Index: SQLObject.py =================================================================== RCS file: /cvsroot/sqlobject/SQLObject/SQLObject/SQLObject.py,v retrieving revision 1.34 retrieving revision 1.35 diff -C2 -d -r1.34 -r1.35 *** SQLObject.py 10 May 2003 21:37:18 -0000 1.34 --- SQLObject.py 12 May 2003 01:59:42 -0000 1.35 *************** *** 777,781 **** # 3-03 @@: Should this have a connection argument? ! def select(cls, clause, clauseTables=None, orderBy=NoDefault, groupBy=None, limit=None, lazyColumns=False): --- 777,781 ---- # 3-03 @@: Should this have a connection argument? ! def select(cls, clause=None, clauseTables=None, orderBy=NoDefault, groupBy=None, limit=None, lazyColumns=False): *************** *** 1009,1013 **** **ops): self.sourceClass = sourceClass ! if isinstance(clause, str) and clause == 'all': clause = SQLBuilder.SQLTrueClause self.clause = clause --- 1009,1013 ---- **ops): self.sourceClass = sourceClass ! if clause is None or isinstance(clause, str) and clause == 'all': clause = SQLBuilder.SQLTrueClause self.clause = clause |
From: <ian...@us...> - 2003-05-12 01:58:24
|
Update of /cvsroot/sqlobject/SQLObject/SQLObject In directory sc8-pr-cvs1:/tmp/cvs-serv22955/SQLObject Modified Files: Col.py Style.py Log Message: ForeignKey class that is easier to specify Index: Col.py =================================================================== RCS file: /cvsroot/sqlobject/SQLObject/SQLObject/Col.py,v retrieving revision 1.20 retrieving revision 1.21 diff -C2 -d -r1.20 -r1.21 *** Col.py 12 May 2003 01:15:16 -0000 1.20 --- Col.py 12 May 2003 01:58:21 -0000 1.21 *************** *** 257,261 **** --- 257,281 ---- class KeyCol(Col): + baseClass = SOKeyCol + + class SOForeignKey(SOKeyCol): + + def __init__(self, **kw): + foreignKey = kw['foreignKey'] + style = kw['soClass']._style + if not kw.get('name'): + kw['name'] = style.instanceAttrToIDAttr(style.pythonClassToAttr(foreignKey)) + else: + if not kw['name'].upper().endswith('ID'): + kw['name'] = style.instanceAttrToIDAttr(kw['name']) + SOKeyCol.__init__(self, **kw) + + class ForeignKey(KeyCol): + + baseClass = SOForeignKey + + def __init__(self, foreignKey=None, **kw): + KeyCol.__init__(self, foreignKey=foreignKey, **kw) class SOEnumCol(SOCol): Index: Style.py =================================================================== RCS file: /cvsroot/sqlobject/SQLObject/SQLObject/Style.py,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** Style.py 5 May 2003 17:55:48 -0000 1.2 --- Style.py 12 May 2003 01:58:21 -0000 1.3 *************** *** 43,46 **** --- 43,54 ---- return 'id' + def pythonClassToAttr(self, className): + return className[0].lower() + className[1:] + + def instanceAttrToIDAttr(self, attr): + # @@: Right now, because of how names are created for foreign + # keys, you can't really change this style. + return attr + "ID" + class MixedCaseUnderscoreStyle(Style): |
From: <ian...@us...> - 2003-05-12 01:58:24
|
Update of /cvsroot/sqlobject/SQLObject/tests In directory sc8-pr-cvs1:/tmp/cvs-serv22955/tests Modified Files: test.py Log Message: ForeignKey class that is easier to specify Index: test.py =================================================================== RCS file: /cvsroot/sqlobject/SQLObject/tests/test.py,v retrieving revision 1.13 retrieving revision 1.14 diff -C2 -d -r1.13 -r1.14 *** test.py 12 May 2003 01:22:48 -0000 1.13 --- test.py 12 May 2003 01:58:21 -0000 1.14 *************** *** 329,333 **** _columns = [StringCol('zip', length=5), ! KeyCol('personJoiner2ID', foreignKey='PersonJoiner2')] class JoinTest2(SQLObjectTest): --- 329,334 ---- _columns = [StringCol('zip', length=5), ! ForeignKey('PersonJoiner2')] ! # KeyCol('personJoiner2ID', foreignKey='PersonJoiner2')] class JoinTest2(SQLObjectTest): |
From: <ian...@us...> - 2003-05-12 01:22:51
|
Update of /cvsroot/sqlobject/SQLObject/tests In directory sc8-pr-cvs1:/tmp/cvs-serv12846/tests Modified Files: test.py Log Message: Test for new-style column definitions. Index: test.py =================================================================== RCS file: /cvsroot/sqlobject/SQLObject/tests/test.py,v retrieving revision 1.12 retrieving revision 1.13 diff -C2 -d -r1.12 -r1.13 *** test.py 6 May 2003 22:43:35 -0000 1.12 --- test.py 12 May 2003 01:22:48 -0000 1.13 *************** *** 20,23 **** --- 20,24 ---- classes = [TestSO1] + MyClass = TestSO1 info = [('bob', 'god'), ('sally', 'sordid'), *************** *** 26,33 **** def inserts(self): for name, passwd in self.info: ! TestSO1.new(name=name, passwd=passwd) def testGet(self): ! bob = TestSO1.selectBy(name='bob')[0] self.assertEqual(bob.name, 'bob') self.assertEqual(bob.passwd, 'god'.encode('rot13')) --- 27,34 ---- def inserts(self): for name, passwd in self.info: ! self.MyClass.new(name=name, passwd=passwd) def testGet(self): ! bob = self.MyClass.selectBy(name='bob')[0] self.assertEqual(bob.name, 'bob') self.assertEqual(bob.passwd, 'god'.encode('rot13')) *************** *** 41,44 **** --- 42,57 ---- self.assertEqual(bob.name, 'joe') + + class TestSO2(SQLObject): + name = StringCol(length=10) + passwd = StringCol(length=10) + + def _set_passwd(self, passwd): + self._SO_set_passwd(passwd.encode('rot13')) + + class TestCase2(TestCase1): + + classes = [TestSO2] + MyClass = TestSO2 ######################################## |
From: <ian...@us...> - 2003-05-12 01:15:19
|
Update of /cvsroot/sqlobject/SQLObject/SQLObject In directory sc8-pr-cvs1:/tmp/cvs-serv10803/SQLObject Modified Files: Col.py Log Message: fixed typo Index: Col.py =================================================================== RCS file: /cvsroot/sqlobject/SQLObject/SQLObject/Col.py,v retrieving revision 1.19 retrieving revision 1.20 diff -C2 -d -r1.19 -r1.20 *** Col.py 6 May 2003 22:43:34 -0000 1.19 --- Col.py 12 May 2003 01:15:16 -0000 1.20 *************** *** 177,181 **** def setName(self, value): ! assert kw['name'] is None, "You cannot change a name after it has already been set" self.kw['name'] = value --- 177,181 ---- def setName(self, value): ! assert self.kw['name'] is None, "You cannot change a name after it has already been set" self.kw['name'] = value |
From: <ian...@us...> - 2003-05-10 21:37:21
|
Update of /cvsroot/sqlobject/SQLObject/SQLObject In directory sc8-pr-cvs1:/tmp/cvs-serv21770/SQLObject Modified Files: SQLObject.py Log Message: Added a warning for when a method shadows a column name (which leads to weird bugs) Index: SQLObject.py =================================================================== RCS file: /cvsroot/sqlobject/SQLObject/SQLObject/SQLObject.py,v retrieving revision 1.33 retrieving revision 1.34 diff -C2 -d -r1.33 -r1.34 *** SQLObject.py 6 May 2003 22:43:35 -0000 1.33 --- SQLObject.py 10 May 2003 21:37:18 -0000 1.34 *************** *** 26,29 **** --- 26,31 ---- import Col import Style + import types + import warnings import sys *************** *** 237,240 **** --- 239,245 ---- continue if d.has_key(var): + if isinstance(d[var], types.MethodType) \ + or isinstance(d[var], types.FunctionType): + warnings.warn("""I tried to set the property "%s", but it was already set, as a method. Methods have significantly different semantics than properties, and this may be a sign of a bug in your code.""" % var) continue setFunc(var, |
From: <ian...@us...> - 2003-05-06 22:43:40
|
Update of /cvsroot/sqlobject/SQLObject/SQLObject In directory sc8-pr-cvs1:/tmp/cvs-serv9293/SQLObject Modified Files: Col.py DBConnection.py SQLObject.py Log Message: * Col objects are more like definitions/factories, SO* classes do the actual work (to the degree there is work there) * SQLObject classes can inherit from each other * New ._SO_columns attribute that holds the non-factory columns Index: Col.py =================================================================== RCS file: /cvsroot/sqlobject/SQLObject/SQLObject/Col.py,v retrieving revision 1.18 retrieving revision 1.19 diff -C2 -d -r1.18 -r1.19 *** Col.py 5 May 2003 17:37:19 -0000 1.18 --- Col.py 6 May 2003 22:43:34 -0000 1.19 *************** *** 16,23 **** # Col is essentially a column definition, it doesn't have # much logic to it. ! class Col(object): def __init__(self, ! name=None, dbName=None, default=NoDefault, --- 16,24 ---- # Col is essentially a column definition, it doesn't have # much logic to it. ! class SOCol(object): def __init__(self, ! name, ! soClass, dbName=None, default=NoDefault, *************** *** 26,32 **** alternateMethodName=None, constraints=None, ! notNull=False, unique=NoDefault, ! sqlType=None): # This isn't strictly true, since we *could* use backquotes # around column names, but why would anyone *want* to --- 27,36 ---- alternateMethodName=None, constraints=None, ! notNull=NoDefault, ! notNone=NoDefault, unique=NoDefault, ! sqlType=None, ! columnDef=None): ! # This isn't strictly true, since we *could* use backquotes # around column names, but why would anyone *want* to *************** *** 37,55 **** % repr(name) assert name != 'id', 'The column name "id" is reserved for SQLObject use (and is implicitly created).' ! self.foreignKey = foreignKey ! self.alternateID = alternateID ! self.alternateMethodName = alternateMethodName ! if unique is NoDefault: ! self.unique = alternateID ! else: ! self.unique = unique ! self.constraints = constraints or [] if type(constraints) not in (type([]), type(())): constraints = [constraints] self.constraints = self.autoConstraints() + constraints ! self.notNull = notNull ! self.dbName = dbName ! if notNull: self.constraints = [Constraints.notNull] + self.constraints self.name = name self.soClass = None --- 41,63 ---- % repr(name) assert name != 'id', 'The column name "id" is reserved for SQLObject use (and is implicitly created).' ! assert name, "You must provide a name for all columns" ! ! self.columnDef = columnDef ! if type(constraints) not in (type([]), type(())): constraints = [constraints] self.constraints = self.autoConstraints() + constraints ! ! self.notNone = False ! if notNull is not NoDefault: ! self.notNone = notNull ! assert notNone is NoDefault or \ ! (not notNone) == (not notNull), \ ! "The notNull and notNone arguments are aliases, and must not conflict. You gave notNull=%r, notNone=%r" % (notNull, notNone) ! elif notNone is not NoDefault: ! self.notNone = notNone ! if self.notNone: self.constraints = [Constraints.notNull] + self.constraints + self.name = name self.soClass = None *************** *** 57,76 **** self.customSQLType = sqlType - def setClass(self, soClass): - if soClass is self.soClass: - return - assert not self.soClass, "This column (%r) has already been associated with another class (%r), and you tried to reassociate it with %r" % (self, self.soClass, soClass) - # if they don't give us a specific database name for # the column, we separate the mixedCase into mixed_case # and assume that. @@: should be able to define # different policies for naming. ! if self.dbName is None: self.dbName = soClass._style.pythonAttrToDBColumn(self.name) # alternateID means that this is a unique column that # can be used to identify rows ! if self.alternateID and self.alternateMethodName is None: self.alternateMethodName = 'by' + self.name[0].capitalize() + self.name[1:] if self.foreignKey: assert self.name.upper().endswith('ID'), "All foreign key columns must end with 'ID' (%s)" % repr(self.name) --- 65,91 ---- self.customSQLType = sqlType # if they don't give us a specific database name for # the column, we separate the mixedCase into mixed_case # and assume that. @@: should be able to define # different policies for naming. ! if dbName is None: self.dbName = soClass._style.pythonAttrToDBColumn(self.name) + else: + self.dbName = dbName + # alternateID means that this is a unique column that # can be used to identify rows ! self.alternateID = alternateID ! if self.alternateID and alternateMethodName is None: self.alternateMethodName = 'by' + self.name[0].capitalize() + self.name[1:] + else: + self.alternateMethodName = alternateMethodName + + if unique is NoDefault: + self.unique = alternateID + else: + self.unique = unique + self.foreignKey = foreignKey if self.foreignKey: assert self.name.upper().endswith('ID'), "All foreign key columns must end with 'ID' (%s)" % repr(self.name) *************** *** 108,112 **** if self.alternateID: r += ' alternate ID' ! if self.notNull: r += ' not null' return r + '>' --- 123,127 ---- if self.alternateID: r += ' alternate ID' ! if self.notNone: r += ' not null' return r + '>' *************** *** 117,121 **** def _extraSQL(self): result = [] ! if self.notNull or self.alternateID: result.append('NOT NULL') if self.unique or self.alternateID: --- 132,136 ---- def _extraSQL(self): result = [] ! if self.notNone or self.alternateID: result.append('NOT NULL') if self.unique or self.alternateID: *************** *** 152,160 **** return ' '.join([self.dbName, self._sqliteType()] + self._extraSQL()) ! class StringCol(Col): # 3-03 @@: What about BLOB? ! def __init__(self, *args, **kw): self.length = popKey(kw, 'length') self.varchar = popKey(kw, 'varchar', 'auto') --- 167,191 ---- return ' '.join([self.dbName, self._sqliteType()] + self._extraSQL()) ! class Col(object): ! ! baseClass = SOCol ! ! def __init__(self, name=None, **kw): ! kw['name'] = name ! kw['columnDef'] = self ! self.kw = kw ! ! def setName(self, value): ! assert kw['name'] is None, "You cannot change a name after it has already been set" ! self.kw['name'] = value ! ! def withClass(self, soClass): ! return self.baseClass(soClass=soClass, **self.kw) ! ! class SOStringCol(SOCol): # 3-03 @@: What about BLOB? ! def __init__(self, **kw): self.length = popKey(kw, 'length') self.varchar = popKey(kw, 'varchar', 'auto') *************** *** 166,170 **** self.varchar = True ! Col.__init__(self, *args, **kw) def autoConstraints(self): --- 197,201 ---- self.varchar = True ! SOCol.__init__(self, **kw) def autoConstraints(self): *************** *** 181,186 **** else: return 'CHAR(%i)' % self.length ! class IntCol(Col): # 3-03 @@: support precision, maybe max and min directly --- 212,220 ---- else: return 'CHAR(%i)' % self.length + + class StringCol(Col): + baseClass = SOStringCol ! class SOIntCol(SOCol): # 3-03 @@: support precision, maybe max and min directly *************** *** 192,196 **** return 'INT' ! class FloatCol(Col): # 3-03 @@: support precision (e.g., DECIMAL) --- 226,233 ---- return 'INT' ! class IntCol(Col): ! baseClass = SOIntCol ! ! class SOFloatCol(SOCol): # 3-03 @@: support precision (e.g., DECIMAL) *************** *** 202,206 **** return 'FLOAT' ! class KeyCol(Col): # 3-03 @@: this should have a simplified constructor --- 239,246 ---- return 'FLOAT' ! class FloatCol(Col): ! baseClass = SOFloatCol ! ! class SOKeyCol(SOCol): # 3-03 @@: this should have a simplified constructor *************** *** 216,226 **** return 'INT' ! class EnumCol(Col): ! def __init__(self, *args, **kw): self.enumValues = popKey(kw, 'enumValues', None) assert self.enumValues is not None, \ 'You must provide an enumValues keyword argument' ! Col.__init__(self, *args, **kw) def autoConstraints(self): --- 256,269 ---- return 'INT' ! class KeyCol(Col): ! baseClass = SOKeyCol ! class SOEnumCol(SOCol): ! ! def __init__(self, **kw): self.enumValues = popKey(kw, 'enumValues', None) assert self.enumValues is not None, \ 'You must provide an enumValues keyword argument' ! SOCol.__init__(self, **kw) def autoConstraints(self): *************** *** 239,243 **** return self._postgresType() ! class DateTimeCol(Col): # 3-03 @@: provide constraints; right now we let the database --- 282,289 ---- return self._postgresType() ! class EnumCol(Col): ! baseClass = SOEnumCol ! ! class SODateTimeCol(SOCol): # 3-03 @@: provide constraints; right now we let the database *************** *** 250,268 **** return 'TIMESTAMP' ! class DecimalCol(Col): ! def __init__(self, name, size, precision, **kw): ! self.size = size ! self.precision = precision ! Col.__init__(self, name, **kw) def _sqlType(self): return 'DECIMAL(%i, %i)' % (self.size, self.precision) ! class CurrencyCol(DecimalCol): ! def __init__(self, name, **kw): ! DecimalCol.__init__(self, name, size=10, precision=2, **kw) def popKey(kw, name, default=None): --- 296,325 ---- return 'TIMESTAMP' ! class DateTimeCol(Col): ! baseClass = SODateTimeCol ! class SODecimalCol(SOCol): ! ! def __init__(self, **kw): ! self.size = popKey(kw, 'size', NoDefault) ! assert self.size is not NoDefault, \ ! "You must give a size argument" ! self.precision = popKey(kw, 'precision', NoDefault) ! assert self.precision is not NoDefault, \ ! "You must give a precision argument" ! SOCol.__init__(self, **kw) def _sqlType(self): return 'DECIMAL(%i, %i)' % (self.size, self.precision) ! class DecimalCol(Col): ! baseClass = SODecimalCol ! class SOCurrencyCol(SODecimalCol): + def __init__(self, **kw): + pushKey(kw, 'size', 10) + pushKey(kw, 'precision', 2) + SODecimalCol.__init__(self, **kw) def popKey(kw, name, default=None): *************** *** 273,283 **** return value all = [] for key, value in globals().items(): ! try: ! if issubclass(value, Col): ! all.append(key) ! except TypeError: ! pass __all__ = all --- 330,341 ---- return value + def pushKey(kw, name, value): + if not kw.has_key(name): + kw[name] = value + all = [] for key, value in globals().items(): ! if isinstance(value, type) and issubclass(value, Col): ! all.append(key) __all__ = all Index: DBConnection.py =================================================================== RCS file: /cvsroot/sqlobject/SQLObject/SQLObject/DBConnection.py,v retrieving revision 1.32 retrieving revision 1.33 diff -C2 -d -r1.32 -r1.33 *** DBConnection.py 5 May 2003 17:35:19 -0000 1.32 --- DBConnection.py 6 May 2003 22:43:34 -0000 1.33 *************** *** 164,168 **** (cls._table, cls._idName, ", ".join(["%s.%s" % (cls._table, col.dbName) ! for col in cls._columns]), ", ".join(select.tables)) --- 164,168 ---- (cls._table, cls._idName, ", ".join(["%s.%s" % (cls._table, col.dbName) ! for col in cls._SO_columns]), ", ".join(select.tables)) *************** *** 221,225 **** columnDefs = [self.createIDColumn(soClass)] \ + [self.createColumn(soClass, col) ! for col in soClass._columns] return ",\n".join([" %s" % c for c in columnDefs]) --- 221,225 ---- columnDefs = [self.createIDColumn(soClass)] \ + [self.createColumn(soClass, col) ! for col in soClass._SO_columns] return ",\n".join([" %s" % c for c in columnDefs]) *************** *** 399,403 **** colClass, kw = self.guessClass(t) kw['name'] = soClass._style.dbColumnToPythonAttr(field) ! kw['notNull'] = not nullAllowed kw['default'] = default # @@ skip key... --- 399,403 ---- colClass, kw = self.guessClass(t) kw['name'] = soClass._style.dbColumnToPythonAttr(field) ! kw['notNone'] = not nullAllowed kw['default'] = default # @@ skip key... *************** *** 520,524 **** colClass, kw = self.guessClass(t) kw['name'] = soClass._style.dbColumnToPythonAttr(field) ! kw['notNull'] = notnull if defaultstr is not None: kw['default'] = getattr(SQLBuilder.const, defaultstr) --- 520,524 ---- colClass, kw = self.guessClass(t) kw['name'] = soClass._style.dbColumnToPythonAttr(field) ! kw['notNone'] = notnull if defaultstr is not None: kw['default'] = getattr(SQLBuilder.const, defaultstr) *************** *** 670,678 **** clauses = [] for name, value in kw.items(): ! clauses.append(getattr(SQLBuilder.SmartTable(soClass._table), name) == value) return SQLBuilder.AND(*clauses) def _SO_selectJoin(self, soClass, column, value): results = [] for id in self._allIDs(soClass._table): d = self._fetchDict(soClass._table, id) --- 670,680 ---- clauses = [] for name, value in kw.items(): ! clauses.append(getattr(soClass.q, name) == value) return SQLBuilder.AND(*clauses) def _SO_selectJoin(self, soClass, column, value): results = [] + # @@: seems lame I need to do this... + value = int(value) for id in self._allIDs(soClass._table): d = self._fetchDict(soClass._table, id) Index: SQLObject.py =================================================================== RCS file: /cvsroot/sqlobject/SQLObject/SQLObject/SQLObject.py,v retrieving revision 1.32 retrieving revision 1.33 diff -C2 -d -r1.32 -r1.33 *** SQLObject.py 5 May 2003 20:40:37 -0000 1.32 --- SQLObject.py 6 May 2003 22:43:35 -0000 1.33 *************** *** 87,96 **** column = Col.Col(column) columns.append(column) for attr, value in d.items(): if isinstance(value, Col.Col): ! value.name = attr ! columns.append(value) del d[attr] - d['_columns'] = columns # We *don't* want to inherit _table, so we make sure it --- 87,99 ---- column = Col.Col(column) columns.append(column) + if columns: + d['_columns'] = columns + + implicitColumns = [] for attr, value in d.items(): if isinstance(value, Col.Col): ! value.setName(attr) ! implicitColumns.append(value) del d[attr] # We *don't* want to inherit _table, so we make sure it *************** *** 108,111 **** --- 111,120 ---- newClass._SO_finishedClassCreation = False + # We append to _columns, but we don't want to change the + # superclass's _columns list, so we make a copy if necessary + if not d.has_key('_columns'): + newClass._columns = newClass._columns[:] + newClass._columns.extend(implicitColumns) + ###################################################### # Set some attributes to their defaults, if necessary. *************** *** 148,151 **** --- 157,161 ---- # This is a dictionary of columnName: columnObject newClass._SO_columnDict = {} + newClass._SO_columns = [] # If _table isn't given, use style default *************** *** 288,291 **** --- 298,303 ---- _connection = None + _columns = [] + _joins = [] *************** *** 329,340 **** return val ! def addColumn(cls, column, changeSchema=False): ! column.setClass(cls) name = column.name assert name != 'id', "The 'id' column is implicit, and should not be defined as a column" cls._SO_columnDict[name] = column ! if column not in cls._columns: ! cls._columns.append(column) ################################################### --- 341,353 ---- return val ! def addColumn(cls, columnDef, changeSchema=False): ! column = columnDef.withClass(cls) name = column.name assert name != 'id', "The 'id' column is implicit, and should not be defined as a column" cls._SO_columnDict[name] = column + cls._SO_columns.append(column) ! if columnDef not in cls._columns: ! cls._columns.append(columnDef) ################################################### *************** *** 435,441 **** def addColumnsFromDatabase(cls): ! for column in cls._connection.columnsFromSchema(cls._table, cls): ! if not cls._SO_columnDict.has_key(column.name): ! cls.addColumn(column) addColumnsFromDatabase = classmethod(addColumnsFromDatabase) --- 448,459 ---- def addColumnsFromDatabase(cls): ! for columnDef in cls._connection.columnsFromSchema(cls._table, cls): ! alreadyExists = False ! for c in cls._columns: ! if c.kw['name'] == columnDef.kw['name']: ! alreadyExists = True ! break ! if not alreadyExists: ! cls.addColumn(columnDef) addColumnsFromDatabase = classmethod(addColumnsFromDatabase) *************** *** 444,448 **** if isinstance(column, str): column = cls._SO_columnDict[column] ! cls._columns.remove(column) name = column.name del cls._SO_columnDict[name] --- 462,472 ---- if isinstance(column, str): column = cls._SO_columnDict[column] ! if isinstance(column, Col.Col): ! for c in cls._SO_columns: ! if column is c.columnDef: ! column = c ! break ! cls._SO_columns.remove(column) ! cls._columns.remove(column.columnDef) name = column.name del cls._SO_columnDict[name] *************** *** 570,574 **** self._SO_perConnection = True ! dbNames = [col.dbName for col in self._columns] if not selectResults: selectResults = (connection or self._connection)._SO_selectOne(self, dbNames) --- 594,598 ---- self._SO_perConnection = True ! dbNames = [col.dbName for col in self._SO_columns] if not selectResults: selectResults = (connection or self._connection)._SO_selectOne(self, dbNames) *************** *** 629,633 **** def _SO_selectInit(self, row): ! for col, colValue in zip(self._columns, row): setattr(self, instanceName(col.name), colValue) --- 653,657 ---- def _SO_selectInit(self, row): ! for col, colValue in zip(self._SO_columns, row): setattr(self, instanceName(col.name), colValue) *************** *** 659,663 **** # First we do a little fix-up on the keywords we were # passed: ! for column in inst._columns: # If a foreign key is given, we get the ID of the object --- 683,687 ---- # First we do a little fix-up on the keywords we were # passed: ! for column in inst._SO_columns: # If a foreign key is given, we get the ID of the object *************** *** 695,699 **** # The rest go through setattr(): for name, value in others.items(): ! if not cls.__dict__.has_key(name): raise TypeError, "%s.new() got an unexpected keyword argument %s" % (cls.__name__, name) setattr(inst, name, value) --- 719,725 ---- # The rest go through setattr(): for name, value in others.items(): ! try: ! getattr(cls, name) ! except AttributeError: raise TypeError, "%s.new() got an unexpected keyword argument %s" % (cls.__name__, name) setattr(inst, name, value) *************** *** 732,736 **** cls, [cls._idName] + ! [col.dbName for col in cls._columns], dbIDName, value) --- 758,762 ---- cls, [cls._idName] + ! [col.dbName for col in cls._SO_columns], dbIDName, value) *************** *** 833,837 **** def _reprItems(self): items = [] ! for col in self._columns: value = getattr(self, col.name) r = repr(value) --- 859,863 ---- def _reprItems(self): items = [] ! for col in self._SO_columns: value = getattr(self, col.name) r = repr(value) |
From: <ian...@us...> - 2003-05-06 22:43:40
|
Update of /cvsroot/sqlobject/SQLObject/tests In directory sc8-pr-cvs1:/tmp/cvs-serv9293/tests Modified Files: test.py Log Message: * Col objects are more like definitions/factories, SO* classes do the actual work (to the degree there is work there) * SQLObject classes can inherit from each other * New ._SO_columns attribute that holds the non-factory columns Index: test.py =================================================================== RCS file: /cvsroot/sqlobject/SQLObject/tests/test.py,v retrieving revision 1.11 retrieving revision 1.12 diff -C2 -d -r1.11 -r1.12 *** test.py 6 May 2003 21:02:00 -0000 1.11 --- test.py 6 May 2003 22:43:35 -0000 1.12 *************** *** 363,369 **** def testSuper(self): - return - print 'super', Super._columns - print 'sub', Sub._columns s1 = Super.new(name='one') s2 = Super.new(name='two') --- 363,366 ---- *************** *** 372,376 **** def testSub(self): - return s1 = Sub.new(name='one', name2='1') s2 = Sub.new(name='two', name2='2') --- 369,372 ---- |
From: <ian...@us...> - 2003-05-06 21:02:05
|
Update of /cvsroot/sqlobject/SQLObject/tests In directory sc8-pr-cvs1:/tmp/cvs-serv29477/tests Modified Files: test.py Log Message: Added a test of MultipleJoin Index: test.py =================================================================== RCS file: /cvsroot/sqlobject/SQLObject/tests/test.py,v retrieving revision 1.10 retrieving revision 1.11 diff -C2 -d -r1.10 -r1.11 *** test.py 5 May 2003 17:35:20 -0000 1.10 --- test.py 6 May 2003 21:02:00 -0000 1.11 *************** *** 33,36 **** --- 33,45 ---- self.assertEqual(bob.passwd, 'god'.encode('rot13')) + class TestCaseGetSet(TestCase1): + + def testGet(self): + bob = TestSO1.selectBy(name='bob')[0] + self.assertEqual(bob.name, 'bob') + bob.name = 'joe' + self.assertEqual(bob.name, 'joe') + + ######################################## ## Delete during select *************** *** 298,301 **** --- 307,348 ---- def assertNamesEqual(self, people, dest): self.assertEqual([p.name for p in people], dest) + + class PersonJoiner2(SQLObject): + + _columns = [StringCol('name', length=40, alternateID=True)] + _joins = [MultipleJoin('AddressJoiner2')] + + class AddressJoiner2(SQLObject): + + _columns = [StringCol('zip', length=5), + KeyCol('personJoiner2ID', foreignKey='PersonJoiner2')] + + class JoinTest2(SQLObjectTest): + + classes = [PersonJoiner2, AddressJoiner2] + + def inserts(self): + p1 = PersonJoiner2.new(name='bob') + p2 = PersonJoiner2.new(name='sally') + for z in ['11111', '22222', '33333']: + a = AddressJoiner2.new(zip=z, personJoiner2=p1) + #p1.addAddressJoiner2(a) + AddressJoiner2.new(zip='00000', personJoiner2=p2) + + def test(self): + bob = PersonJoiner2.byName('bob') + sally = PersonJoiner2.byName('sally') + self.assertEqual(len(bob.addressJoiner2s), 3) + self.assertEqual(len(sally.addressJoiner2s), 1) + bob.addressJoiner2s[0].destroySelf() + self.assertEqual(len(bob.addressJoiner2s), 2) + z = bob.addressJoiner2s[0] + z.zip = 'xxxxx' + id = z.id + del z + z = AddressJoiner2(id) + self.assertEqual(z.zip, 'xxxxx') + + ######################################## |
From: <ian...@us...> - 2003-05-05 20:42:12
|
Update of /cvsroot/sqlobject/SQLObject/SQLObject In directory sc8-pr-cvs1:/tmp/cvs-serv14782/SQLObject Modified Files: Cache.py Log Message: Added clear method to CacheSet too... Index: Cache.py =================================================================== RCS file: /cvsroot/sqlobject/SQLObject/SQLObject/Cache.py,v retrieving revision 1.6 retrieving revision 1.7 diff -C2 -d -r1.6 -r1.7 *** Cache.py 5 May 2003 20:40:37 -0000 1.6 --- Cache.py 5 May 2003 20:42:08 -0000 1.7 *************** *** 174,175 **** --- 174,183 ---- except KeyError: pass + + def clear(self, cls=None): + if cls is None: + for cache in self.caches.values(): + cache.clear() + elif self.caches.has_key(cls.__name__): + self.caches[cls.__name__].clear() + |
From: <ian...@us...> - 2003-05-05 20:40:40
|
Update of /cvsroot/sqlobject/SQLObject/SQLObject In directory sc8-pr-cvs1:/tmp/cvs-serv13460/SQLObject Modified Files: Cache.py SQLObject.py Log Message: * Fixed bug with cached attributes not being updated * Added clear method to cache objects Index: Cache.py =================================================================== RCS file: /cvsroot/sqlobject/SQLObject/SQLObject/Cache.py,v retrieving revision 1.5 retrieving revision 1.6 diff -C2 -d -r1.5 -r1.6 *** Cache.py 17 Apr 2003 02:59:29 -0000 1.5 --- Cache.py 5 May 2003 20:40:37 -0000 1.6 *************** *** 135,138 **** --- 135,145 ---- self.lock.release() + def clear(self): + self.lock.acquire() + for key, value in self.cache.items(): + self.expiredCache[id] = ref(obj) + self.cache = {} + self.lock.release() + class CacheSet(object): Index: SQLObject.py =================================================================== RCS file: /cvsroot/sqlobject/SQLObject/SQLObject/SQLObject.py,v retrieving revision 1.31 retrieving revision 1.32 diff -C2 -d -r1.31 -r1.32 *** SQLObject.py 5 May 2003 17:35:19 -0000 1.31 --- SQLObject.py 5 May 2003 20:40:37 -0000 1.32 *************** *** 559,563 **** # anytime the object was returned from cache. self.id = id - self._SO_autoInitDone = False self._SO_writeLock = threading.Lock() # If no connection was given, we'll inherit the class --- 559,562 ---- *************** *** 591,605 **** return - # There's a write lock. Not sure if I need this... - #self._SO_writeLock.acquire() self._connection._SO_update(self, [(self._SO_columnDict[name].dbName, value)]) ! # _SO_autoInitDone implies there's a cached value we also ! # have to update. ! if self._SO_autoInitDone: setattr(self, instanceName(name), value) - #self._SO_writeLock.release() def set(self, **kw): --- 590,599 ---- return self._connection._SO_update(self, [(self._SO_columnDict[name].dbName, value)]) ! if self._cacheValues: setattr(self, instanceName(name), value) def set(self, **kw): *************** *** 626,630 **** if self._SO_plainSetters.has_key(name): toUpdate[name] = value ! if self._SO_autoInitDone: setattr(self, instanceName(name), value) else: --- 620,624 ---- if self._SO_plainSetters.has_key(name): toUpdate[name] = value ! if self._cacheValues: setattr(self, instanceName(name), value) else: *************** *** 744,748 **** raise SQLObjectNotFound, "The %s by alternateID %s=%s does not exist" % (cls.__name__, dbIDName, repr(value)) obj = cls(result[0]) ! if not obj._SO_autoInitDone: obj._SO_writeLock.acquire() obj._SO_selectInit(result[1:]) --- 738,742 ---- raise SQLObjectNotFound, "The %s by alternateID %s=%s does not exist" % (cls.__name__, dbIDName, repr(value)) obj = cls(result[0]) ! if not obj._cacheValues: obj._SO_writeLock.acquire() obj._SO_selectInit(result[1:]) *************** *** 822,826 **** # Kills this object. Kills it dead! self._SO_obsolete = True - self._SO_autoInitDone = False self._connection._SO_delete(self) self._connection.cache.purge(self.id, self.__class__) --- 816,819 ---- |
From: <ian...@us...> - 2003-05-05 17:55:51
|
Update of /cvsroot/sqlobject/SQLObject/SQLObject In directory sc8-pr-cvs1:/tmp/cvs-serv12093/SQLObject Modified Files: Style.py Log Message: Style tweak: PPerson -> p_person, not pperson; XXPerson -> xx_person Index: Style.py =================================================================== RCS file: /cvsroot/sqlobject/SQLObject/SQLObject/Style.py,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** Style.py 21 Apr 2003 22:50:32 -0000 1.1 --- Style.py 5 May 2003 17:55:48 -0000 1.2 *************** *** 99,107 **** if s.endswith('ID'): return mixedToUnder(s[:-2] + "_id") ! trans = _mixedToUnderRE.sub(lambda x: '_%s' % x.group(0).lower(), s) if trans.startswith('_'): trans = trans[1:] return trans _underToMixedRE = re.compile('_.') --- 99,113 ---- if s.endswith('ID'): return mixedToUnder(s[:-2] + "_id") ! trans = _mixedToUnderRE.sub(mixedToUnderSub, s) if trans.startswith('_'): trans = trans[1:] return trans + def mixedToUnderSub(match): + m = match.group(0).lower() + if len(m) > 1: + return '_%s_%s' % (m[:-1], m[-1]) + else: + return '_%s' % m _underToMixedRE = re.compile('_.') |
From: <ian...@us...> - 2003-05-05 17:53:06
|
Update of /cvsroot/sqlobject/SQLObject/tests In directory sc8-pr-cvs1:/tmp/cvs-serv1423/tests Modified Files: test.py Log Message: * SomeClass.q.colName now uses proper dbNames * orderBy clauses translate to dbName Index: test.py =================================================================== RCS file: /cvsroot/sqlobject/SQLObject/tests/test.py,v retrieving revision 1.9 retrieving revision 1.10 diff -C2 -d -r1.9 -r1.10 *** test.py 19 Apr 2003 00:54:25 -0000 1.9 --- test.py 5 May 2003 17:35:20 -0000 1.10 *************** *** 21,27 **** classes = [TestSO1] def inserts(self): ! for name, passwd in [('bob', 'god'), ('sally', 'sordid'), ! ('dave', 'dremel'), ('fred', 'forgo')]: TestSO1.new(name=name, passwd=passwd) --- 21,29 ---- classes = [TestSO1] + info = [('bob', 'god'), ('sally', 'sordid'), + ('dave', 'dremel'), ('fred', 'forgo')] + def inserts(self): ! for name, passwd in self.info: TestSO1.new(name=name, passwd=passwd) *************** *** 32,35 **** --- 34,53 ---- ######################################## + ## Delete during select + ######################################## + + class DeleteSelectTest(TestCase1): + + def testGet(self): + return + + def testSelect(self): + for obj in TestSO1.select('all'): + obj.destroySelf() + self.assertEqual(list(TestSO1.select('all')), []) + + + + ######################################## ## Enum test ######################################## *************** *** 280,283 **** --- 298,334 ---- def assertNamesEqual(self, people, dest): self.assertEqual([p.name for p in people], dest) + + ######################################## + ## Inheritance + ######################################## + + class Super(SQLObject): + + _columns = [StringCol('name', length=10)] + + class Sub(Super): + + _columns = Super._columns + [StringCol('name2', length=10)] + + class InheritanceTest(SQLObjectTest): + + classes = [Super, Sub] + + def testSuper(self): + return + print 'super', Super._columns + print 'sub', Sub._columns + s1 = Super.new(name='one') + s2 = Super.new(name='two') + s3 = Super(s1.id) + self.assertEqual(s1, s3) + + def testSub(self): + return + s1 = Sub.new(name='one', name2='1') + s2 = Sub.new(name='two', name2='2') + s3 = Sub(s1.id) + self.assertEqual(s1, s3) + |
From: <ian...@us...> - 2003-05-05 17:53:02
|
Update of /cvsroot/sqlobject/SQLObject/SQLObject In directory sc8-pr-cvs1:/tmp/cvs-serv1423/SQLObject Modified Files: DBConnection.py SQLBuilder.py SQLObject.py Log Message: * SomeClass.q.colName now uses proper dbNames * orderBy clauses translate to dbName Index: DBConnection.py =================================================================== RCS file: /cvsroot/sqlobject/SQLObject/SQLObject/DBConnection.py,v retrieving revision 1.31 retrieving revision 1.32 diff -C2 -d -r1.31 -r1.32 *** DBConnection.py 29 Apr 2003 09:36:25 -0000 1.31 --- DBConnection.py 5 May 2003 17:35:19 -0000 1.32 *************** *** 181,184 **** --- 181,186 ---- if type(s) is type(""): assert SQLBuilder.sqlIdentifier(s), "Strings in clauses are expected to be column identifiers. I got: %r" % s + if select.sourceClass._SO_columnDict.has_key(s): + s = select.sourceClass._SO_columnDict[s].dbName return s else: Index: SQLBuilder.py =================================================================== RCS file: /cvsroot/sqlobject/SQLObject/SQLObject/SQLBuilder.py,v retrieving revision 1.4 retrieving revision 1.5 diff -C2 -d -r1.4 -r1.5 *** SQLBuilder.py 18 Apr 2003 08:20:53 -0000 1.4 --- SQLBuilder.py 5 May 2003 17:35:19 -0000 1.5 *************** *** 350,359 **** raise ValueError, "Tables don't have values" ! class SmartTable(Table): ! _capRE = re.compile(r'[A-Z]+') def __getattr__(self, attr): ! if self._capRE.search(attr): ! attr = attr[0] + self._capRE.sub(lambda m: '_%s' % m.group(0).lower(), attr[1:]) ! return Table.__getattr__(self, attr) class Field(SQLExpression): --- 350,365 ---- raise ValueError, "Tables don't have values" ! class SQLObjectTable(Table): ! ! def __init__(self, soClass): ! self.soClass = soClass ! Table.__init__(self, soClass._table) ! def __getattr__(self, attr): ! if attr == 'id': ! return Table.__getattr__(self, self.soClass._idName) ! else: ! return Table.__getattr__( ! self, self.soClass._SO_columnDict[attr].dbName) class Field(SQLExpression): Index: SQLObject.py =================================================================== RCS file: /cvsroot/sqlobject/SQLObject/SQLObject/SQLObject.py,v retrieving revision 1.30 retrieving revision 1.31 diff -C2 -d -r1.30 -r1.31 *** SQLObject.py 29 Apr 2003 09:47:48 -0000 1.30 --- SQLObject.py 5 May 2003 17:35:19 -0000 1.31 *************** *** 160,164 **** # SQL where-clause generation. See the sql module for # more. ! newClass.q = SQLBuilder.SmartTable(newClass._table) for column in newClass._columns[:]: --- 160,164 ---- # SQL where-clause generation. See the sql module for # more. ! newClass.q = SQLBuilder.SQLObjectTable(newClass) for column in newClass._columns[:]: |
From: <ian...@us...> - 2003-05-05 17:37:23
|
Update of /cvsroot/sqlobject/SQLObject/SQLObject In directory sc8-pr-cvs1:/tmp/cvs-serv2632/SQLObject Modified Files: Col.py Log Message: Added sqlType argument to Col Index: Col.py =================================================================== RCS file: /cvsroot/sqlobject/SQLObject/SQLObject/Col.py,v retrieving revision 1.17 retrieving revision 1.18 diff -C2 -d -r1.17 -r1.18 *** Col.py 29 Apr 2003 09:37:06 -0000 1.17 --- Col.py 5 May 2003 17:37:19 -0000 1.18 *************** *** 18,26 **** class Col(object): ! def __init__(self, name=None, dbName=None, default=NoDefault, foreignKey=None, ! alternateID=False, alternateMethodName=None, ! constraints=None, notNull=False, ! unique=NoDefault): # This isn't strictly true, since we *could* use backquotes # around column names, but why would anyone *want* to --- 18,32 ---- class Col(object): ! def __init__(self, ! name=None, ! dbName=None, ! default=NoDefault, foreignKey=None, ! alternateID=False, ! alternateMethodName=None, ! constraints=None, ! notNull=False, ! unique=NoDefault, ! sqlType=None): # This isn't strictly true, since we *could* use backquotes # around column names, but why would anyone *want* to *************** *** 49,52 **** --- 55,59 ---- self.soClass = None self._default = default + self.customSQLType = sqlType def setClass(self, soClass): *************** *** 117,121 **** def _sqlType(self): ! raise ValueError, "Col cannot be used for automatic schema creation (too abstract)" def _mysqlType(self): --- 124,131 ---- def _sqlType(self): ! if self.customSQLType is None: ! raise ValueError, "Col cannot be used for automatic schema creation (too abstract)" ! else: ! return self.customSQLType def _mysqlType(self): |