root / elixir / trunk / elixir / options.py @ 421

Revision 421, 13.3 kB (checked in by ged, 6 years ago)

- moved all relationship options to explicit kwargs, instead of doing

"kwargs.pops()" all over the place.

- changed empty dicts and lists to {} and []. I really tried to get used to the

other notation but it seems like it didn't work out.

Line 
1'''
2This module provides support for defining several options on your Elixir
3entities.  There are three different kinds of options that can be set
4up, and for this there are three different statements: using_options_,
5using_table_options_ and using_mapper_options_.
6
7Alternatively, these options can be set on all Elixir entities by modifying
8the `options_defaults` dictionary before defining any entity.
9
10`using_options`
11---------------
12The 'using_options' DSL statement allows you to set up some additional
13behaviors on your model objects, including table names, ordering, and
14more.  To specify an option, simply supply the option as a keyword
15argument onto the statement, as follows:
16
17.. sourcecode:: python
18
19    class Person(Entity):
20        name = Field(Unicode(64))
21
22        using_options(shortnames=True, order_by='name')
23The list of supported arguments are as follows:
24
25+---------------------+-------------------------------------------------------+
26| Option Name         | Description                                           |
27+=====================+=======================================================+
28| ``inheritance``     | Specify the type of inheritance this entity must use. |
29|                     | It can be one of ``single``, ``concrete`` or          |
30|                     | ``multi``. Defaults to ``single``.                    |
31|                     | Note that polymorphic concrete inheritance is         |
32|                     | currently not implemented. See:                       |
33|                     | http://www.sqlalchemy.org/docs/04/mappers.html        |
34|                     | #advdatamapping_mapper_inheritance for an explanation |
35|                     | of the different kinds of inheritances.               |
36+---------------------+-------------------------------------------------------+
37| ``polymorphic``     | Whether the inheritance should be polymorphic or not. |
38|                     | Defaults to ``True``. The column used to store the    |
39|                     | type of each row is named "row_type" by default. You  |
40|                     | can change this by passing the desired name for the   |
41|                     | column to this argument.                              |
42+---------------------+-------------------------------------------------------+
43| ``identity``        | Specify a custom polymorphic identity. When using     |
44|                     | polymorphic inheritance, this value (usually a        |
45|                     | string) will represent this particular entity (class) |
46|                     | . It will be used to differentiate it from other      |
47|                     | entities (classes) in your inheritance hierarchy when |
48|                     | loading from the database instances of different      |
49|                     | entities in that hierarchy at the same time.          |
50|                     | This value will be stored by default in the           |
51|                     | "row_type" column of the entity's table (see above).  |
52|                     | You can either provide a                              |
53|                     | plain string or a callable. The callable will be      |
54|                     | given the entity (ie class) as argument and must      |
55|                     | return a value (usually a string) representing the    |
56|                     | polymorphic identity of that entity.                  |
57|                     | By default, this value is automatically generated: it |
58|                     | is the name of the entity lower-cased.                |
59+---------------------+-------------------------------------------------------+
60| ``metadata``        | Specify a custom MetaData for this entity.            |
61|                     | By default, entities uses the global                  |
62|                     | ``elixir.metadata``.                                  |
63|                     | This option can also be set for all entities of a     |
64|                     | module by setting the ``__metadata__`` attribute of   |
65|                     | that module.                                          |
66+---------------------+-------------------------------------------------------+
67| ``autoload``        | Automatically load column definitions from the        |
68|                     | existing database table.                              |
69+---------------------+-------------------------------------------------------+
70| ``tablename``       | Specify a custom tablename. You can either provide a  |
71|                     | plain string or a callable. The callable will be      |
72|                     | given the entity (ie class) as argument and must      |
73|                     | return a string representing the name of the table    |
74|                     | for that entity. By default, the tablename is         |
75|                     | automatically generated: it is a concatenation of the |
76|                     | full module-path to the entity and the entity (class) |
77|                     | name itself. The result is lower-cased and separated  |
78|                     | by underscores ("_"), eg.: for an entity named        |
79|                     | "MyEntity" in the module "project1.model", the        |
80|                     | generated table name will be                          |
81|                     | "project1_model_myentity".                            |
82+---------------------+-------------------------------------------------------+
83| ``shortnames``      | Specify whether or not the automatically generated    |
84|                     | table names include the full module-path              |
85|                     | to the entity. Defaults to ``True``.                  |
86+---------------------+-------------------------------------------------------+
87| ``auto_primarykey`` | If given as string, it will represent the             |
88|                     | auto-primary-key's column name.  If this option       |
89|                     | is True, it will allow auto-creation of a primary     |
90|                     | key if there's no primary key defined for the         |
91|                     | corresponding entity.  If this option is False,       |
92|                     | it will disallow auto-creation of a primary key.      |
93|                     | Defaults to ``True``.                                 |
94+---------------------+-------------------------------------------------------+
95| ``version_id_col``  | If this option is True, it will create a version      |
96|                     | column automatically using the default name. If given |
97|                     | as string, it will create the column using that name. |
98|                     | This can be used to prevent concurrent modifications  |
99|                     | to the entity's table rows (i.e. it will raise an     |
100|                     | exception if it happens). Defaults to ``False``.      |
101+---------------------+-------------------------------------------------------+
102| ``order_by``        | How to order select results. Either a string or a     |
103|                     | list of strings, composed of the field name,          |
104|                     | optionally lead by a minus (for descending order).    |
105+---------------------+-------------------------------------------------------+
106| ``session``         | Specify a custom contextual session for this entity.  |
107|                     | By default, entities uses the global                  |
108|                     | ``elixir.session``.                                   |
109|                     | This option takes a ``ScopedSession`` object or       |
110|                     | ``None``. In the later case your entity will be       |
111|                     | mapped using a non-contextual mapper which requires   |
112|                     | manual session management, as seen in pure SQLAlchemy.|
113|                     | This option can also be set for all entities of a     |
114|                     | module by setting the ``__session__`` attribute of    |
115|                     | that module.                                          |
116+---------------------+-------------------------------------------------------+
117| ``autosetup``       | Specify whether that entity will contain automatic    |
118|                     | setup triggers. That is if this entity will be        |
119|                     | automatically setup (along with all other entities    |
120|                     | which were already declared) if any of the following  |
121|                     | condition happen: some of its attributes are accessed |
122|                     | ('c', 'table', 'mapper' or 'query'), instanciated     |
123|                     | (called) or the create_all method of this entity's    |
124|                     | metadata is called. Defaults to ``False``.            |
125+---------------------+-------------------------------------------------------+
126| ``allowcoloverride``| Specify whether it is allowed to override columns.    |
127|                     | By default, Elixir forbids you to add a column to an  |
128|                     | entity's table which already exist in that table. If  |
129|                     | you set this option to ``True`` it will skip that     |
130|                     | check. Use with care as it is easy to shoot oneself   |
131|                     | in the foot when overriding columns.                  |
132+---------------------+-------------------------------------------------------+
133
134For examples, please refer to the examples and unit tests.
135
136`using_table_options`
137---------------------
138The 'using_table_options' DSL statement allows you to set up some
139additional options on your entity table. It is meant only to handle the
140options which are not supported directly by the 'using_options' statement.
141By opposition to the 'using_options' statement, these options are passed
142directly to the underlying SQLAlchemy Table object (both non-keyword arguments
143and keyword arguments) without any processing.
144
145For further information, please refer to the `SQLAlchemy table's documentation
146<http://www.sqlalchemy.org/docs/04/sqlalchemy_schema.html
147#docstrings_sqlalchemy.schema_Table>`_.
148
149You might also be interested in the section about `constraints
150<http://www.sqlalchemy.org/docs/04/metadata.html#metadata_constraints>`_.
151
152`using_mapper_options`
153----------------------
154The 'using_mapper_options' DSL statement allows you to set up some
155additional options on your entity mapper. It is meant only to handle the
156options which are not supported directly by the 'using_options' statement.
157By opposition to the 'using_options' statement, these options are passed
158directly to the underlying SQLAlchemy mapper (as keyword arguments)
159without any processing.
160
161For further information, please refer to the `SQLAlchemy mapper
162function's documentation
163<http://www.sqlalchemy.org/docs/04/sqlalchemy_orm.html
164#docstrings_sqlalchemy.orm_modfunc_mapper>`_.
165
166`using_options_defaults`
167------------------------
168The 'using_options_defaults' DSL statement allows you to set up some
169default options on a custom base class. These will be used as the default value
170for options of all its subclasses. Note that any option not set within the
171using_options_defaults (nor specifically on a particular Entity) will use the
172global defaults, so you don't have to provide a default value for all options,
173but only those you want to change.
174
175'''
176
177from sqlalchemy import Integer, String
178
179from elixir.statements import ClassMutator
180
181__doc_all__ = ['options_defaults']
182
183# format constants
184FKCOL_NAMEFORMAT = "%(relname)s_%(key)s"
185M2MCOL_NAMEFORMAT = "%(tablename)s_%(key)s"
186CONSTRAINT_NAMEFORMAT = "%(tablename)s_%(colnames)s_fk"
187MULTIINHERITANCECOL_NAMEFORMAT = "%(entity)s_%(key)s"
188
189# other global constants
190DEFAULT_AUTO_PRIMARYKEY_NAME = "id"
191DEFAULT_AUTO_PRIMARYKEY_TYPE = Integer
192DEFAULT_VERSION_ID_COL_NAME = "row_version"
193DEFAULT_POLYMORPHIC_COL_NAME = "row_type"
194POLYMORPHIC_COL_SIZE = 40
195POLYMORPHIC_COL_TYPE = String(POLYMORPHIC_COL_SIZE)
196
197# debugging/migration help
198CHECK_TABLENAME_CHANGES = False
199
200#
201options_defaults = dict(
202    autosetup=False,
203    inheritance='single',
204    polymorphic=True,
205    identity=None,
206    autoload=False,
207    tablename=None,
208    shortnames=False,
209    auto_primarykey=True,
210    version_id_col=False,
211    allowcoloverride=False,
212    order_by=None,
213    mapper_options={},
214    table_options={}
215)
216
217valid_options = options_defaults.keys() + [
218    'metadata',
219    'session',
220    'collection'
221]
222
223
224def using_options_defaults_handler(entity, **kwargs):
225    for kwarg in kwargs:
226        if kwarg not in valid_options:
227            raise Exception("'%s' is not a valid option for Elixir entities."
228                            % kwarg)
229
230    entity.options_defaults = kwargs
231
232
233def using_options_handler(entity, *args, **kwargs):
234    for kwarg in kwargs:
235        if kwarg in valid_options:
236            setattr(entity._descriptor, kwarg, kwargs[kwarg])
237        else:
238            raise Exception("'%s' is not a valid option for Elixir entities."
239                            % kwarg)
240
241
242def using_table_options_handler(entity, *args, **kwargs):
243    entity._descriptor.table_args = list(args)
244    entity._descriptor.table_options.update(kwargs)
245
246
247def using_mapper_options_handler(entity, *args, **kwargs):
248    entity._descriptor.mapper_options.update(kwargs)
249
250
251using_options_defaults = ClassMutator(using_options_defaults_handler)
252using_options = ClassMutator(using_options_handler)
253using_table_options = ClassMutator(using_table_options_handler)
254using_mapper_options = ClassMutator(using_mapper_options_handler)
Note: See TracBrowser for help on using the browser.