Changeset 83
- Timestamp:
- 03/05/07 21:32:53 (6 years ago)
- Location:
- elixir/trunk
- Files:
-
- 4 modified
-
CHANGES (modified) (2 diffs)
-
elixir/entity.py (modified) (4 diffs)
-
elixir/options.py (modified) (5 diffs)
-
tests/test_options.py (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
elixir/trunk/CHANGES
r82 r83 1 0. 2.11 0.3.0 2 2 - Added support for autoloading/reflecting databases with 3 3 has_and_belongs_to_many relationships. The tablename argument is now 4 4 optional, but still recommended, otherwise you'll have to use the same exact 5 5 name for your intermediary table than the one generated. 6 - Added support for the "version_id_col" option on entities. This option adds 7 a column to the table which will be used to prevent concurrent modifications 8 on any row of the entity's table (i.e. it will raise an error if it happens). 6 9 - Made the colname argument optional for belongs_to relationships in 7 10 autoloaded entities. It is only required to specify it if you have several … … 19 22 - Actually make the code python 2.3 compatible (Robin's patch was based on 20 23 0.1.0 while I had introduced more decorators in the trunk in the mean time). 24 - Using invalid options on entities will now raise an exception 21 25 - Some cleanup/useless code removal 22 26 -
elixir/trunk/elixir/entity.py
r82 r83 25 25 DEFAULT_AUTO_PRIMARYKEY_NAME = "id" 26 26 DEFAULT_AUTO_PRIMARYKEY_TYPE = Integer 27 27 DEFAULT_VERSION_ID_COL = "row_version" 28 28 29 29 class EntityDescriptor(object): … … 70 70 71 71 for option in ('inheritance', 72 'autoload', 'shortnames', 'auto_primarykey'): 72 'autoload', 'shortnames', 'auto_primarykey', 73 'version_id_col'): 73 74 setattr(self, option, options_defaults[option]) 74 75 … … 141 142 kwargs['order_by'] = self.translate_order_by(self.order_by) 142 143 144 if self.version_id_col: 145 kwargs['version_id_col'] = self.fields[self.version_id_col].column 146 143 147 if self.parent: 144 148 if self.inheritance == 'single': … … 192 196 # for field in self.fields.itervalues(): 193 197 # self.add_field(field) 198 199 if self.version_id_col: 200 if not isinstance(self.version_id_col, basestring): 201 self.version_id_col = DEFAULT_VERSION_ID_COL 202 self.add_field(Field(Integer, colname=self.version_id_col)) 194 203 195 204 if not self.autoload: -
elixir/trunk/elixir/options.py
r82 r83 40 40 +---------------------+-------------------------------------------------------+ 41 41 | ``autoload`` | Automatically load column definitions from the | 42 | | existing database table. For now, it does **not** | 43 | | work for ``has_and_belongs_to_many`` relationships. | 42 | | existing database table. | 44 43 | | Using autoloaded tables implies setting | 45 44 | | ``delay_setup`` to ``True`` before defining your | … … 62 61 | | corresponding entity. If this option is False, | 63 62 | | it will disallow auto-creation of a primary key. | 63 +---------------------+-------------------------------------------------------+ 64 | ``version_id_col`` | If this option is True, it will create a version | 65 | | column automatically using the default name. If given | 66 | | as string, it will create the column using that name. | 67 | | This can be used to prevent concurrent modifications | 68 | | to the entity's table rows (i.e. it will raise an | 69 | | exception if it happens). | 64 70 +---------------------+-------------------------------------------------------+ 65 71 | ``order_by`` | How to order select results. Either a string or a | … … 112 118 shortnames=False, 113 119 auto_primarykey=True, 120 version_id_col=False, 114 121 mapper_options=dict(), 115 122 table_options=dict(), … … 124 131 'shortnames', 125 132 'auto_primarykey', 133 'version_id_col', 126 134 'order_by', 127 135 ) … … 133 141 if kwarg in UsingOptions.valid_options: 134 142 setattr(desc, kwarg, kwargs[kwarg]) 143 else: 144 raise Exception("'%s' is not a valid option for Elixir " 145 "entities." % kwarg) 135 146 136 147 -
elixir/trunk/tests/test_options.py
r71 r83 3 3 """ 4 4 5 from sqlalchemy import create_engine, UniqueConstraint6 from sqlalchemy.exceptions import SQLError 5 from sqlalchemy import create_engine, create_session, UniqueConstraint 6 from sqlalchemy.exceptions import SQLError, ConcurrentModificationError 7 7 from elixir import * 8 8 9 #TODO: complete this test.10 11 # The order_by option is already tested in test_order_by.py12 13 class Record(Entity):14 with_fields(15 title = Field(Unicode(30)),16 artist = Field(Unicode(30)),17 year = Field(Integer)18 )19 20 using_options(tablename="records")21 9 22 10 class TestOptions(object): … … 24 12 engine = create_engine('sqlite:///') 25 13 metadata.connect(engine) 26 create_all() 27 14 15 # this test is a rip-off SQLAlchemy's activemapper's update test 16 def test_version_id_col(self): 17 class Person(Entity): 18 has_field('name', Unicode(30)) 19 20 using_options(version_id_col=True) 21 22 Person.table.create() 23 24 p1 = Person(name='Daniel') 25 objectstore.flush() 26 objectstore.clear() 27 28 person = Person.select()[0] 29 person.name = 'Gaetan' 30 objectstore.flush() 31 objectstore.clear() 32 assert person.row_version == 2 33 34 person = Person.select()[0] 35 person.name = 'Jonathan' 36 objectstore.flush() 37 objectstore.clear() 38 assert person.row_version == 3 39 40 # check that a concurrent modification raises exception 41 p1 = Person.select()[0] 42 s1 = objectstore.session 43 s2 = create_session() 44 objectstore.context.current = s2 45 p2 = Person.select()[0] 46 p1.name = "Daniel" 47 p2.name = "Gaetan" 48 objectstore.flush() 49 try: 50 objectstore.context.current = s1 51 objectstore.flush() 52 assert False 53 except ConcurrentModificationError: 54 pass 55 28 56 def teardown(self): 29 57 cleanup_all() 30 58 59 31 60 class TestTableOptions(object): 32 61 def setup(self):
