Changeset 188
- Timestamp:
- 03/07/06 17:32:23
- Files:
-
- trunk/arenas.py (modified) (3 diffs)
- trunk/doc/managing.html (modified) (2 diffs)
- trunk/doc/modeling.html (modified) (4 diffs)
- trunk/engines.py (modified) (4 diffs)
- trunk/storage/__init__.py (modified) (1 diff)
- trunk/storage/db.py (modified) (6 diffs)
- trunk/storage/storeado.py (modified) (5 diffs)
- trunk/storage/storemysql.py (modified) (4 diffs)
- trunk/storage/storepypgsql.py (modified) (2 diffs)
- trunk/storage/storeshelve.py (modified) (1 diff)
- trunk/storage/storesqlite.py (modified) (2 diffs)
- trunk/test/zoo_fixture.py (modified) (1 diff)
- trunk/units.py (modified) (6 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/arenas.py
r187 r188 227 227 # Allow identifiers to be supplied as args or kwargs 228 228 # (since the common case will be a single identifier). 229 for arg, idin zip(args, cls.identifiers):230 kwargs[str( id.key)] = arg229 for arg, key in zip(args, cls.identifiers): 230 kwargs[str(key)] = arg 231 231 expr = logic.filter(**kwargs) 232 232 try: … … 437 437 indices = [] 438 438 added_fields = 0 439 for propin cls.identifiers:440 if prop.key not in fields:439 for key in cls.identifiers: 440 if key not in fields: 441 441 added_fields += 1 442 fields.append( prop.key)443 indices.append(fields.index( prop.key))442 fields.append(key) 443 indices.append(fields.index(key)) 444 444 445 445 for row in self.arena.storage(cls).view(cls, fields, expr): … … 482 482 def count(self, cls, expr): 483 483 """count(cls, expr) -> Number of Units of class 'cls'.""" 484 idnames = [prop.key for prop in cls.identifiers] 485 return len(self.distinct(cls, idnames, expr)) 484 return len(self.distinct(cls, cls.identifiers, expr)) 486 485 487 486 #################################### trunk/doc/managing.html
r187 r188 277 277 278 278 <h4>Collections: Lists of Units</h4> 279 <p>The <tt>UnitCollection</tt> class provides a means of storing a list 280 of Units, or rather, a list of Unit identifiers. You use its <tt>Type</tt>279 <p>The <tt>UnitCollection</tt> class provides a means of storing a list of 280 Units, or rather, a list of Unit identifier values. You use its <tt>Type</tt> 281 281 property to indicate the class of the indexed Units. That value should be 282 282 the <b>name</b> of the Unit Class, <b>not</b> the class object itself … … 296 296 297 297 <p>When you need to retrieve the actual Units which are indexed by the 298 Collection, call the <tt class='def'>units(quota=None)</tt> method, 299 which will 300 look up the Units and return them in a list. Since the Collection only 301 stores identifiers, it is possible that one of the indexed Units may have 298 Collection, call the <tt class='def'>units(quota=None)</tt> method, which 299 will look up the Units and return them in a list. Since the Collection only 300 stores identifier values, it is possible that one of the indexed Units may have 302 301 been destroyed since the list was built. The <tt>units</tt> method simply 303 302 passes over these "phantom" Units. You can inspect the full list of IDs trunk/doc/modeling.html
r187 r188 68 68 <h4>Unit ID's</h4> 69 69 <p>All Units possess an <tt>identifiers</tt> attribute, a tuple of 70 their UnitProperties which define the uniqueness of a Unit. The70 their UnitProperties names which define the uniqueness of a Unit. The 71 71 <tt>Unit</tt> base class possesses a single Unit Property, an int 72 72 named 'ID', and its <tt>identifiers</tt> attribute is therefore 73 <tt>(ID,)</tt>. That's not a string in the tuple; it's a reference 74 to the actual UnitProperty class. If you wish to use identifiers 73 <tt>('ID',)</tt>. That's a string in the tuple; older versions of Dejavu 74 used a reference to the actual UnitProperty class instead. If you wish 75 to use identifiers 75 76 of a different number, types, or names, simply replace the 76 77 <tt>identifiers</tt> attribute in your subclass:</p> … … 82 83 Model = UnitProperty(unicode) 83 84 UnitNumber = UnitProperty(int) 84 identifiers = ( Model, UnitNumber)85 identifiers = ('Model', 'UnitNumber') 85 86 </pre> 86 87 … … 329 330 to help Sandboxes generate new IDs. The default value is an instance of 330 331 <tt>UnitSequencerInteger</tt>, which examines all existing Units, finds 331 the maximum integer ID, adds 1, and uses that value for the new ID.</p> 332 the maximum integer ID, adds 1, and uses that value for the new ID. 333 [StorageManagers are free to optimize any sequencer, whether builtin or 334 custom, in order to take advantage of ID-generation tools in the database 335 or other storage provider. All builtin database StorageManagers optimize 336 UnitSequencerInteger in this way.]</p> 332 337 333 338 <p>The other useful Sequencer is <tt>UnitSequencerNull</tt>, which simply … … 562 567 563 568 <p>The <tt>distinct</tt> function can also be used as a <tt>count</tt> 564 function by passing <tt>attrs = [prop.key for prop in cls.identifiers]</tt>.569 function by passing <tt>attrs = cls.identifiers</tt>. 565 570 Sandboxes provide a <tt class='def'>count(cls, expr)</tt> method which does 566 571 just this.</p> trunk/engines.py
r187 r188 126 126 def units(self, quota=None): 127 127 cls = self.unit_class() 128 idnames = [prop.key for prop in cls.identifiers]129 128 130 129 output = [] … … 134 133 if quota and i >= quota: 135 134 break 136 unit = self.sandbox.unit(cls, **dict(zip(idnames, eachID))) 135 filter = dict(zip(cls.identifiers, eachID)) 136 unit = self.sandbox.unit(cls, **filter) 137 137 if unit: 138 138 output.append(unit) … … 491 491 else: 492 492 newset = [] 493 idnames = [prop.key for prop in cls.identifiers]494 493 for id in mem: 495 unit = self.sandbox.unit(cls, **dict(zip(idnames, id))) 494 filter = dict(zip(cls.identifiers, id)) 495 unit = self.sandbox.unit(cls, **filter) 496 496 if unit and expr(unit): 497 497 newset.append(id) … … 584 584 A.universal = False 585 585 else: 586 idnames = [prop.key for prop in cls.identifiers]587 586 for id in A.Members: 588 unit = self.sandbox.unit(cls, **dict(zip(idnames, id))) 587 filter = dict(zip(cls.identifiers, id)) 588 unit = self.sandbox.unit(cls, **filter) 589 589 if unit: 590 590 farUnits = ua.__get__(unit)() trunk/storage/__init__.py
r187 r188 311 311 indices = [] 312 312 added_fields = 0 313 for propin cls.identifiers:314 if prop.key not in fields:315 fields.append( prop.key)313 for key in cls.identifiers: 314 if key not in fields: 315 fields.append(key) 316 316 added_fields += 1 317 indices.append(fields.index( prop.key))317 indices.append(fields.index(key)) 318 318 319 319 for row in self.nextstore.view(cls, fields, expr): trunk/storage/db.py
r187 r188 746 746 # Place the identifier properties first 747 747 # in case others depend upon them. 748 idnames = [prop.key for prop in wclass.identifiers]749 keys = idnames + [k for k in wclass.properties() if k not in idnames]748 keys = list(wclass.identifiers) + [k for k in wclass.properties() 749 if k not in wclass.identifiers] 750 750 cols = [(wclass, k) for k in keys] 751 751 colnames = ['%s.%s' % (self.alias or self.tablename, … … 1005 1005 # See load_expanded, for example. 1006 1006 props = [] 1007 idnames = [prop.key for prop in cls.identifiers]1007 idnames = list(cls.identifiers) 1008 1008 for key in idnames + [x for x in cls.properties() if x not in idnames]: 1009 1009 index, ftype = columns[self.column_name(clsname, key, quoted=False)] … … 1053 1053 if not unit.sequencer.valid_id(unit.identity()): 1054 1054 # Examine all existing IDs and grant the "next" one. 1055 id_fields = [self.column_name(clsname, prop.key)1056 for propin cls.identifiers]1055 id_fields = [self.column_name(clsname, key) 1056 for key in cls.identifiers] 1057 1057 data, cols = self.fetch('SELECT %s FROM %s;' % 1058 1058 (', '.join(id_fields), tablename)) … … 1061 1061 coerce = self.fromAdapter.coerce 1062 1062 coltypes = [cols[x][1] for x in xrange(len(cols))] 1063 expectedTypes = [prop.type for prop in cls.identifiers] 1063 expectedTypes = [getattr(cls, key).type 1064 for key in cls.identifiers] 1064 1065 newdata = [] 1065 1066 for row in data: … … 1095 1096 col = self.column_name 1096 1097 c = self.toAdapter.coerce 1097 idnames = [prop.key for prop in unit.identifiers]1098 1098 return " AND ".join(["%s = %s" % (col(clsname, key), 1099 1099 c(getattr(unit, key))) 1100 for key in idnames])1100 for key in unit.identifiers]) 1101 1101 1102 1102 def save(self, unit, forceSave=False): … … 1107 1107 1108 1108 parms = [] 1109 idnames = [prop.key for prop in cls.identifiers]1110 1109 for key in cls.properties(): 1111 if key not in idnames:1110 if key not in cls.identifiers: 1112 1111 subtype = self.expanded_columns.get((clsname, key)) 1113 1112 if subtype: trunk/storage/storeado.py
r187 r188 501 501 prop = getattr(cls, key) 502 502 if isinstance(cls.sequencer, dejavu.UnitSequencerInteger): 503 if propin cls.identifiers:503 if key in cls.identifiers: 504 504 return ("INTEGER IDENTITY(%s, 1) NOT NULL" 505 505 % cls.sequencer.initial) … … 582 582 data, col_defs = self.fetch("SELECT IDENT_CURRENT('%s');" 583 583 % str(tablename)) 584 setattr(unit, cls.identifiers[0] .key, data[0][0])584 setattr(unit, cls.identifiers[0], data[0][0]) 585 585 586 586 # Now that we have an ID, save our expanded tables. … … 710 710 prop = getattr(cls, key) 711 711 if isinstance(cls.sequencer, dejavu.UnitSequencerInteger): 712 if propin cls.identifiers:712 if key in cls.identifiers: 713 713 return "AUTOINCREMENT(%s, 1)" % cls.sequencer.initial 714 714 bytes = int(prop.hints.get('bytes', '4')) … … 721 721 prop = getattr(cls, key) 722 722 if isinstance(cls.sequencer, dejavu.UnitSequencerInteger): 723 if propin cls.identifiers:723 if key in cls.identifiers: 724 724 return "AUTOINCREMENT(%s, 1)" % cls.sequencer.initial 725 725 bytes = int(prop.hints.get('bytes', 0)) … … 818 818 # Grab the new ID. This is threadsafe because db.reserve has a mutex. 819 819 data, col_defs = self.fetch("SELECT @@IDENTITY;") 820 setattr(unit, cls.identifiers[0] .key, data[0][0])820 setattr(unit, cls.identifiers[0], data[0][0]) 821 821 822 822 # Now that we have an ID, save our expanded tables. trunk/storage/storemysql.py
r187 r188 125 125 typename = "INTEGER" 126 126 if isinstance(cls.sequencer, dejavu.UnitSequencerInteger): 127 if propin cls.identifiers:127 if key in cls.identifiers: 128 128 typename += " AUTO_INCREMENT" 129 129 return typename … … 246 246 # Grab the new ID. This is threadsafe because db.reserve has a mutex. 247 247 data, col_defs = self.fetch("SELECT LAST_INSERT_ID();") 248 setattr(unit, cls.identifiers[0] .key, data[0][0])248 setattr(unit, cls.identifiers[0], data[0][0]) 249 249 250 250 # Now that we have an ID, save our expanded tables. … … 278 278 dbtype = typename(cls, key) 279 279 fields.append('%s %s' % (qname, dbtype)) 280 if getattr(cls, key)in cls.identifiers:280 if key in cls.identifiers: 281 281 if dbtype.endswith('BLOB') or dbtype == 'TEXT': 282 282 # MySQL won't allow indexes on a BLOB field … … 298 298 # can't delete it until after the CREATE INDEX 299 299 # statements below (or the counter will revert). 300 colname = self.column_name(clsname, cls.identifiers[0] .key)300 colname = self.column_name(clsname, cls.identifiers[0]) 301 301 self.execute("INSERT INTO %s (%s) VALUES (%s);" 302 302 % (tablename, colname, i - 1)) trunk/storage/storepypgsql.py
r187 r188 16 16 prop = getattr(cls, key) 17 17 if isinstance(cls.sequencer, dejavu.UnitSequencerInteger): 18 if propin cls.identifiers:18 if key in cls.identifiers: 19 19 return ("INTEGER DEFAULT nextval('%s_%s_seq') NOT NULL" 20 20 % (cls.__name__, key)) … … 148 148 # Grab the new ID. This is threadsafe because db.reserve has a mutex. 149 149 data, col_defs = self.fetch("SELECT last_value FROM %s_%s_seq;" 150 % (clsname, cls.identifiers[0] .key))151 setattr(unit, cls.identifiers[0] .key, data[0][0])150 % (clsname, cls.identifiers[0])) 151 setattr(unit, cls.identifiers[0], data[0][0]) 152 152 153 153 # Now that we have an ID, save our expanded tables. trunk/storage/storeshelve.py
r187 r188 91 91 try: 92 92 if not unit.sequencer.valid_id(unit.identity()): 93 ids = [[row[ prop.key] for propin unit.identifiers]93 ids = [[row[key] for key in unit.identifiers] 94 94 for row in data.itervalues()] 95 95 unit.sequencer.assign(unit, ids) trunk/storage/storesqlite.py
r187 r188 139 139 if _autoincrement_support: 140 140 prop = getattr(cls, key, None) 141 if prop and prop.type is int and propin cls.identifiers:141 if prop and prop.type is int and key in cls.identifiers: 142 142 if isinstance(cls.sequencer, dejavu.UnitSequencerInteger): 143 143 return "INTEGER PRIMARY KEY AUTOINCREMENT" … … 308 308 # Grab the new ID. This is safe because db.reserve has a mutex. 309 309 new_id = conn.sqlite_last_insert_rowid() 310 setattr(unit, cls.identifiers[0] .key, new_id)310 setattr(unit, cls.identifiers[0], new_id) 311 311 312 312 # Now that we have an ID, save our expanded tables. trunk/test/zoo_fixture.py
r187 r188 116 116 ID = None 117 117 sequencer = dejavu.UnitSequencerNull() 118 identifiers = ( ZooID, Name)118 identifiers = ("ZooID", Name) 119 119 120 120 Zoo.one_to_many('ID', Exhibit, 'ZooID') trunk/units.py
r187 r188 245 245 if m != (None,): 246 246 newvalue = m[0] + 1 247 unit.identifiers[0].__set__(unit, newvalue)247 setattr(unit, unit.identifiers[0], newvalue) 248 248 249 249 … … 281 281 % self.width) 282 282 newvalue = maxid 283 unit.identifiers[0].__set__(unit, newvalue)283 setattr(unit, unit.identifiers[0], newvalue) 284 284 285 285 … … 412 412 cls._properties = props 413 413 cls._associations = assocs 414 415 # Keep backward compatibility from 1.4 to 1.5. See ticket #48. 416 ident = dct.get('identifiers', ()) 417 if ident: 418 newident = [] 419 for val in ident: 420 if isinstance(val, UnitProperty): 421 # Substitute the name for the property 422 val = val.key 423 newident.append(val) 424 cls.identifiers = tuple(newident) 414 425 415 426 def __lshift__(self, other): … … 487 498 ID = UnitProperty(int, index=True) 488 499 sequencer = UnitSequencerInteger() 489 identifiers = ( ID,)500 identifiers = ("ID",) 490 501 491 502 def __init__(self, **kwargs): … … 514 525 def __copy__(self): 515 526 newUnit = self.__class__() 516 for key in self.__class__.properties(): 517 if key not in self.identifiers: 527 for key, prop in self.__class__._properties.iteritems(): 528 if key in self.identifiers: 529 newUnit._properties[key] = prop.default 530 else: 518 531 newUnit._properties[key] = self._properties[key] 519 for prop in self.identifiers:520 prop.__set__(newUnit, None)521 532 newUnit.sandbox = None 522 533 return newUnit … … 536 547 def identity(self): 537 548 # Must be immutable for use as a dictionary key. 538 return tuple([ prop.__get__(self) for propin self.identifiers])549 return tuple([getattr(self, key) for key in self.identifiers]) 539 550 540 551 def _property_hash(self):
