Commit 4ab53a55 authored by Ian Foote's avatar Ian Foote Committed by Marc Tamlyn
Browse files

Fixed #24767 -- Added Greatest and Least expressions

Greatest and Least are row-level Function versions of Min and Max.
parent fe21fb81
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -208,6 +208,10 @@ class BaseDatabaseFeatures(object):
    # Does the backend support "select for update" queries with limit (and offset)?
    supports_select_for_update_with_limit = True

    # Does the backend ignore null expressions in GREATEST and LEAST queries unless
    # every expression is null?
    greatest_least_ignores_nulls = False

    def __init__(self, connection):
        self.connection = connection

+1 −0
Original line number Diff line number Diff line
@@ -27,3 +27,4 @@ class DatabaseFeatures(BaseDatabaseFeatures):
    closed_cursor_error_class = InterfaceError
    has_case_insensitive_like = False
    requires_sqlparse_for_splitting = False
    greatest_least_ignores_nulls = True
+42 −0
Original line number Diff line number Diff line
@@ -83,6 +83,48 @@ class Concat(Func):
        return ConcatPair(expressions[0], self._paired(expressions[1:]))


class Greatest(Func):
    """
    Chooses the maximum expression and returns it.

    If any expression is null the return value is database-specific:
    On Postgres, the maximum not-null expression is returned.
    On MySQL, Oracle and SQLite, if any expression is null, null is
    returned.
    """
    function = 'GREATEST'

    def __init__(self, *expressions, **extra):
        if len(expressions) < 2:
            raise ValueError('Greatest must take at least two expressions')
        super(Greatest, self).__init__(*expressions, **extra)

    def as_sqlite(self, compiler, connection):
        """Use the MAX function on SQLite."""
        return super(Greatest, self).as_sql(compiler, connection, function='MAX')


class Least(Func):
    """
    Chooses the minimum expression and returns it.

    If any expression is null the return value is database-specific:
    On Postgres, the minimum not-null expression is returned.
    On MySQL, Oracle and SQLite, if any expression is null, null is
    returned.
    """
    function = 'LEAST'

    def __init__(self, *expressions, **extra):
        if len(expressions) < 2:
            raise ValueError('Least must take at least two expressions')
        super(Least, self).__init__(*expressions, **extra)

    def as_sqlite(self, compiler, connection):
        """Use the MIN function on SQLite."""
        return super(Least, self).as_sql(compiler, connection, function='MIN')


class Length(Func):
    """Returns the number of characters in the expression"""
    function = 'LENGTH'
+68 −0
Original line number Diff line number Diff line
@@ -82,6 +82,74 @@ Usage example::
    >>> print(author.screen_name)
    Margaret Smith (Maggie)

Greatest
--------

.. versionadded:: 1.9

.. class:: Greatest(*expressions, **extra)

Accepts a list of at least two field names or expressions and returns the
greatest value. Each argument must be of a similar type, so mixing text and numbers
will result in a database error.

Usage example::

    class Blog(models.Model):
        body = models.TextField()
        modified = models.DateTimeField(auto_now=True)

    class Comment(models.Model):
        body = models.TextField()
        modified = models.DateTimeField(auto_now=True)
        blog = models.ForeignKey(Blog)

    >>> from django.db.models.functions import Greatest
    >>> blog = Blog.objects.create(body='Greatest is the best.')
    >>> comment = Comment.objects.create(body='No, Least is better.', blog=blog)
    >>> comments = Comment.objects.annotate(last_updated=Greatest('modified', 'blog__modified'))
    >>> annotated_comment = comments.get()

``annotated_comment.last_updated`` will be the most recent of 
``blog.modified`` and ``comment.modified``.

.. warning::

    The behavior of ``Greatest`` when one or more expression may be ``null``
    varies between databases:

    - PostgreSQL: ``Greatest`` will return the largest non-null expression,
      or ``null`` if all expressions are ``null``.
    - SQLite, Oracle and MySQL: If any expression is ``null``, ``Greatest``
      will return ``null``.

    The PostgreSQL behavior can be emulated using ``Coalesce`` if you know
    a sensible minimum value to provide as a default.

Least
--------

.. versionadded:: 1.9

.. class:: Least(*expressions, **extra)

Accepts a list of at least two field names or expressions and returns the
least value. Each argument must be of a similar type, so mixing text and numbers
will result in a database error.

.. warning::

    The behavior of ``Least`` when one or more expression may be ``null``
    varies between databases:

    - PostgreSQL: ``Least`` will return the smallest non-null expression,
      or ``null`` if all expressions are ``null``.
    - SQLite, Oracle and MySQL: If any expression is ``null``, ``Least``
      will return ``null``.

    The PostgreSQL behavior can be emulated using ``Coalesce`` if you know
    a sensible maximum value to provide as a default.

Length
------

+3 −0
Original line number Diff line number Diff line
@@ -256,6 +256,9 @@ Models
* Added the :lookup:`date` lookup to :class:`~django.db.models.DateTimeField`
  to allow querying the field by only the date portion.

* Added the :class:`~django.db.models.functions.Greatest` and
  :class:`~django.db.models.functions.Least` database functions.

* Added the :class:`~django.db.models.functions.Now` database function, which
  returns the current date and time.

Loading