Mercurial > kallithea
comparison rhodecode/lib/dbmigrate/migrate/changeset/schema.py @ 833:9753e0907827 beta
added dbmigrate package, added model changes
moved out upgrade db command to that package
author | Marcin Kuzminski <marcin@python-works.com> |
---|---|
date | Sat, 11 Dec 2010 01:54:12 +0100 |
parents | |
children | 08d2dcd71666 |
comparison
equal
deleted
inserted
replaced
832:634596f81cfd | 833:9753e0907827 |
---|---|
1 """ | |
2 Schema module providing common schema operations. | |
3 """ | |
4 import warnings | |
5 | |
6 from UserDict import DictMixin | |
7 | |
8 import sqlalchemy | |
9 | |
10 from sqlalchemy.schema import ForeignKeyConstraint | |
11 from sqlalchemy.schema import UniqueConstraint | |
12 | |
13 from migrate.exceptions import * | |
14 from migrate.changeset import SQLA_06 | |
15 from migrate.changeset.databases.visitor import (get_engine_visitor, | |
16 run_single_visitor) | |
17 | |
18 | |
19 __all__ = [ | |
20 'create_column', | |
21 'drop_column', | |
22 'alter_column', | |
23 'rename_table', | |
24 'rename_index', | |
25 'ChangesetTable', | |
26 'ChangesetColumn', | |
27 'ChangesetIndex', | |
28 'ChangesetDefaultClause', | |
29 'ColumnDelta', | |
30 ] | |
31 | |
32 DEFAULT_ALTER_METADATA = True | |
33 | |
34 | |
35 def create_column(column, table=None, *p, **kw): | |
36 """Create a column, given the table. | |
37 | |
38 API to :meth:`ChangesetColumn.create`. | |
39 """ | |
40 if table is not None: | |
41 return table.create_column(column, *p, **kw) | |
42 return column.create(*p, **kw) | |
43 | |
44 | |
45 def drop_column(column, table=None, *p, **kw): | |
46 """Drop a column, given the table. | |
47 | |
48 API to :meth:`ChangesetColumn.drop`. | |
49 """ | |
50 if table is not None: | |
51 return table.drop_column(column, *p, **kw) | |
52 return column.drop(*p, **kw) | |
53 | |
54 | |
55 def rename_table(table, name, engine=None, **kw): | |
56 """Rename a table. | |
57 | |
58 If Table instance is given, engine is not used. | |
59 | |
60 API to :meth:`ChangesetTable.rename`. | |
61 | |
62 :param table: Table to be renamed. | |
63 :param name: New name for Table. | |
64 :param engine: Engine instance. | |
65 :type table: string or Table instance | |
66 :type name: string | |
67 :type engine: obj | |
68 """ | |
69 table = _to_table(table, engine) | |
70 table.rename(name, **kw) | |
71 | |
72 | |
73 def rename_index(index, name, table=None, engine=None, **kw): | |
74 """Rename an index. | |
75 | |
76 If Index instance is given, | |
77 table and engine are not used. | |
78 | |
79 API to :meth:`ChangesetIndex.rename`. | |
80 | |
81 :param index: Index to be renamed. | |
82 :param name: New name for index. | |
83 :param table: Table to which Index is reffered. | |
84 :param engine: Engine instance. | |
85 :type index: string or Index instance | |
86 :type name: string | |
87 :type table: string or Table instance | |
88 :type engine: obj | |
89 """ | |
90 index = _to_index(index, table, engine) | |
91 index.rename(name, **kw) | |
92 | |
93 | |
94 def alter_column(*p, **k): | |
95 """Alter a column. | |
96 | |
97 This is a helper function that creates a :class:`ColumnDelta` and | |
98 runs it. | |
99 | |
100 :argument column: | |
101 The name of the column to be altered or a | |
102 :class:`ChangesetColumn` column representing it. | |
103 | |
104 :param table: | |
105 A :class:`~sqlalchemy.schema.Table` or table name to | |
106 for the table where the column will be changed. | |
107 | |
108 :param engine: | |
109 The :class:`~sqlalchemy.engine.base.Engine` to use for table | |
110 reflection and schema alterations. | |
111 | |
112 :param alter_metadata: | |
113 If `True`, which is the default, the | |
114 :class:`~sqlalchemy.schema.Column` will also modified. | |
115 If `False`, the :class:`~sqlalchemy.schema.Column` will be left | |
116 as it was. | |
117 | |
118 :returns: A :class:`ColumnDelta` instance representing the change. | |
119 | |
120 | |
121 """ | |
122 | |
123 k.setdefault('alter_metadata', DEFAULT_ALTER_METADATA) | |
124 | |
125 if 'table' not in k and isinstance(p[0], sqlalchemy.Column): | |
126 k['table'] = p[0].table | |
127 if 'engine' not in k: | |
128 k['engine'] = k['table'].bind | |
129 | |
130 # deprecation | |
131 if len(p) >= 2 and isinstance(p[1], sqlalchemy.Column): | |
132 warnings.warn( | |
133 "Passing a Column object to alter_column is deprecated." | |
134 " Just pass in keyword parameters instead.", | |
135 MigrateDeprecationWarning | |
136 ) | |
137 engine = k['engine'] | |
138 delta = ColumnDelta(*p, **k) | |
139 | |
140 visitorcallable = get_engine_visitor(engine, 'schemachanger') | |
141 engine._run_visitor(visitorcallable, delta) | |
142 | |
143 return delta | |
144 | |
145 | |
146 def _to_table(table, engine=None): | |
147 """Return if instance of Table, else construct new with metadata""" | |
148 if isinstance(table, sqlalchemy.Table): | |
149 return table | |
150 | |
151 # Given: table name, maybe an engine | |
152 meta = sqlalchemy.MetaData() | |
153 if engine is not None: | |
154 meta.bind = engine | |
155 return sqlalchemy.Table(table, meta) | |
156 | |
157 | |
158 def _to_index(index, table=None, engine=None): | |
159 """Return if instance of Index, else construct new with metadata""" | |
160 if isinstance(index, sqlalchemy.Index): | |
161 return index | |
162 | |
163 # Given: index name; table name required | |
164 table = _to_table(table, engine) | |
165 ret = sqlalchemy.Index(index) | |
166 ret.table = table | |
167 return ret | |
168 | |
169 | |
170 class ColumnDelta(DictMixin, sqlalchemy.schema.SchemaItem): | |
171 """Extracts the differences between two columns/column-parameters | |
172 | |
173 May receive parameters arranged in several different ways: | |
174 | |
175 * **current_column, new_column, \*p, \*\*kw** | |
176 Additional parameters can be specified to override column | |
177 differences. | |
178 | |
179 * **current_column, \*p, \*\*kw** | |
180 Additional parameters alter current_column. Table name is extracted | |
181 from current_column object. | |
182 Name is changed to current_column.name from current_name, | |
183 if current_name is specified. | |
184 | |
185 * **current_col_name, \*p, \*\*kw** | |
186 Table kw must specified. | |
187 | |
188 :param table: Table at which current Column should be bound to.\ | |
189 If table name is given, reflection will be used. | |
190 :type table: string or Table instance | |
191 :param alter_metadata: If True, it will apply changes to metadata. | |
192 :type alter_metadata: bool | |
193 :param metadata: If `alter_metadata` is true, \ | |
194 metadata is used to reflect table names into | |
195 :type metadata: :class:`MetaData` instance | |
196 :param engine: When reflecting tables, either engine or metadata must \ | |
197 be specified to acquire engine object. | |
198 :type engine: :class:`Engine` instance | |
199 :returns: :class:`ColumnDelta` instance provides interface for altered attributes to \ | |
200 `result_column` through :func:`dict` alike object. | |
201 | |
202 * :class:`ColumnDelta`.result_column is altered column with new attributes | |
203 | |
204 * :class:`ColumnDelta`.current_name is current name of column in db | |
205 | |
206 | |
207 """ | |
208 | |
209 # Column attributes that can be altered | |
210 diff_keys = ('name', 'type', 'primary_key', 'nullable', | |
211 'server_onupdate', 'server_default', 'autoincrement') | |
212 diffs = dict() | |
213 __visit_name__ = 'column' | |
214 | |
215 def __init__(self, *p, **kw): | |
216 self.alter_metadata = kw.pop("alter_metadata", False) | |
217 self.meta = kw.pop("metadata", None) | |
218 self.engine = kw.pop("engine", None) | |
219 | |
220 # Things are initialized differently depending on how many column | |
221 # parameters are given. Figure out how many and call the appropriate | |
222 # method. | |
223 if len(p) >= 1 and isinstance(p[0], sqlalchemy.Column): | |
224 # At least one column specified | |
225 if len(p) >= 2 and isinstance(p[1], sqlalchemy.Column): | |
226 # Two columns specified | |
227 diffs = self.compare_2_columns(*p, **kw) | |
228 else: | |
229 # Exactly one column specified | |
230 diffs = self.compare_1_column(*p, **kw) | |
231 else: | |
232 # Zero columns specified | |
233 if not len(p) or not isinstance(p[0], basestring): | |
234 raise ValueError("First argument must be column name") | |
235 diffs = self.compare_parameters(*p, **kw) | |
236 | |
237 self.apply_diffs(diffs) | |
238 | |
239 def __repr__(self): | |
240 return '<ColumnDelta altermetadata=%r, %s>' % (self.alter_metadata, | |
241 super(ColumnDelta, self).__repr__()) | |
242 | |
243 def __getitem__(self, key): | |
244 if key not in self.keys(): | |
245 raise KeyError("No such diff key, available: %s" % self.diffs) | |
246 return getattr(self.result_column, key) | |
247 | |
248 def __setitem__(self, key, value): | |
249 if key not in self.keys(): | |
250 raise KeyError("No such diff key, available: %s" % self.diffs) | |
251 setattr(self.result_column, key, value) | |
252 | |
253 def __delitem__(self, key): | |
254 raise NotImplementedError | |
255 | |
256 def keys(self): | |
257 return self.diffs.keys() | |
258 | |
259 def compare_parameters(self, current_name, *p, **k): | |
260 """Compares Column objects with reflection""" | |
261 self.table = k.pop('table') | |
262 self.result_column = self._table.c.get(current_name) | |
263 if len(p): | |
264 k = self._extract_parameters(p, k, self.result_column) | |
265 return k | |
266 | |
267 def compare_1_column(self, col, *p, **k): | |
268 """Compares one Column object""" | |
269 self.table = k.pop('table', None) | |
270 if self.table is None: | |
271 self.table = col.table | |
272 self.result_column = col | |
273 if len(p): | |
274 k = self._extract_parameters(p, k, self.result_column) | |
275 return k | |
276 | |
277 def compare_2_columns(self, old_col, new_col, *p, **k): | |
278 """Compares two Column objects""" | |
279 self.process_column(new_col) | |
280 self.table = k.pop('table', None) | |
281 # we cannot use bool() on table in SA06 | |
282 if self.table is None: | |
283 self.table = old_col.table | |
284 if self.table is None: | |
285 new_col.table | |
286 self.result_column = old_col | |
287 | |
288 # set differences | |
289 # leave out some stuff for later comp | |
290 for key in (set(self.diff_keys) - set(('type',))): | |
291 val = getattr(new_col, key, None) | |
292 if getattr(self.result_column, key, None) != val: | |
293 k.setdefault(key, val) | |
294 | |
295 # inspect types | |
296 if not self.are_column_types_eq(self.result_column.type, new_col.type): | |
297 k.setdefault('type', new_col.type) | |
298 | |
299 if len(p): | |
300 k = self._extract_parameters(p, k, self.result_column) | |
301 return k | |
302 | |
303 def apply_diffs(self, diffs): | |
304 """Populate dict and column object with new values""" | |
305 self.diffs = diffs | |
306 for key in self.diff_keys: | |
307 if key in diffs: | |
308 setattr(self.result_column, key, diffs[key]) | |
309 | |
310 self.process_column(self.result_column) | |
311 | |
312 # create an instance of class type if not yet | |
313 if 'type' in diffs and callable(self.result_column.type): | |
314 self.result_column.type = self.result_column.type() | |
315 | |
316 # add column to the table | |
317 if self.table is not None and self.alter_metadata: | |
318 self.result_column.add_to_table(self.table) | |
319 | |
320 def are_column_types_eq(self, old_type, new_type): | |
321 """Compares two types to be equal""" | |
322 ret = old_type.__class__ == new_type.__class__ | |
323 | |
324 # String length is a special case | |
325 if ret and isinstance(new_type, sqlalchemy.types.String): | |
326 ret = (getattr(old_type, 'length', None) == \ | |
327 getattr(new_type, 'length', None)) | |
328 return ret | |
329 | |
330 def _extract_parameters(self, p, k, column): | |
331 """Extracts data from p and modifies diffs""" | |
332 p = list(p) | |
333 while len(p): | |
334 if isinstance(p[0], basestring): | |
335 k.setdefault('name', p.pop(0)) | |
336 elif isinstance(p[0], sqlalchemy.types.AbstractType): | |
337 k.setdefault('type', p.pop(0)) | |
338 elif callable(p[0]): | |
339 p[0] = p[0]() | |
340 else: | |
341 break | |
342 | |
343 if len(p): | |
344 new_col = column.copy_fixed() | |
345 new_col._init_items(*p) | |
346 k = self.compare_2_columns(column, new_col, **k) | |
347 return k | |
348 | |
349 def process_column(self, column): | |
350 """Processes default values for column""" | |
351 # XXX: this is a snippet from SA processing of positional parameters | |
352 if not SQLA_06 and column.args: | |
353 toinit = list(column.args) | |
354 else: | |
355 toinit = list() | |
356 | |
357 if column.server_default is not None: | |
358 if isinstance(column.server_default, sqlalchemy.FetchedValue): | |
359 toinit.append(column.server_default) | |
360 else: | |
361 toinit.append(sqlalchemy.DefaultClause(column.server_default)) | |
362 if column.server_onupdate is not None: | |
363 if isinstance(column.server_onupdate, FetchedValue): | |
364 toinit.append(column.server_default) | |
365 else: | |
366 toinit.append(sqlalchemy.DefaultClause(column.server_onupdate, | |
367 for_update=True)) | |
368 if toinit: | |
369 column._init_items(*toinit) | |
370 | |
371 if not SQLA_06: | |
372 column.args = [] | |
373 | |
374 def _get_table(self): | |
375 return getattr(self, '_table', None) | |
376 | |
377 def _set_table(self, table): | |
378 if isinstance(table, basestring): | |
379 if self.alter_metadata: | |
380 if not self.meta: | |
381 raise ValueError("metadata must be specified for table" | |
382 " reflection when using alter_metadata") | |
383 meta = self.meta | |
384 if self.engine: | |
385 meta.bind = self.engine | |
386 else: | |
387 if not self.engine and not self.meta: | |
388 raise ValueError("engine or metadata must be specified" | |
389 " to reflect tables") | |
390 if not self.engine: | |
391 self.engine = self.meta.bind | |
392 meta = sqlalchemy.MetaData(bind=self.engine) | |
393 self._table = sqlalchemy.Table(table, meta, autoload=True) | |
394 elif isinstance(table, sqlalchemy.Table): | |
395 self._table = table | |
396 if not self.alter_metadata: | |
397 self._table.meta = sqlalchemy.MetaData(bind=self._table.bind) | |
398 | |
399 def _get_result_column(self): | |
400 return getattr(self, '_result_column', None) | |
401 | |
402 def _set_result_column(self, column): | |
403 """Set Column to Table based on alter_metadata evaluation.""" | |
404 self.process_column(column) | |
405 if not hasattr(self, 'current_name'): | |
406 self.current_name = column.name | |
407 if self.alter_metadata: | |
408 self._result_column = column | |
409 else: | |
410 self._result_column = column.copy_fixed() | |
411 | |
412 table = property(_get_table, _set_table) | |
413 result_column = property(_get_result_column, _set_result_column) | |
414 | |
415 | |
416 class ChangesetTable(object): | |
417 """Changeset extensions to SQLAlchemy tables.""" | |
418 | |
419 def create_column(self, column, *p, **kw): | |
420 """Creates a column. | |
421 | |
422 The column parameter may be a column definition or the name of | |
423 a column in this table. | |
424 | |
425 API to :meth:`ChangesetColumn.create` | |
426 | |
427 :param column: Column to be created | |
428 :type column: Column instance or string | |
429 """ | |
430 if not isinstance(column, sqlalchemy.Column): | |
431 # It's a column name | |
432 column = getattr(self.c, str(column)) | |
433 column.create(table=self, *p, **kw) | |
434 | |
435 def drop_column(self, column, *p, **kw): | |
436 """Drop a column, given its name or definition. | |
437 | |
438 API to :meth:`ChangesetColumn.drop` | |
439 | |
440 :param column: Column to be droped | |
441 :type column: Column instance or string | |
442 """ | |
443 if not isinstance(column, sqlalchemy.Column): | |
444 # It's a column name | |
445 try: | |
446 column = getattr(self.c, str(column)) | |
447 except AttributeError: | |
448 # That column isn't part of the table. We don't need | |
449 # its entire definition to drop the column, just its | |
450 # name, so create a dummy column with the same name. | |
451 column = sqlalchemy.Column(str(column), sqlalchemy.Integer()) | |
452 column.drop(table=self, *p, **kw) | |
453 | |
454 def rename(self, name, connection=None, **kwargs): | |
455 """Rename this table. | |
456 | |
457 :param name: New name of the table. | |
458 :type name: string | |
459 :param alter_metadata: If True, table will be removed from metadata | |
460 :type alter_metadata: bool | |
461 :param connection: reuse connection istead of creating new one. | |
462 :type connection: :class:`sqlalchemy.engine.base.Connection` instance | |
463 """ | |
464 self.alter_metadata = kwargs.pop('alter_metadata', DEFAULT_ALTER_METADATA) | |
465 engine = self.bind | |
466 self.new_name = name | |
467 visitorcallable = get_engine_visitor(engine, 'schemachanger') | |
468 run_single_visitor(engine, visitorcallable, self, connection, **kwargs) | |
469 | |
470 # Fix metadata registration | |
471 if self.alter_metadata: | |
472 self.name = name | |
473 self.deregister() | |
474 self._set_parent(self.metadata) | |
475 | |
476 def _meta_key(self): | |
477 return sqlalchemy.schema._get_table_key(self.name, self.schema) | |
478 | |
479 def deregister(self): | |
480 """Remove this table from its metadata""" | |
481 key = self._meta_key() | |
482 meta = self.metadata | |
483 if key in meta.tables: | |
484 del meta.tables[key] | |
485 | |
486 | |
487 class ChangesetColumn(object): | |
488 """Changeset extensions to SQLAlchemy columns.""" | |
489 | |
490 def alter(self, *p, **k): | |
491 """Makes a call to :func:`alter_column` for the column this | |
492 method is called on. | |
493 """ | |
494 if 'table' not in k: | |
495 k['table'] = self.table | |
496 if 'engine' not in k: | |
497 k['engine'] = k['table'].bind | |
498 return alter_column(self, *p, **k) | |
499 | |
500 def create(self, table=None, index_name=None, unique_name=None, | |
501 primary_key_name=None, populate_default=True, connection=None, **kwargs): | |
502 """Create this column in the database. | |
503 | |
504 Assumes the given table exists. ``ALTER TABLE ADD COLUMN``, | |
505 for most databases. | |
506 | |
507 :param table: Table instance to create on. | |
508 :param index_name: Creates :class:`ChangesetIndex` on this column. | |
509 :param unique_name: Creates :class:\ | |
510 `~migrate.changeset.constraint.UniqueConstraint` on this column. | |
511 :param primary_key_name: Creates :class:\ | |
512 `~migrate.changeset.constraint.PrimaryKeyConstraint` on this column. | |
513 :param alter_metadata: If True, column will be added to table object. | |
514 :param populate_default: If True, created column will be \ | |
515 populated with defaults | |
516 :param connection: reuse connection istead of creating new one. | |
517 :type table: Table instance | |
518 :type index_name: string | |
519 :type unique_name: string | |
520 :type primary_key_name: string | |
521 :type alter_metadata: bool | |
522 :type populate_default: bool | |
523 :type connection: :class:`sqlalchemy.engine.base.Connection` instance | |
524 | |
525 :returns: self | |
526 """ | |
527 self.populate_default = populate_default | |
528 self.alter_metadata = kwargs.pop('alter_metadata', DEFAULT_ALTER_METADATA) | |
529 self.index_name = index_name | |
530 self.unique_name = unique_name | |
531 self.primary_key_name = primary_key_name | |
532 for cons in ('index_name', 'unique_name', 'primary_key_name'): | |
533 self._check_sanity_constraints(cons) | |
534 | |
535 if self.alter_metadata: | |
536 self.add_to_table(table) | |
537 engine = self.table.bind | |
538 visitorcallable = get_engine_visitor(engine, 'columngenerator') | |
539 engine._run_visitor(visitorcallable, self, connection, **kwargs) | |
540 | |
541 # TODO: reuse existing connection | |
542 if self.populate_default and self.default is not None: | |
543 stmt = table.update().values({self: engine._execute_default(self.default)}) | |
544 engine.execute(stmt) | |
545 | |
546 return self | |
547 | |
548 def drop(self, table=None, connection=None, **kwargs): | |
549 """Drop this column from the database, leaving its table intact. | |
550 | |
551 ``ALTER TABLE DROP COLUMN``, for most databases. | |
552 | |
553 :param alter_metadata: If True, column will be removed from table object. | |
554 :type alter_metadata: bool | |
555 :param connection: reuse connection istead of creating new one. | |
556 :type connection: :class:`sqlalchemy.engine.base.Connection` instance | |
557 """ | |
558 self.alter_metadata = kwargs.pop('alter_metadata', DEFAULT_ALTER_METADATA) | |
559 if table is not None: | |
560 self.table = table | |
561 engine = self.table.bind | |
562 if self.alter_metadata: | |
563 self.remove_from_table(self.table, unset_table=False) | |
564 visitorcallable = get_engine_visitor(engine, 'columndropper') | |
565 engine._run_visitor(visitorcallable, self, connection, **kwargs) | |
566 if self.alter_metadata: | |
567 self.table = None | |
568 return self | |
569 | |
570 def add_to_table(self, table): | |
571 if table is not None and self.table is None: | |
572 self._set_parent(table) | |
573 | |
574 def _col_name_in_constraint(self, cons, name): | |
575 return False | |
576 | |
577 def remove_from_table(self, table, unset_table=True): | |
578 # TODO: remove primary keys, constraints, etc | |
579 if unset_table: | |
580 self.table = None | |
581 | |
582 to_drop = set() | |
583 for index in table.indexes: | |
584 columns = [] | |
585 for col in index.columns: | |
586 if col.name != self.name: | |
587 columns.append(col) | |
588 if columns: | |
589 index.columns = columns | |
590 else: | |
591 to_drop.add(index) | |
592 table.indexes = table.indexes - to_drop | |
593 | |
594 to_drop = set() | |
595 for cons in table.constraints: | |
596 # TODO: deal with other types of constraint | |
597 if isinstance(cons, (ForeignKeyConstraint, | |
598 UniqueConstraint)): | |
599 for col_name in cons.columns: | |
600 if not isinstance(col_name, basestring): | |
601 col_name = col_name.name | |
602 if self.name == col_name: | |
603 to_drop.add(cons) | |
604 table.constraints = table.constraints - to_drop | |
605 | |
606 if table.c.contains_column(self): | |
607 table.c.remove(self) | |
608 | |
609 # TODO: this is fixed in 0.6 | |
610 def copy_fixed(self, **kw): | |
611 """Create a copy of this ``Column``, with all attributes.""" | |
612 return sqlalchemy.Column(self.name, self.type, self.default, | |
613 key=self.key, | |
614 primary_key=self.primary_key, | |
615 nullable=self.nullable, | |
616 quote=self.quote, | |
617 index=self.index, | |
618 unique=self.unique, | |
619 onupdate=self.onupdate, | |
620 autoincrement=self.autoincrement, | |
621 server_default=self.server_default, | |
622 server_onupdate=self.server_onupdate, | |
623 *[c.copy(**kw) for c in self.constraints]) | |
624 | |
625 def _check_sanity_constraints(self, name): | |
626 """Check if constraints names are correct""" | |
627 obj = getattr(self, name) | |
628 if (getattr(self, name[:-5]) and not obj): | |
629 raise InvalidConstraintError("Column.create() accepts index_name," | |
630 " primary_key_name and unique_name to generate constraints") | |
631 if not isinstance(obj, basestring) and obj is not None: | |
632 raise InvalidConstraintError( | |
633 "%s argument for column must be constraint name" % name) | |
634 | |
635 | |
636 class ChangesetIndex(object): | |
637 """Changeset extensions to SQLAlchemy Indexes.""" | |
638 | |
639 __visit_name__ = 'index' | |
640 | |
641 def rename(self, name, connection=None, **kwargs): | |
642 """Change the name of an index. | |
643 | |
644 :param name: New name of the Index. | |
645 :type name: string | |
646 :param alter_metadata: If True, Index object will be altered. | |
647 :type alter_metadata: bool | |
648 :param connection: reuse connection istead of creating new one. | |
649 :type connection: :class:`sqlalchemy.engine.base.Connection` instance | |
650 """ | |
651 self.alter_metadata = kwargs.pop('alter_metadata', DEFAULT_ALTER_METADATA) | |
652 engine = self.table.bind | |
653 self.new_name = name | |
654 visitorcallable = get_engine_visitor(engine, 'schemachanger') | |
655 engine._run_visitor(visitorcallable, self, connection, **kwargs) | |
656 if self.alter_metadata: | |
657 self.name = name | |
658 | |
659 | |
660 class ChangesetDefaultClause(object): | |
661 """Implements comparison between :class:`DefaultClause` instances""" | |
662 | |
663 def __eq__(self, other): | |
664 if isinstance(other, self.__class__): | |
665 if self.arg == other.arg: | |
666 return True | |
667 | |
668 def __ne__(self, other): | |
669 return not self.__eq__(other) |