Merge branch 'carrotquest-qs-final' into develop

This commit is contained in:
Itai Shirav 2018-12-14 08:32:10 +02:00
commit 50f1fed187
4 changed files with 63 additions and 3 deletions

View File

@ -117,6 +117,17 @@ Adds a DISTINCT clause to the query, meaning that any duplicate rows in the resu
>>> Person.objects_in(database).only('first_name').distinct().count() >>> Person.objects_in(database).only('first_name').distinct().count()
94 94
Final
--------
This method can be used only with CollapsingMergeTree engine.
Adds a FINAL modifier to the query, meaning data is selected fully "collapsed" by sign field.
>>> Person.objects_in(database).count()
100
>>> Person.objects_in(database).final().count()
94
Slicing Slicing
------- -------

View File

@ -1,8 +1,11 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import six import six
import pytz import pytz
from copy import copy from copy import copy
from math import ceil from math import ceil
from .engines import CollapsingMergeTree
from .utils import comma_join from .utils import comma_join
@ -243,6 +246,7 @@ class QuerySet(object):
self._fields = model_cls.fields().keys() self._fields = model_cls.fields().keys()
self._limits = None self._limits = None
self._distinct = False self._distinct = False
self._final = False
def __iter__(self): def __iter__(self):
""" """
@ -290,9 +294,10 @@ class QuerySet(object):
fields = comma_join('`%s`' % field for field in self._fields) fields = comma_join('`%s`' % field for field in self._fields)
ordering = '\nORDER BY ' + self.order_by_as_sql() if self._order_by else '' ordering = '\nORDER BY ' + self.order_by_as_sql() if self._order_by else ''
limit = '\nLIMIT %d, %d' % self._limits if self._limits else '' limit = '\nLIMIT %d, %d' % self._limits if self._limits else ''
params = (distinct, fields, self._model_cls.table_name(), final = ' FINAL' if self._final else ''
params = (distinct, fields, self._model_cls.table_name(), final,
self.conditions_as_sql(), ordering, limit) self.conditions_as_sql(), ordering, limit)
return u'SELECT %s%s\nFROM `%s`\nWHERE %s%s%s' % params return u'SELECT %s%s\nFROM `%s`%s\nWHERE %s%s%s' % params
def order_by_as_sql(self): def order_by_as_sql(self):
""" """
@ -399,6 +404,18 @@ class QuerySet(object):
qs._distinct = True qs._distinct = True
return qs return qs
def final(self):
"""
Adds a FINAL modifier to table, meaning data will be collapsed to final version.
Can be used with CollapsingMergeTree engine only
"""
if not isinstance(self._model_cls.engine, CollapsingMergeTree):
raise TypeError('final() method can be used only with CollapsingMergeTree engine')
qs = copy(self)
qs._final = True
return qs
def aggregate(self, *args, **kwargs): def aggregate(self, *args, **kwargs):
""" """
Returns an `AggregateQuerySet` over this query, with `args` serving as Returns an `AggregateQuerySet` over this query, with `args` serving as

View File

@ -148,4 +148,4 @@ data = [
{"first_name": "Whitney", "last_name": "Scott", "birthday": "1971-07-04", "height": "1.70"}, {"first_name": "Whitney", "last_name": "Scott", "birthday": "1971-07-04", "height": "1.70"},
{"first_name": "Wynter", "last_name": "Garcia", "birthday": "1975-01-10", "height": "1.69"}, {"first_name": "Wynter", "last_name": "Garcia", "birthday": "1975-01-10", "height": "1.69"},
{"first_name": "Yolanda", "last_name": "Duke", "birthday": "1997-02-25", "height": "1.74"} {"first_name": "Yolanda", "last_name": "Duke", "birthday": "1997-02-25", "height": "1.74"}
]; ]

View File

@ -141,6 +141,20 @@ class QuerySetTestCase(TestCaseWithData):
SampleModel(timestamp=now, num=4, color=Color.white), SampleModel(timestamp=now, num=4, color=Color.white),
]) ])
def _insert_sample_collapsing_model(self):
self.database.create_table(SampleCollapsingModel)
now = datetime.now()
self.database.insert([
SampleCollapsingModel(timestamp=now, num=1, color=Color.red),
SampleCollapsingModel(timestamp=now, num=2, color=Color.red),
SampleCollapsingModel(timestamp=now, num=2, color=Color.red, sign=-1),
SampleCollapsingModel(timestamp=now, num=2, color=Color.green),
SampleCollapsingModel(timestamp=now, num=3, color=Color.white),
SampleCollapsingModel(timestamp=now, num=4, color=Color.white, sign=1),
SampleCollapsingModel(timestamp=now, num=4, color=Color.white, sign=-1),
SampleCollapsingModel(timestamp=now, num=4, color=Color.blue, sign=1),
])
def test_filter_enum_field(self): def test_filter_enum_field(self):
self._insert_sample_model() self._insert_sample_model()
qs = SampleModel.objects_in(self.database) qs = SampleModel.objects_in(self.database)
@ -249,6 +263,17 @@ class QuerySetTestCase(TestCaseWithData):
self._test_qs(qs[70:80], 10) self._test_qs(qs[70:80], 10)
self._test_qs(qs[80:], 20) self._test_qs(qs[80:], 20)
def test_final(self):
# Final can be used with CollapsingMergeTree engine only
with self.assertRaises(TypeError):
Person.objects_in(self.database).final()
self._insert_sample_collapsing_model()
res = list(SampleCollapsingModel.objects_in(self.database).final().order_by('num'))
self.assertEqual(4, len(res))
for item, exp_color in zip(res, (Color.red, Color.green, Color.white, Color.blue)):
self.assertEqual(exp_color, item.color)
class AggregateTestCase(TestCaseWithData): class AggregateTestCase(TestCaseWithData):
@ -392,6 +417,13 @@ class SampleModel(Model):
engine = MergeTree('materialized_date', ('materialized_date',)) engine = MergeTree('materialized_date', ('materialized_date',))
class SampleCollapsingModel(SampleModel):
sign = Int8Field(default=1)
engine = CollapsingMergeTree('materialized_date', ('num',), 'sign')
class Numbers(Model): class Numbers(Model):
number = UInt64Field() number = UInt64Field()