Changeset 505
- Timestamp:
- 09/23/07 22:49:29
- Files:
-
- trunk/dejavu/errors.py (modified) (2 diffs)
- trunk/dejavu/schemas.py (modified) (2 diffs)
- trunk/dejavu/storage/__init__.py (modified) (8 diffs)
- trunk/dejavu/storage/db.py (modified) (16 diffs)
- trunk/dejavu/storage/multischema.py (modified) (6 diffs)
- trunk/dejavu/storage/partitions.py (modified) (6 diffs)
- trunk/dejavu/storage/storefs.py (modified) (4 diffs)
- trunk/dejavu/storage/storeram.py (modified) (4 diffs)
- trunk/dejavu/storage/storeshelve.py (modified) (14 diffs)
- trunk/dejavu/test/zoo_fixture.py (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/dejavu/errors.py
r504 r505 1 """Exception classes for Dejavu.""" 2 1 3 2 4 class DejavuError(Exception): … … 33 35 """ 34 36 pass 37 38 39 40 # -------------------------- Conflict handling -------------------------- # 41 42 43 class ConflictHandler(object): 44 """Dispatcher for behavior upon encountering a mapping conflict. 45 46 When MappingErrors are encountered, a singleton instance of this class 47 is used to respond to the error based upon a supplied mode. You can add 48 failure modes (and their corresponding behaviors) by adding methods to 49 this class. 50 51 In general, only leaf nodes need call this object; pure proxies and 52 storage mixers which simply pass calls through to (possibly multiple) 53 child storage nodes may safely rely on the behavior of their child 54 nodes by passing the 'conflicts' argument through to all children. 55 """ 56 57 def __call__(self, mode, msg): 58 """React to a conflict according to the given mode. 59 60 mode: This argument determines what happens when there are 61 discrepancies between the Dejavu model and the actual database. 62 63 If 'error' (the default), MappingError is raised for the 64 first issue and the call is aborted. 65 66 If 'warn', then a StorageWarning is raised (instead of an error) 67 for each issue, and the call is not aborted. This allows you to 68 see all errors at once, without having to stop and fix each one 69 and then execute the call again. 70 71 If 'repair', then each issue will be resolved by changing 72 the database to match the model. Not all calls support this 73 mode for all errors; any which do not support this mode will 74 error instead. 75 76 If 'ignore', any model conflicts are silently ignored. 77 Use of this mode causes mandelbugs. You have been warned. 78 """ 79 func = getattr(self, mode, None) 80 if func is None: 81 raise ValueError("Conflict mode %r not recognized." % mode) 82 return func(msg) 83 84 def warn(self, msg): 85 import warnings 86 warnings.warn(msg, StorageWarning) 87 88 def ignore(self, msg): 89 pass 90 91 def error(self, msg): 92 raise MappingError(msg) 93 94 conflict = ConflictHandler() 95 trunk/dejavu/schemas.py
r504 r505 65 65 """Retrieve our DeployedVersion unit, optionally creating it.""" 66 66 if not self.store.has_storage(DeployedVersion): 67 self.store. create_storage(DeployedVersion)67 self.store.map([DeployedVersion], conflicts='repair') 68 68 69 69 if self._deployed_unit is None: … … 143 143 easily if you run assert_storage before the upgrade methods. 144 144 """ 145 self.store.map_all(conflict _mode='repair')145 self.store.map_all(conflicts='repair') 146 146 147 147 def assert_version(self): trunk/dejavu/storage/__init__.py
r504 r505 6 6 except NameError: 7 7 from sets import Set as set 8 import warnings9 8 10 9 import dejavu … … 48 47 self.logflags = logflags.ERROR + logflags.IO 49 48 50 def shutdown(self): 49 def shutdown(self, conflicts='error'): 50 """Shut down all connections to internal storage. 51 52 conflicts: see errors.conflict. 53 """ 51 54 pass 52 55 … … 97 100 raise KeyError("No registered class found for '%s'." % classname) 98 101 99 def map(self, classes, conflict _mode='error'):102 def map(self, classes, conflicts='error'): 100 103 """Map classes to internal storage. 101 104 102 conflict_mode: This argument determines what happens when there are 103 discrepancies between the Dejavu model and the actual storage. 104 105 If 'error' (the default), MappingError is raised for the 106 first issue and the mapping process is aborted. 107 108 If 'warn', then a warning is raised (instead of an error) 109 for each issue, and the mapping process is not aborted. 110 This allows you to see all errors at once, without having 111 to stop and fix each one and then execute the process again. 112 113 If 'repair', then each issue will be resolved by changing 114 storage to match the model. 105 conflicts: see errors.conflict. 115 106 """ 116 107 for cls in classes: 117 108 if not self.has_storage(cls): 118 if conflict _mode== 'repair':109 if conflicts == 'repair': 119 110 self.create_storage(cls) 120 111 else: 121 msg = "%s: no storage found." % cls.__name__ 122 if conflict_mode == 'warn': 123 warnings.warn(msg) 124 else: 125 raise errors.MappingError(msg) 126 127 def map_all(self, conflict_mode='error'): 112 errors.conflict(conflicts, 113 "%s: no storage found." % cls.__name__) 114 115 def map_all(self, conflicts='error'): 128 116 """Map all registered classes to internal storage structures. 129 117 … … 135 123 to call it very often (once at app startup is usually enough). 136 124 137 conflict_mode: This argument determines what happens when there are 138 discrepancies between the Dejavu model and the actual database. 139 140 If 'error' (the default), MappingError is raised for the 141 first issue and the sync process is aborted. 142 143 If 'warn', then a warning is raised (instead of an error) 144 for each issue, and the sync process is not aborted. This 145 allows you to see all errors at once, without having to stop 146 and fix each one and then execute the process again. 147 148 If 'repair', then each issue will be resolved by changing 149 the database to match the model. 150 """ 151 self.map(self.classes, conflict_mode=conflict_mode) 152 153 def create_database(self): 125 conflicts: see errors.conflict. 126 """ 127 self.map(self.classes, conflicts=conflicts) 128 129 def create_database(self, conflicts='error'): 130 """Create internal structures for the entire database. 131 132 conflicts: see errors.conflict. 133 """ 154 134 raise NotImplementedError("%s has no create_database method." 155 135 % self.__class__) 156 136 157 def drop_database(self): 137 def drop_database(self, conflicts='error'): 138 """Destroy internal structures for the entire database. 139 140 conflicts: see errors.conflict. 141 """ 158 142 raise NotImplementedError("%s has no drop_database method." 159 143 % self.__class__) 160 144 161 def create_storage(self, cls): 145 def create_storage(self, cls, conflicts='error'): 146 """Create internal structures for the given class. 147 148 conflicts: see errors.conflict. 149 """ 162 150 raise NotImplementedError("%s has no create_storage method." 163 151 % self.__class__) 164 152 165 153 def has_storage(self, cls): 154 """If storage structures exist for the given class, return True.""" 166 155 raise NotImplementedError("%s has no has_storage method." 167 156 % self.__class__) 168 157 169 def drop_storage(self, cls): 158 def drop_storage(self, cls, conflicts='error'): 159 """Destroy internal structures for the given class. 160 161 conflicts: see errors.conflict. 162 """ 170 163 raise NotImplementedError("%s has no drop_storage method." 171 164 % self.__class__) 172 165 173 def add_property(self, cls, name): 166 def add_property(self, cls, name, conflicts='error'): 167 """Add internal structures for the given property. 168 169 conflicts: see errors.conflict. 170 """ 174 171 raise NotImplementedError("%s has no add_property method." 175 172 % self.__class__) 176 173 177 174 def has_property(self, cls, name): 175 """If storage structures exist for the given property, return True.""" 178 176 raise NotImplementedError("%s has no has_property method." 179 177 % self.__class__) 180 178 181 def drop_property(self, cls, name): 179 def drop_property(self, cls, name, conflicts='error'): 180 """Destroy internal structures for the given property. 181 182 conflicts: see errors.conflict. 183 """ 182 184 raise NotImplementedError("%s has no drop_property method." 183 185 % self.__class__) 184 186 185 def rename_property(self, cls, oldname, newname): 187 def rename_property(self, cls, oldname, newname, conflicts='error'): 188 """Rename internal structures for the given property. 189 190 conflicts: see errors.conflict. 191 """ 186 192 raise NotImplementedError("%s has no rename_property method." 187 193 % self.__class__) 188 194 189 def add_index(self, cls, name): 195 def add_index(self, cls, name, conflicts='error'): 196 """Add an index to the given property. 197 198 conflicts: see errors.conflict. 199 """ 190 200 raise NotImplementedError("%s has no add_index method." 191 201 % self.__class__) 192 202 193 203 def has_index(self, cls, name): 204 """If an index exists for the given property, return True.""" 194 205 raise NotImplementedError("%s has no has_index method." 195 206 % self.__class__) 196 207 197 def drop_index(self, cls, name): 208 def drop_index(self, cls, name, conflicts='error'): 209 """Destroy any index on the given property. 210 211 conflicts: see errors.conflict. 212 """ 198 213 raise NotImplementedError("%s has no drop_index method." 199 214 % self.__class__) … … 558 573 559 574 def xrecall(self, classes, expr=None, order=None, limit=None, offset=None): 575 """Return an iterable of Units.""" 560 576 if isinstance(classes, dejavu.UnitJoin): 561 577 for unitrow in self._xmultirecall(classes, expr, order=order, … … 608 624 return self.nextstore._xmultirecall(classes, expr, order, limit, offset) 609 625 610 def count(self, cls, expr=None):611 """Number of Units of the given cls which match the given expr."""612 if self.logflags & logflags.RECALL:613 self.log(logflags.RECALL.message(cls, ('count', expr)))614 return self.nextstore.count(cls, expr)615 616 626 # Schemas # 617 627 618 def map(self, classes, conflict _mode='error'):628 def map(self, classes, conflicts='error'): 619 629 """Map classes to internal storage. 620 630 621 conflict_mode: This argument determines what happens when there are 622 discrepancies between the Dejavu model and the actual database. 623 624 If 'error' (the default), MappingError is raised for the 625 first issue and the sync process is aborted. 626 627 If 'warn', then a warning is raised (instead of an error) 628 for each issue, and the sync process is not aborted. This 629 allows you to see all errors at once, without having to stop 630 and fix each one and then execute the process again. 631 632 If 'repair', then each issue will be resolved by changing 633 the database to match the model. 634 """ 635 self.nextstore.map(classes, conflict_mode) 636 637 def create_database(self): 631 conflict: see errors.conflict. 632 """ 633 self.nextstore.map(classes, conflicts=conflicts) 634 635 def create_database(self, conflicts='error'): 636 """Create internal structures for the entire database. 637 638 conflicts: see errors.conflict. 639 """ 638 640 if self.logflags & logflags.DDL: 639 641 self.log(logflags.DDL.message("create database")) 640 self.nextstore.create_database() 641 642 def drop_database(self): 642 self.nextstore.create_database(conflicts=conflicts) 643 644 def drop_database(self, conflicts='error'): 645 """Destroy internal structures for the entire database. 646 647 conflicts: see errors.conflict. 648 """ 643 649 if self.logflags & logflags.DDL: 644 650 self.log(logflags.DDL.message("drop database")) 645 self.nextstore.drop_database() 646 647 def create_storage(self, cls): 651 self.nextstore.drop_database(conflicts=conflicts) 652 653 def create_storage(self, cls, conflicts='error'): 654 """Create internal structures for the given class. 655 656 conflicts: see errors.conflict. 657 """ 648 658 if self.logflags & logflags.DDL: 649 659 self.log(logflags.DDL.message("create storage %r" % cls)) … … 651 661 652 662 def has_storage(self, cls): 663 """If storage structures exist for the given class, return True.""" 653 664 return self.nextstore.has_storage(cls) 654 665 655 def drop_storage(self, cls): 666 def drop_storage(self, cls, conflicts='error'): 667 """Destroy internal structures for the given class. 668 669 conflicts: see errors.conflict. 670 """ 656 671 if self.logflags & logflags.DDL: 657 672 self.log(logflags.DDL.message("drop storage %r" % cls)) 658 self.nextstore.drop_storage(cls) 659 660 def add_property(self, cls, name): 673 self.nextstore.drop_storage(cls, conflicts=conflicts) 674 675 def add_property(self, cls, name, conflicts='error'): 676 """Add internal structures for the given property. 677 678 conflicts: see errors.conflict. 679 """ 661 680 if self.logflags & logflags.DDL: 662 681 self.log(logflags.DDL.message("add property %r %r" % (cls, name))) 663 self.nextstore.add_property(cls, name) 664 665 def drop_property(self, cls, name): 682 self.nextstore.add_property(cls, name, conflicts=conflicts) 683 684 def has_property(self, cls, name): 685 """If storage structures exist for the given property, return True.""" 686 return self.nextstore.has_property(cls, name) 687 688 def drop_property(self, cls, name, conflicts='error'): 689 """Destroy internal structures for the given property. 690 691 conflicts: see errors.conflict. 692 """ 666 693 if self.logflags & logflags.DDL: 667 694 self.log(logflags.DDL.message("drop property %r %r" % (cls, name))) 668 self.nextstore.drop_property(cls, name) 669 670 def rename_property(self, cls, oldname, newname): 695 self.nextstore.drop_property(cls, name, conflicts=conflicts) 696 697 def rename_property(self, cls, oldname, newname, conflicts='error'): 698 """Rename internal structures for the given property. 699 700 conflicts: see errors.conflict. 701 """ 671 702 if self.logflags & logflags.DDL: 672 703 self.log(logflags.DDL.message("rename property %r from %r to %r" % 673 704 (cls, oldname, newname))) 674 self.nextstore.rename_property(cls, oldname, newname) 675 676 def shutdown(self): 677 self.nextstore.shutdown() 705 self.nextstore.rename_property(cls, oldname, newname, conflicts=conflicts) 706 707 def shutdown(self, conflicts='error'): 708 """Shut down all connections to internal storage. 709 710 conflicts: see errors.conflict. 711 """ 712 self.nextstore.shutdown(conflicts=conflicts) 713 714 def add_index(self, cls, name, conflicts='error'): 715 """Add an index to the given property. 716 717 conflicts: see errors.conflict. 718 """ 719 self.nextstore.add_index(cls, name, conflicts=conflicts) 720 721 def has_index(self, cls, name): 722 """If an index exists for the given property, return True.""" 723 return self.nextstore.has_index(cls, name) 724 725 def drop_index(self, cls, name, conflicts='error'): 726 """Destroy any index on the given property. 727 728 conflicts: see errors.conflict. 729 """ 730 self.nextstore.drop_index(cls, name, conflicts=conflicts) 678 731 679 732 … … 773 826 self.cache.destroy(unit) 774 827 775 def shutdown(self): 776 self.cache.shutdown() 777 self.nextstore.shutdown() 778 779 def add_property(self, cls, name): 828 def shutdown(self, conflicts='error'): 829 """Shut down all connections to internal storage. 830 831 conflicts: see errors.conflict. 832 """ 833 self.cache.shutdown(conflicts=conflicts) 834 self.nextstore.shutdown(conflicts=conflicts) 835 836 def add_property(self, cls, name, conflicts='error'): 837 """Add internal structures for the given property. 838 839 conflicts: see errors.conflict. 840 """ 780 841 if self.logflags & logflags.DDL: 781 842 self.log(logflags.DDL.message("add property %r %r" % (cls, name))) 782 843 self.cache.dump(cls) 783 self.nextstore.add_property(cls, name) 784 785 def drop_property(self, cls, name): 844 self.nextstore.add_property(cls, name, conflicts=conflicts) 845 846 def drop_property(self, cls, name, conflicts='error'): 847 """Destroy internal structures for the given property. 848 849 conflicts: see errors.conflict. 850 """ 786 851 if self.logflags & logflags.DDL: 787 852 self.log(logflags.DDL.message("drop property %r %r" % (cls, name))) 788 853 self.cache.dump(cls) 789 self.nextstore.drop_property(cls, name) 790 791 def rename_property(self, cls, oldname, newname): 854 self.nextstore.drop_property(cls, name, conflicts=conflicts) 855 856 def rename_property(self, cls, oldname, newname, conflicts='error'): 857 """Rename internal structures for the given property. 858 859 conflicts: see errors.conflict. 860 """ 792 861 if self.logflags & logflags.DDL: 793 862 self.log(logflags.DDL.message("rename property %r from %r to %r" 794 863 % (cls, oldname, newname))) 795 864 self.cache.dump(cls) 796 self.nextstore.rename_property(cls, oldname, newname) 797 798 def create_database(self): 799 ProxyStorage.create_database(self) 800 self.cache.create_database() 801 802 def drop_database(self): 803 ProxyStorage.drop_database(self) 804 self.cache.drop_database() 805 806 def create_storage(self, cls): 807 ProxyStorage.create_storage(self, cls) 808 self.cache.create_storage(cls) 809 810 def drop_storage(self, cls): 811 ProxyStorage.drop_storage(self, cls) 812 self.cache.drop_storage(cls) 813 814 def map(self, classes, conflict_mode='error'): 865 self.nextstore.rename_property(cls, oldname, newname, conflicts=conflicts) 866 867 def create_database(self, conflicts='error'): 868 """Create internal structures for the entire database. 869 870 conflicts: see errors.conflict. 871 """ 872 ProxyStorage.create_database(self, conflicts=conflicts) 873 self.cache.create_database(conflicts=conflicts) 874 875 def drop_database(self, conflicts='error'): 876 """Destroy internal structures for the entire database. 877 878 conflicts: see errors.conflict. 879 """ 880 ProxyStorage.drop_database(self, conflicts=conflicts) 881 self.cache.drop_database(conflicts=conflicts) 882 883 def create_storage(self, cls, conflicts='error'): 884 """Create internal structures for the given class. 885 886 conflicts: see errors.conflict. 887 """ 888 ProxyStorage.create_storage(self, cls, conflicts=conflicts) 889 self.cache.create_storage(cls, conflicts=conflicts) 890 891 def drop_storage(self, cls, conflicts='error'): 892 """Destroy internal structures for the given class. 893 894 conflicts: see errors.conflict. 895 """ 896 ProxyStorage.drop_storage(self, cls, conflicts=conflicts) 897 self.cache.drop_storage(cls, conflicts=conflicts) 898 899 def map(self, classes, conflicts='error'): 815 900 """Map classes to internal storage. 816 901 817 conflict_mode: This argument determines what happens when there are 818 discrepancies between the Dejavu model and the actual storage. 819 820 If 'error' (the default), MappingError is raised for the 821 first issue and the mapping process is aborted. 822 823 If 'warn', then a warning is raised (instead of an error) 824 for each issue, and the mapping process is not aborted. 825 This allows you to see all errors at once, without having 826 to stop and fix each one and then execute the process again. 827 828 If 'repair', then each issue will be resolved by changing 829 storage to match the model. 830 """ 831 ProxyStorage.map(self, classes, conflict_mode) 902 conflicts: see errors.conflict. 903 """ 904 ProxyStorage.map(self, classes, conflicts=conflicts) 832 905 for cls in classes: 833 906 if not self.cache.has_storage(cls): 834 self.cache.create_storage(cls )907 self.cache.create_storage(cls, conflicts=conflicts) 835 908 836 909 trunk/dejavu/storage/db.py
r504 r505 38 38 import dejavu 39 39 from dejavu import storage, logflags, xray 40 from dejavu.errors import StorageWarning, MappingError 40 from dejavu.errors import StorageWarning, MappingError, conflict 41 41 42 42 … … 80 80 return self.db.version() 81 81 82 def shutdown(self): 82 def shutdown(self, conflicts='error'): 83 """Shut down all connections to internal storage. 84 85 conflicts: see errors.conflict. 86 """ 83 87 self.db.connections.shutdown() 84 88 … … 359 363 # Schemas # 360 364 361 def create_database(self): 365 def create_database(self, conflicts='error'): 366 """Create internal structures for the entire database. 367 368 conflicts: see errors.conflict. 369 """ 362 370 if self.logflags & logflags.DDL: 363 371 self.log(logflags.DDL.message("create database")) 364 self.db.create() 365 self.schema.create() 366 367 def drop_database(self): 372 373 try: 374 self.db.create() 375 self.schema.create() 376 except geniusql.errors.MappingError, x: 377 conflict(conflicts, str(x)) 378 379 def drop_database(self, conflicts='error'): 380 """Destroy internal structures for the entire database. 381 382 conflicts: see errors.conflict. 383 """ 368 384 if self.logflags & logflags.DDL: 369 385 self.log(logflags.DDL.message("drop database")) 370 self.schema.drop() 371 self.db.drop() 386 387 try: 388 self.schema.drop() 389 except geniusql.errors.MappingError, x: 390 conflict(conflicts, str(x)) 391 392 try: 393 self.db.drop() 394 except geniusql.errors.MappingError, x: 395 conflict(conflicts, str(x)) 372 396 373 397 def _make_table(self, cls): … … 388 412 return t 389 413 390 def create_storage(self, cls): 391 """Create storage for the given class.""" 414 def create_storage(self, cls, conflicts='error'): 415 """Create internal structures for the given class. 416 417 conflicts: see errors.conflict. 418 """ 392 419 if self.logflags & logflags.DDL: 393 420 self.log(logflags.DDL.message("create storage %s" % cls)) 394 # Attach to self.schema, which should call CREATE TABLE. 395 self.schema[cls.__name__] = self._make_table(cls) 421 422 try: 423 # Attach to self.schema, which should call CREATE TABLE. 424 self.schema[cls.__name__] = self._make_table(cls) 425 except geniusql.errors.MappingError, x: 426 conflict(conflicts, str(x)) 396 427 397 428 def _make_column(self, cls, key): … … 406 437 407 438 def has_storage(self, cls): 439 """If storage structures exist for the given class, return True.""" 408 440 return cls.__name__ in self.schema 409 441 410 def drop_storage(self, cls): 442 def drop_storage(self, cls, conflicts='error'): 443 """Destroy internal structures for the given class. 444 445 conflicts: see errors.conflict. 446 """ 411 447 if self.logflags & logflags.DDL: 412 448 self.log(logflags.DDL.message("drop storage %s" % cls)) 413 del self.schema[cls.__name__] 414 415 def rename_storage(self, oldname, newname): 449 450 try: 451 del self.schema[cls.__name__] 452 except geniusql.errors.MappingError, x: 453 conflict(conflicts, str(x)) 454 455 def rename_storage(self, oldname, newname, conflicts='error'): 456 """Rename internal structures for the given class. 457 458 conflicts: see errors.conflict. 459 """ 416 460 if self.logflags & logflags.DDL: 417 461 self.log(logflags.DDL.message("rename storage from %s to %s" 418 462 % (oldname, newname))) 419 self.schema.rename(oldname, newname) 420 421 def add_property(self, cls, name): 463 464 try: 465 self.schema.rename(oldname, newname) 466 except geniusql.errors.MappingError, x: 467 conflict(conflicts, str(x)) 468 469 def add_property(self, cls, name, conflicts='error'): 470 """Add internal structures for the given property. 471 472 conflicts: see errors.conflict. 473 """ 422 474 if self.logflags & logflags.DDL: 423 475 self.log(logflags.DDL.message("add property %s %s" % 424 476 (cls, name))) 477 425 478 if not self.has_property(cls, name): 426 table = self.schema[cls.__name__] 427 table[name] = self._make_column(cls, name) 479 try: 480 table = self.schema[cls.__name__] 481 table[name] = self._make_column(cls, name) 482 except geniusql.errors.MappingError, x: 483 conflict(conflicts, str(x)) 428 484 429 485 def has_property(self, cls, name): 486 """If storage structures exist for the given property, return True.""" 430 487 return name in self.schema[cls.__name__] 431 488 432 def drop_property(self, cls, name): 489 def drop_property(self, cls, name, conflicts='error'): 490 """Destroy internal structures for the given property. 491 492 conflicts: see errors.conflict. 493 """ 433 494 if self.logflags & logflags.DDL: 434 495 self.log(logflags.DDL.message("drop property %s %s" % 435 496 (cls, name))) 436 497 if self.has_property(cls, name): 437 del self.schema[cls.__name__][name] 438 439 def rename_property(self, cls, oldname, newname): 498 try: 499 del self.schema[cls.__name__][name] 500 except geniusql.errors.MappingError, x: 501 conflict(conflicts, str(x)) 502 503 def rename_property(self, cls, oldname, newname, conflicts='error'): 504 """Rename internal structures for the given property. 505 506 conflicts: see errors.conflict. 507 """ 440 508 if self.logflags & logflags.DDL: 441 509 self.log(logflags.DDL.message( 442 510 "rename property %s from %s to %s" % 443 511 (cls, oldname, newname))) 444 t = self.schema[cls.__name__] 445 446 # Sometimes, a Dejavu Schema will change a code model first, and 447 # then change the database afterward. So it's possible that the 448 # column we're trying to rename hasn't been loaded, because the 449 # model layer no longer references it. So if table[oldname] 450 # raises a KeyError, try to find a column that matches oldkey. 451 tempcol = None 452 try: 453 t[oldname] 454 except KeyError: 455 c = [x for x in self.schema._get_columns(t.name) 456 if x.name == self.schema._column_name(t.name, oldname)] 457 if not c: 458 raise KeyError("Rename failed. Old column %r not found in %r." 459 % (oldname, t.name)) 460 oldcol = c[0] 461 # Use the superclass call to avoid DROP COLUMN/ADD COLUMN. 462 dict.__setitem__(t, oldname, oldcol) 463 464 t.rename(oldname, newname) 465 466 def add_index(self, cls, name): 467 self.schema[cls.__name__].add_index(name) 512 513 try: 514 t = self.schema[cls.__name__] 515 516 # Sometimes, a Dejavu Schema will change a code model first, and 517 # then change the database afterward. So it's possible that the 518 # column we're trying to rename hasn't been loaded, because the 519 # model layer no longer references it. So if table[oldname] 520 # raises a KeyError, try to find a column that matches oldkey. 521 tempcol = None 522 try: 523 t[oldname] 524 except KeyError: 525 c = [x for x in self.schema._get_columns(t.name) 526 if x.name == self.schema._column_name(t.name, oldname)] 527 if not c: 528 raise KeyError("Rename failed. Old column %r not found in %r." 529 % (oldname, t.name)) 530 oldcol = c[0] 531 # Use the superclass call to avoid DROP COLUMN/ADD COLUMN. 532 dict.__setitem__(t, oldname, oldcol) 533 534 t.rename(oldname, newname) 535 except geniusql.errors.MappingError, x: 536 conflict(conflicts, str(x)) 537 538 def add_index(self, cls, name, conflicts='error'): 539 """Add an index for the given property. 540 541 conflicts: see errors.conflict. 542 """ 543 try: 544 self.schema[cls.__name__].add_index(name) 545 except geniusql.errors.MappingError, x: 546 conflict(conflicts, str(x)) 468 547 469 548 def has_index(self, cls, name): 549 """If an index exists for the given property, return True.""" 470 550 return name in self.schema[cls.__name__].indices 471 551 472 def drop_index(self, cls, name): 473 del self.schema[cls.__name__].indices[name] 552 def drop_index(self, cls, name, conflicts='error'): 553 """Destroy any index on the given property. 554 555 conflicts: see errors.conflict. 556 """ 557 try: 558 del self.schema[cls.__name__].indices[name] 559 except geniusql.errors.MappingError, x: 560 conflict(conflicts, str(x)) 474 561 475 562 auto_discover = True 476 563 477 def map(self, classes, conflict _mode='error'):564 def map(self, classes, conflicts='error'): 478 565 """Map classes to internal storage. 479 566 … … 487 574 and changes to the database are not expected outside the model. 488 575 489 conflict_mode: This argument determines what happens when there are 490 discrepancies between the Dejavu model and the actual database. 491 492 If 'error' (the default), MappingError is raised for the 493 first issue and the sync process is aborted. 494 495 If 'warn', then a StorageWarning is raised (instead of an 496 error) for each issue, and the sync process is not aborted. 497 This allows you to see all errors at once, without having to 498 stop and fix each one and then execute the process again. 499 500 If 'repair', then each issue will be resolved by changing 501 the database to match the model. 576 conflicts: see errors.conflict. 502 577 """ 503 578 if self.auto_discover: 504 579 self.db.discover_dbinfo() 505 self.sync(classes, conflict _mode)580 self.sync(classes, conflicts) 506 581 else: 507 582 for cls in classes: … … 517 592 dict.__setitem__(self.schema, cls.__name__, t) 518 593 519 def sync(self, classes, conflict _mode='error'):594 def sync(self, classes, conflicts='error'): 520 595 """Map classes to existing Table objects (found via discovery). 521 596 522 conflict_mode: This argument determines what happens when there are 523 discrepancies between the Dejavu model and the actual database. 524 525 If 'error' (the default), MappingError is raised for the 526 first issue and the sync process is aborted. 527 528 If 'warn', then a Storagewarning is raised (instead of an 529 error) for each issue, and the sync process is not aborted. 530 This allows you to see all errors at once, without having to 531 stop and fix each one and then execute the process again. 532 533 If 'repair', then each issue will be resolved by changing 534 the database to match the model. 535 536 If 'ignore', then each issue will be silently ignored. 597 conflicts: see errors.conflict. 537 598 """ 538 599 for cls in classes: … … 542 603 # without calling the expensive discover() func each time. 543 604 continue 544 self._find_table(self.schema, cls, conflict _mode)545 546 def _find_table(self, schema, cls, conflict _mode='error'):605 self._find_table(self.schema, cls, conflicts=conflicts) 606 607 def _find_table(self, schema, cls, conflicts='error'): 547 608 # This is broken out to make multi-schema subclasses easier to write. 548 549 def notify(msg):550 if conflict_mode == 'warn':551 warnings.warn(msg, StorageWarning)552 elif conflict_mode == 'ignore':553 pass554 else:555 raise MappingError(msg)556 609 557 610 # Try to find a matching Table object using the DB-side key. … … 569 622 except geniusql.errors.MappingError: 570 623 msg = "%s: no such table %r." % (clsname, tablename) 571 if conflict _mode== 'repair':624 if conflicts == 'repair': 572 625 self.create_storage(cls) 573 626 table = schema[clsname] 574 627 else: 575 notify(msg)628 conflict(conflicts, msg) 576 629 return 577 630 … … 586 639 except KeyError, x: 587 640 msg = "%s: no column found for %r." % (clsname, pkey) 588 if conflict _mode== 'repair':641 if conflicts == 'repair': 589 642 self.add_property(cls, pkey) 590 643 if pkey in cls.indices() and pkey not in table.indices: … … 592 645 col = table[pkey] 593 646 else: 594 notify(msg)647 conflict(conflicts, msg) 595 648 continue 596 649 … … 603 656 "column is not marked as a primary key." 604 657 % (clsname, pkey)) 605 if conflict _mode== 'repair':658 if conflicts == 'repair': 606 659 col.key = True 607 660 table.set_primary() 608 661 else: 609 notify(msg)662 conflict(conflicts, msg) 610 663 continue 611 664 elif col.key and not pkey in cls.identifiers: … … 613 666 "column is marked as a primary key." 614 667 % (clsname, pkey)) 615 if conflict _mode== 'repair':668 if conflicts == 'repair': 616 669 col.key = False 617 670 # Just because the current pkey is not an identifier … … 619 672 table.set_primary() 620 673 else: 621 notify(msg)674 c
