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 / selectable.py

# sql/selectable.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 :class:`.FromClause` class of SQL expression elements, representing
SQL tables and derived rowsets.

"""

from .elements import ClauseElement, TextClause, ClauseList, \
    and_, Grouping, UnaryExpression, literal_column, BindParameter
from .elements import _clone, \
    _literal_as_text, _interpret_as_column_or_from, _expand_cloned,\
    _select_iterables, _anonymous_label, _clause_element_as_expr,\
    _cloned_intersection, _cloned_difference, True_, \
    _literal_as_label_reference, _literal_and_labels_as_label_reference
from .base import Immutable, Executable, _generative, \
    ColumnCollection, ColumnSet, _from_objects, Generative
from . import type_api
from .. import inspection
from .. import util
from .. import exc
from operator import attrgetter
from . import operators
import operator
import collections
from .annotation import Annotated
import itertools
from sqlalchemy.sql.visitors import Visitable


def _interpret_as_from(element):
    insp = inspection.inspect(element, raiseerr=False)
    if insp is None:
        if isinstance(element, util.string_types):
            util.warn_limited(
                "Textual SQL FROM expression %(expr)r should be "
                "explicitly declared as text(%(expr)r), "
                "or use table(%(expr)r) for more specificity",
                {"expr": util.ellipses_string(element)})

            return TextClause(util.text_type(element))
    try:
        return insp.selectable
    except AttributeError:
        raise exc.ArgumentError("FROM expression expected")


def _interpret_as_select(element):
    element = _interpret_as_from(element)
    if isinstance(element, Alias):
        element = element.original
    if not isinstance(element, SelectBase):
        element = element.select()
    return element


class _OffsetLimitParam(BindParameter):
    @property
    def _limit_offset_value(self):
        return self.effective_value


def _offset_or_limit_clause(element, name=None, type_=None):
    """Convert the given value to an "offset or limit" clause.

    This handles incoming integers and converts to an expression; if
    an expression is already given, it is passed through.

    """
    if element is None:
        return None
    elif hasattr(element, '__clause_element__'):
        return element.__clause_element__()
    elif isinstance(element, Visitable):
        return element
    else:
        value = util.asint(element)
        return _OffsetLimitParam(name, value, type_=type_, unique=True)


def _offset_or_limit_clause_asint(clause, attrname):
    """Convert the "offset or limit" clause of a select construct to an
    integer.

    This is only possible if the value is stored as a simple bound parameter.
    Otherwise, a compilation error is raised.

    """
    if clause is None:
        return None
    try:
        value = clause._limit_offset_value
    except AttributeError:
        raise exc.CompileError(
            "This SELECT structure does not use a simple "
            "integer value for %s" % attrname)
    else:
        return util.asint(value)


def subquery(alias, *args, **kwargs):
    r"""Return an :class:`.Alias` object derived
    from a :class:`.Select`.

    name
      alias name

    \*args, \**kwargs

      all other arguments are delivered to the
      :func:`select` function.

    """
    return Select(*args, **kwargs).alias(alias)


def alias(selectable, name=None, flat=False):
    """Return an :class:`.Alias` object.

    An :class:`.Alias` represents any :class:`.FromClause`
    with an alternate name assigned within SQL, typically using the ``AS``
    clause when generated, e.g. ``SELECT * FROM table AS aliasname``.

    Similar functionality is available via the
    :meth:`~.FromClause.alias` method
    available on all :class:`.FromClause` subclasses.

    When an :class:`.Alias` is created from a :class:`.Table` object,
    this has the effect of the table being rendered
    as ``tablename AS aliasname`` in a SELECT statement.

    For :func:`.select` objects, the effect is that of creating a named
    subquery, i.e. ``(select ...) AS aliasname``.

    The ``name`` parameter is optional, and provides the name
    to use in the rendered SQL.  If blank, an "anonymous" name
    will be deterministically generated at compile time.
    Deterministic means the name is guaranteed to be unique against
    other constructs used in the same statement, and will also be the
    same name for each successive compilation of the same statement
    object.

    :param selectable: any :class:`.FromClause` subclass,
        such as a table, select statement, etc.

    :param name: string name to be assigned as the alias.
        If ``None``, a name will be deterministically generated
        at compile time.

    :param flat: Will be passed through to if the given selectable
     is an instance of :class:`.Join` - see :meth:`.Join.alias`
     for details.

     .. versionadded:: 0.9.0

    """
    return _interpret_as_from(selectable).alias(name=name, flat=flat)


def lateral(selectable, name=None):
    """Return a :class:`.Lateral` object.

    :class:`.Lateral` is an :class:`.Alias` subclass that represents
    a subquery with the LATERAL keyword applied to it.

    The special behavior of a LATERAL subquery is that it appears in the
    FROM clause of an enclosing SELECT, but may correlate to other
    FROM clauses of that SELECT.   It is a special case of subquery
    only supported by a small number of backends, currently more recent
    PostgreSQL versions.

    .. versionadded:: 1.1

    .. seealso::

        :ref:`lateral_selects` -  overview of usage.

    """
    return _interpret_as_from(selectable).lateral(name=name)


def tablesample(selectable, sampling, name=None, seed=None):
    """Return a :class:`.TableSample` object.

    :class:`.TableSample` is an :class:`.Alias` subclass that represents
    a table with the TABLESAMPLE clause applied to it.
    :func:`~.expression.tablesample`
    is also available from the :class:`.FromClause` class via the
    :meth:`.FromClause.tablesample` method.

    The TABLESAMPLE clause allows selecting a randomly selected approximate
    percentage of rows from a table. It supports multiple sampling methods,
    most commonly BERNOULLI and SYSTEM.

    e.g.::

        from sqlalchemy import func

        selectable = people.tablesample(
                    func.bernoulli(1),
                    name='alias',
                    seed=func.random())
        stmt = select([selectable.c.people_id])

    Assuming ``people`` with a column ``people_id``, the above
    statement would render as::

        SELECT alias.people_id FROM
        people AS alias TABLESAMPLE bernoulli(:bernoulli_1)
        REPEATABLE (random())

    .. versionadded:: 1.1

    :param sampling: a ``float`` percentage between 0 and 100 or
        :class:`.functions.Function`.

    :param name: optional alias name

    :param seed: any real-valued SQL expression.  When specified, the
     REPEATABLE sub-clause is also rendered.

    """
    return _interpret_as_from(selectable).tablesample(
        sampling, name=name, seed=seed)


class Selectable(ClauseElement):
    """mark a class as being selectable"""
    __visit_name__ = 'selectable'

    is_selectable = True

    @property
    def selectable(self):
        return self


class HasPrefixes(object):
    _prefixes = ()

    @_generative
    def prefix_with(self, *expr, **kw):
        r"""Add one or more expressions following the statement keyword, i.e.
        SELECT, INSERT, UPDATE, or DELETE. Generative.

        This is used to support backend-specific prefix keywords such as those
        provided by MySQL.

        E.g.::

            stmt = table.insert().prefix_with("LOW_PRIORITY", dialect="mysql")

        Multiple prefixes can be specified by multiple calls
        to :meth:`.prefix_with`.

        :param \*expr: textual or :class:`.ClauseElement` construct which
         will be rendered following the INSERT, UPDATE, or DELETE
         keyword.
        :param \**kw: A single keyword 'dialect' is accepted.  This is an
         optional string dialect name which will
         limit rendering of this prefix to only that dialect.

        """
        dialect = kw.pop('dialect', None)
        if kw:
            raise exc.ArgumentError("Unsupported argument(s): %s" %
                                    ",".join(kw))
        self._setup_prefixes(expr, dialect)

    def _setup_prefixes(self, prefixes, dialect=None):
        self._prefixes = self._prefixes + tuple(
            [(_literal_as_text(p, warn=False), dialect) for p in prefixes])


class HasSuffixes(object):
    _suffixes = ()

    @_generative
    def suffix_with(self, *expr, **kw):
        r"""Add one or more expressions following the statement as a whole.

        This is used to support backend-specific suffix keywords on
        certain constructs.

        E.g.::

            stmt = select([col1, col2]).cte().suffix_with(
                "cycle empno set y_cycle to 1 default 0", dialect="oracle")

        Multiple suffixes can be specified by multiple calls
        to :meth:`.suffix_with`.

        :param \*expr: textual or :class:`.ClauseElement` construct which
         will be rendered following the target clause.
        :param \**kw: A single keyword 'dialect' is accepted.  This is an
         optional string dialect name which will
         limit rendering of this suffix to only that dialect.

        """
        dialect = kw.pop('dialect', None)
        if kw:
            raise exc.ArgumentError("Unsupported argument(s): %s" %
                                    ",".join(kw))
        self._setup_suffixes(expr, dialect)

    def _setup_suffixes(self, suffixes, dialect=None):
        self._suffixes = self._suffixes + tuple(
            [(_literal_as_text(p, warn=False), dialect) for p in suffixes])


class FromClause(Selectable):
    """Represent an element that can be used within the ``FROM``
    clause of a ``SELECT`` statement.

    The most common forms of :class:`.FromClause` are the
    :class:`.Table` and the :func:`.select` constructs.  Key
    features common to all :class:`.FromClause` objects include:

    * a :attr:`.c` collection, which provides per-name access to a collection
      of :class:`.ColumnElement` objects.
    * a :attr:`.primary_key` attribute, which is a collection of all those
      :class:`.ColumnElement` objects that indicate the ``primary_key`` flag.
    * Methods to generate various derivations of a "from" clause, including
      :meth:`.FromClause.alias`, :meth:`.FromClause.join`,
      :meth:`.FromClause.select`.


    """
    __visit_name__ = 'fromclause'
    named_with_column = False
    _hide_froms = []

    _is_join = False
    _is_select = False
    _is_from_container = False

    _textual = False
    """a marker that allows us to easily distinguish a :class:`.TextAsFrom`
    or similar object from other kinds of :class:`.FromClause` objects."""

    schema = None
Loading ...