[tryton-debian-vcs] python-sql branch upstream updated. upstream/0.8-1-gea30e0b

Mathias Behrle tryton-debian-vcs at alioth.debian.org
Mon Jun 19 13:29:52 UTC 2017


The following commit has been merged in the upstream branch:
https://alioth.debian.org/plugins/scmgit/cgi-bin/gitweb.cgi/?p=tryton/python-sql.git;a=commitdiff;h=upstream/0.8-1-gea30e0b

commit ea30e0b25f65f8e07c4a7c840eda8de42ba89bb2
Author: Mathias Behrle <mathiasb at m9s.biz>
Date:   Sat Jun 10 12:25:18 2017 +0200

    Adding upstream version 0.9.0.
    
    Signed-off-by: Mathias Behrle <mathiasb at m9s.biz>

diff --git a/CHANGELOG b/CHANGELOG
index e7337b6..f50694c 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,8 @@
+Version 0.9 - 2017-04-24
+* Add distinct_on on Select
+* Allow to use Select as Column of Select query
+* Support Select without from clause
+
 Version 0.8 - 2015-09-19
 * Add DISTINCT qualifier to aggregate expressions
 * Allow to order on select queries
diff --git a/PKG-INFO b/PKG-INFO
index 20cca95..55c47fd 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: python-sql
-Version: 0.8
+Version: 0.9
 Summary: Library to write SQL queries
 Home-page: http://python-sql.tryton.org/
 Author: B2CK
@@ -192,6 +192,7 @@ Description: python-sql
             ('SELECT "a".* FROM (SELECT "b".*, ROWNUM AS "rnum" FROM (SELECT * FROM "user" AS "c") AS "b" WHERE (ROWNUM <= %s)) AS "a" WHERE ("rnum" > %s)', (30, 20))
         
         qmark style::
+        
             >>> Flavor.set(Flavor(paramstyle='qmark'))
             >>> select = user.select()
             >>> select.where = user.name == 'foo'
diff --git a/README b/README
index 431680b..4b00cf5 100644
--- a/README
+++ b/README
@@ -184,6 +184,7 @@ Limit style::
     ('SELECT "a".* FROM (SELECT "b".*, ROWNUM AS "rnum" FROM (SELECT * FROM "user" AS "c") AS "b" WHERE (ROWNUM <= %s)) AS "a" WHERE ("rnum" > %s)', (30, 20))
 
 qmark style::
+
     >>> Flavor.set(Flavor(paramstyle='qmark'))
     >>> select = user.select()
     >>> select.where = user.name == 'foo'
diff --git a/python_sql.egg-info/PKG-INFO b/python_sql.egg-info/PKG-INFO
index 20cca95..55c47fd 100644
--- a/python_sql.egg-info/PKG-INFO
+++ b/python_sql.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: python-sql
-Version: 0.8
+Version: 0.9
 Summary: Library to write SQL queries
 Home-page: http://python-sql.tryton.org/
 Author: B2CK
@@ -192,6 +192,7 @@ Description: python-sql
             ('SELECT "a".* FROM (SELECT "b".*, ROWNUM AS "rnum" FROM (SELECT * FROM "user" AS "c") AS "b" WHERE (ROWNUM <= %s)) AS "a" WHERE ("rnum" > %s)', (30, 20))
         
         qmark style::
+        
             >>> Flavor.set(Flavor(paramstyle='qmark'))
             >>> select = user.select()
             >>> select.where = user.name == 'foo'
diff --git a/sql/__init__.py b/sql/__init__.py
index 48d3fea..9f104ff 100644
--- a/sql/__init__.py
+++ b/sql/__init__.py
@@ -1,8 +1,8 @@
 # -*- coding: utf-8 -*-
 #
-# Copyright (c) 2011-2015, Cédric Krier
+# Copyright (c) 2011-2016, Cédric Krier
 # Copyright (c) 2013-2014, Nicolas Évrard
-# Copyright (c) 2011-2015, B2CK
+# Copyright (c) 2011-2016, B2CK
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -29,7 +29,7 @@
 
 from __future__ import division
 
-__version__ = '0.8'
+__version__ = '0.9'
 __all__ = ['Flavor', 'Table', 'Values', 'Literal', 'Column', 'Join',
     'Asc', 'Desc', 'NullsFirst', 'NullsLast', 'format2numeric']
 
@@ -37,6 +37,7 @@ import string
 import warnings
 from threading import local, currentThread
 from collections import defaultdict
+from itertools import chain
 
 
 def alias(i, letters=string.ascii_lowercase):
@@ -293,7 +294,7 @@ class With(FromItem):
         super(With, self).__init__(**kwargs)
 
     def statement(self):
-        columns = ('(%s)' % ', '.join('"%s"' % c for c in self.columns)
+        columns = (' (%s)' % ', '.join('"%s"' % c for c in self.columns)
             if self.columns else '')
         return '"%s"%s AS (%s)' % (self.alias, columns, self.query)
 
@@ -382,20 +383,24 @@ class SelectQuery(WithQuery):
                 fetch = ' FETCH FIRST (%s) ROWS ONLY' % self.limit
             return offset + fetch
 
+    def as_(self, output_name):
+        return As(self, output_name)
+
 
 class Select(FromItem, SelectQuery):
     __slots__ = ('_columns', '_where', '_group_by', '_having', '_for_',
-        'from_')
+        'from_', '_distinct_on')
 
     def __init__(self, columns, from_=None, where=None, group_by=None,
-            having=None, for_=None, **kwargs):
+            having=None, for_=None, distinct_on=None, **kwargs):
+        self._distinct_on = None
         self._columns = None
         self._where = None
         self._group_by = None
         self._having = None
         self._for_ = None
         super(Select, self).__init__(**kwargs)
-        # TODO ALL|DISTINCT
+        self.distinct_on = distinct_on
         self.columns = columns
         self.from_ = from_
         self.where = where
@@ -404,12 +409,24 @@ class Select(FromItem, SelectQuery):
         self.for_ = for_
 
     @property
+    def distinct_on(self):
+        return self._distinct_on
+
+    @distinct_on.setter
+    def distinct_on(self, value):
+        if value is not None:
+            if isinstance(value, Expression):
+                value = [value]
+            assert all(isinstance(col, Expression) for col in value)
+        self._distinct_on = value
+
+    @property
     def columns(self):
         return self._columns
 
     @columns.setter
     def columns(self, value):
-        assert all(isinstance(col, Expression) for col in value)
+        assert all(isinstance(col, (Expression, SelectQuery)) for col in value)
         self._columns = tuple(value)
 
     @property
@@ -461,12 +478,19 @@ class Select(FromItem, SelectQuery):
     @staticmethod
     def _format_column(column):
         if isinstance(column, As):
+            if isinstance(column.expression, Select):
+                expression = '(%s)' % column.expression
+            else:
+                expression = column.expression
             if Flavor.get().no_as:
-                return '%s %s' % (column.expression, column)
+                return '%s %s' % (expression, column)
             else:
-                return '%s AS %s' % (column.expression, column)
+                return '%s AS %s' % (expression, column)
         else:
-            return str(column)
+            if isinstance(column, Select):
+                return '(%s)' % column
+            else:
+                return str(column)
 
     def _window_functions(self):
         from sql.functions import WindowFunction
@@ -528,7 +552,15 @@ class Select(FromItem, SelectQuery):
             return self._rownum(str)
 
         with AliasManager():
-            from_ = str(self.from_)
+            if self.from_ is not None:
+                from_ = ' FROM %s' % self.from_
+            else:
+                from_ = ''
+            if self.distinct_on is not None:
+                distinct_on = ('DISTINCT ON (%s) '
+                    % ', '.join(map(str, self.distinct_on)))
+            else:
+                distinct_on = ''
             if self.columns:
                 columns = ', '.join(map(self._format_column, self.columns))
             else:
@@ -551,7 +583,7 @@ class Select(FromItem, SelectQuery):
             if self.for_ is not None:
                 for_ = ' ' + ' '.join(map(str, self.for_))
             return (self._with_str()
-                + 'SELECT %s FROM %s' % (columns, from_)
+                + 'SELECT %s%s%s' % (distinct_on, columns, from_)
                 + where + group_by + having + window + self._order_by_str
                 + self._limit_offset_str + for_)
 
@@ -562,11 +594,12 @@ class Select(FromItem, SelectQuery):
             return self._rownum(lambda q: q.params)
         p = []
         p.extend(self._with_params())
-        for column in self.columns:
+        for column in chain(self.distinct_on or (), self.columns):
             if isinstance(column, As):
                 p.extend(column.expression.params)
             p.extend(column.params)
-        p.extend(self.from_.params)
+        if self.from_ is not None:
+            p.extend(self.from_.params)
         if self.where:
             p.extend(self.where.params)
         if self.group_by:
diff --git a/sql/tests/test_select.py b/sql/tests/test_select.py
index ad82b93..63ff5ab 100644
--- a/sql/tests/test_select.py
+++ b/sql/tests/test_select.py
@@ -1,8 +1,8 @@
 # -*- coding: utf-8 -*-
 #
-# Copyright (c) 2011-2015, Cédric Krier
+# Copyright (c) 2011-2016, Cédric Krier
 # Copyright (c) 2013-2014, Nicolas Évrard
-# Copyright (c) 2011-2015, B2CK
+# Copyright (c) 2011-2016, B2CK
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -59,6 +59,34 @@ class TestSelect(unittest.TestCase):
             'SELECT * FROM "t" AS "a" WHERE ("a"."c" = %s)')
         self.assertEqual(query.params, ('foo',))
 
+    def test_select_without_from(self):
+        query = Select([Literal(1)])
+        self.assertEqual(str(query), 'SELECT %s')
+        self.assertEqual(query.params, (1,))
+
+    def test_select_select(self):
+        query = Select([Select([Literal(1)])])
+        self.assertEqual(str(query), 'SELECT (SELECT %s)')
+        self.assertEqual(query.params, (1,))
+
+    def test_select_select_as(self):
+        query = Select([Select([Literal(1)]).as_('foo')])
+        self.assertEqual(str(query), 'SELECT (SELECT %s) AS "foo"')
+        self.assertEqual(query.params, (1,))
+
+    def test_select_distinct_on(self):
+        query = self.table.select(self.table.c, distinct_on=self.table.c)
+        self.assertEqual(
+            str(query), 'SELECT DISTINCT ON ("a"."c") "a"."c" FROM "t" AS "a"')
+        self.assertEqual(query.params, ())
+
+        query = self.table.select(
+            self.table.c, distinct_on=[self.table.a, self.table.b])
+        self.assertEqual(
+            str(query),
+            'SELECT DISTINCT ON ("a"."a", "a"."b") "a"."c" FROM "t" AS "a"')
+        self.assertEqual(query.params, ())
+
     def test_select_from_list(self):
         t2 = Table('t2')
         t3 = Table('t3')
diff --git a/sql/tests/test_with.py b/sql/tests/test_with.py
index 3fb8ed3..326f752 100644
--- a/sql/tests/test_with.py
+++ b/sql/tests/test_with.py
@@ -50,7 +50,7 @@ class TestWith(unittest.TestCase):
             second = With('a', query=self.table.select(self.table.a))
 
             self.assertEqual(second.statement(),
-                '"a"("a") AS ('
+                '"a" ("a") AS ('
                 'SELECT "b"."a" FROM "t" AS "b"'
                 ')')
             self.assertEqual(second.statement_params(), ())
@@ -82,7 +82,7 @@ class TestWith(unittest.TestCase):
 
         q = upto10.select(with_=[upto10])
         self.assertEqual(str(q),
-            'WITH RECURSIVE "a"("n") AS ('
+            'WITH RECURSIVE "a" ("n") AS ('
             'VALUES (%s) '
             'UNION ALL '
             'SELECT ("a"."n" + %s) FROM "a" AS "a" WHERE ("a"."n" < %s)'
-- 
python-sql



More information about the tryton-debian-vcs mailing list