Learn more  » Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Bower components Debian packages RPM packages NuGet packages

aroundthecode / SQLAlchemy   python

Repository URL to install this package:

Version: 1.2.10 

/ sql / schema.py

# sql/schema.py
# Copyright (C) 2005-2018 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
# the MIT License: http://www.opensource.org/licenses/mit-license.php

"""The schema module provides the building blocks for database metadata.

Each element within this module describes a database entity which can be
created and dropped, or is otherwise part of such an entity.  Examples include
tables, columns, sequences, and indexes.

All entities are subclasses of :class:`~sqlalchemy.schema.SchemaItem`, and as
defined in this module they are intended to be agnostic of any vendor-specific
constructs.

A collection of entities are grouped into a unit called
:class:`~sqlalchemy.schema.MetaData`. MetaData serves as a logical grouping of
schema elements, and can also be associated with an actual database connection
such that operations involving the contained elements can contact the database
as needed.

Two of the elements here also build upon their "syntactic" counterparts, which
are defined in :class:`~sqlalchemy.sql.expression.`, specifically
:class:`~sqlalchemy.schema.Table` and :class:`~sqlalchemy.schema.Column`.
Since these objects are part of the SQL expression language, they are usable
as components in SQL expressions.

"""
from __future__ import absolute_import

from .. import exc, util, event, inspection
from .base import SchemaEventTarget, DialectKWArgs
import operator
from . import visitors
from . import type_api
from .base import _bind_or_error, ColumnCollection
from .elements import ClauseElement, ColumnClause, \
    _as_truncated, TextClause, _literal_as_text,\
    ColumnElement, quoted_name
from .selectable import TableClause
import collections
import sqlalchemy
from . import ddl

RETAIN_SCHEMA = util.symbol('retain_schema')

BLANK_SCHEMA = util.symbol(
    'blank_schema',
    """Symbol indicating that a :class:`.Table` or :class:`.Sequence`
    should have 'None' for its schema, even if the parent
    :class:`.MetaData` has specified a schema.

    .. versionadded:: 1.0.14

    """
)


def _get_table_key(name, schema):
    if schema is None:
        return name
    else:
        return schema + "." + name


# this should really be in sql/util.py but we'd have to
# break an import cycle
def _copy_expression(expression, source_table, target_table):
    def replace(col):
        if isinstance(col, Column) and \
                col.table is source_table and col.key in source_table.c:
            return target_table.c[col.key]
        else:
            return None
    return visitors.replacement_traverse(expression, {}, replace)


@inspection._self_inspects
class SchemaItem(SchemaEventTarget, visitors.Visitable):
    """Base class for items that define a database schema."""

    __visit_name__ = 'schema_item'

    def _init_items(self, *args):
        """Initialize the list of child items for this SchemaItem."""

        for item in args:
            if item is not None:
                item._set_parent_with_dispatch(self)

    def get_children(self, **kwargs):
        """used to allow SchemaVisitor access"""
        return []

    def __repr__(self):
        return util.generic_repr(self, omit_kwarg=['info'])

    @property
    @util.deprecated('0.9', 'Use ``<obj>.name.quote``')
    def quote(self):
        """Return the value of the ``quote`` flag passed
        to this schema object, for those schema items which
        have a ``name`` field.

        """

        return self.name.quote

    @util.memoized_property
    def info(self):
        """Info dictionary associated with the object, allowing user-defined
        data to be associated with this :class:`.SchemaItem`.

        The dictionary is automatically generated when first accessed.
        It can also be specified in the constructor of some objects,
        such as :class:`.Table` and :class:`.Column`.

        """
        return {}

    def _schema_item_copy(self, schema_item):
        if 'info' in self.__dict__:
            schema_item.info = self.info.copy()
        schema_item.dispatch._update(self.dispatch)
        return schema_item

    def _translate_schema(self, effective_schema, map_):
        return map_.get(effective_schema, effective_schema)


class Table(DialectKWArgs, SchemaItem, TableClause):
    r"""Represent a table in a database.

    e.g.::

        mytable = Table("mytable", metadata,
                        Column('mytable_id', Integer, primary_key=True),
                        Column('value', String(50))
                   )

    The :class:`.Table` object constructs a unique instance of itself based
    on its name and optional schema name within the given
    :class:`.MetaData` object. Calling the :class:`.Table`
    constructor with the same name and same :class:`.MetaData` argument
    a second time will return the *same* :class:`.Table` object - in this way
    the :class:`.Table` constructor acts as a registry function.

    .. seealso::

        :ref:`metadata_describing` - Introduction to database metadata

    Constructor arguments are as follows:

    :param name: The name of this table as represented in the database.

        The table name, along with the value of the ``schema`` parameter,
        forms a key which uniquely identifies this :class:`.Table` within
        the owning :class:`.MetaData` collection.
        Additional calls to :class:`.Table` with the same name, metadata,
        and schema name will return the same :class:`.Table` object.

        Names which contain no upper case characters
        will be treated as case insensitive names, and will not be quoted
        unless they are a reserved word or contain special characters.
        A name with any number of upper case characters is considered
        to be case sensitive, and will be sent as quoted.

        To enable unconditional quoting for the table name, specify the flag
        ``quote=True`` to the constructor, or use the :class:`.quoted_name`
        construct to specify the name.

    :param metadata: a :class:`.MetaData` object which will contain this
        table.  The metadata is used as a point of association of this table
        with other tables which are referenced via foreign key.  It also
        may be used to associate this table with a particular
        :class:`.Connectable`.

    :param \*args: Additional positional arguments are used primarily
        to add the list of :class:`.Column` objects contained within this
        table. Similar to the style of a CREATE TABLE statement, other
        :class:`.SchemaItem` constructs may be added here, including
        :class:`.PrimaryKeyConstraint`, and :class:`.ForeignKeyConstraint`.

    :param autoload: Defaults to False, unless :paramref:`.Table.autoload_with`
        is set in which case it defaults to True; :class:`.Column` objects
        for this table should be reflected from the database, possibly
        augmenting or replacing existing :class:`.Column` objects that were
        explicitly specified.

        .. versionchanged:: 1.0.0 setting the :paramref:`.Table.autoload_with`
           parameter implies that :paramref:`.Table.autoload` will default
           to True.

        .. seealso::

            :ref:`metadata_reflection_toplevel`

    :param autoload_replace: Defaults to ``True``; when using
        :paramref:`.Table.autoload`
        in conjunction with :paramref:`.Table.extend_existing`, indicates
        that :class:`.Column` objects present in the already-existing
        :class:`.Table` object should be replaced with columns of the same
        name retrieved from the autoload process.   When ``False``, columns
        already present under existing names will be omitted from the
        reflection process.

        Note that this setting does not impact :class:`.Column` objects
        specified programmatically within the call to :class:`.Table` that
        also is autoloading; those :class:`.Column` objects will always
        replace existing columns of the same name when
        :paramref:`.Table.extend_existing` is ``True``.

        .. versionadded:: 0.7.5

        .. seealso::

            :paramref:`.Table.autoload`

            :paramref:`.Table.extend_existing`

    :param autoload_with: An :class:`.Engine` or :class:`.Connection` object
        with which this :class:`.Table` object will be reflected; when
        set to a non-None value, it implies that :paramref:`.Table.autoload`
        is ``True``.   If left unset, but :paramref:`.Table.autoload` is
        explicitly set to ``True``, an autoload operation will attempt to
        proceed by locating an :class:`.Engine` or :class:`.Connection` bound
        to the underlying :class:`.MetaData` object.

        .. seealso::

            :paramref:`.Table.autoload`

    :param extend_existing: When ``True``, indicates that if this
        :class:`.Table` is already present in the given :class:`.MetaData`,
        apply further arguments within the constructor to the existing
        :class:`.Table`.

        If :paramref:`.Table.extend_existing` or
        :paramref:`.Table.keep_existing` are not set, and the given name
        of the new :class:`.Table` refers to a :class:`.Table` that is
        already present in the target :class:`.MetaData` collection, and
        this :class:`.Table` specifies additional columns or other constructs
        or flags that modify the table's state, an
        error is raised.  The purpose of these two mutually-exclusive flags
        is to specify what action should be taken when a :class:`.Table`
        is specified that matches an existing :class:`.Table`, yet specifies
        additional constructs.

        :paramref:`.Table.extend_existing` will also work in conjunction
        with :paramref:`.Table.autoload` to run a new reflection
        operation against the database, even if a :class:`.Table`
        of the same name is already present in the target
        :class:`.MetaData`; newly reflected :class:`.Column` objects
        and other options will be added into the state of the
        :class:`.Table`, potentially overwriting existing columns
        and options of the same name.

        .. versionchanged:: 0.7.4 :paramref:`.Table.extend_existing` will
           invoke a new reflection operation when combined with
           :paramref:`.Table.autoload` set to True.

        As is always the case with :paramref:`.Table.autoload`,
        :class:`.Column` objects can be specified in the same :class:`.Table`
        constructor, which will take precedence.  Below, the existing
        table ``mytable`` will be augmented with :class:`.Column` objects
        both reflected from the database, as well as the given :class:`.Column`
        named "y"::

            Table("mytable", metadata,
                        Column('y', Integer),
                        extend_existing=True,
                        autoload=True,
                        autoload_with=engine
                    )

        .. seealso::

            :paramref:`.Table.autoload`

            :paramref:`.Table.autoload_replace`

            :paramref:`.Table.keep_existing`


    :param implicit_returning: True by default - indicates that
        RETURNING can be used by default to fetch newly inserted primary key
        values, for backends which support this.  Note that
        create_engine() also provides an implicit_returning flag.

    :param include_columns: A list of strings indicating a subset of
        columns to be loaded via the ``autoload`` operation; table columns who
        aren't present in this list will not be represented on the resulting
        ``Table`` object. Defaults to ``None`` which indicates all columns
        should be reflected.

    :param info: Optional data dictionary which will be populated into the
        :attr:`.SchemaItem.info` attribute of this object.

    :param keep_existing: When ``True``, indicates that if this Table
        is already present in the given :class:`.MetaData`, ignore
        further arguments within the constructor to the existing
        :class:`.Table`, and return the :class:`.Table` object as
        originally created. This is to allow a function that wishes
        to define a new :class:`.Table` on first call, but on
        subsequent calls will return the same :class:`.Table`,
        without any of the declarations (particularly constraints)
        being applied a second time.

        If :paramref:`.Table.extend_existing` or
        :paramref:`.Table.keep_existing` are not set, and the given name
        of the new :class:`.Table` refers to a :class:`.Table` that is
        already present in the target :class:`.MetaData` collection, and
        this :class:`.Table` specifies additional columns or other constructs
        or flags that modify the table's state, an
        error is raised.  The purpose of these two mutually-exclusive flags
        is to specify what action should be taken when a :class:`.Table`
        is specified that matches an existing :class:`.Table`, yet specifies
        additional constructs.

        .. seealso::

            :paramref:`.Table.extend_existing`

    :param listeners: A list of tuples of the form ``(<eventname>, <fn>)``
        which will be passed to :func:`.event.listen` upon construction.
        This alternate hook to :func:`.event.listen` allows the establishment
        of a listener function specific to this :class:`.Table` before
        the "autoload" process begins.  Particularly useful for
        the :meth:`.DDLEvents.column_reflect` event::

            def listen_for_reflect(table, column_info):
                "handle the column reflection event"
                # ...

            t = Table(
                'sometable',
                autoload=True,
                listeners=[
                    ('column_reflect', listen_for_reflect)
                ])

    :param mustexist: When ``True``, indicates that this Table must already
        be present in the given :class:`.MetaData` collection, else
Loading ...