336
336
invert_sort_expression(expression)
337
337
for expression in self.getOrderBy()]
339
def andClausesForLeadingColumns(self, limits):
339
def limitsGroupedByOrderDirection(self, sort_expressions, memos):
340
"""Group sort expressions and memo values by order direction."""
341
descending = isinstance(sort_expressions[0], Desc)
343
expression_group = []
345
for expression, memo in zip(sort_expressions, memos):
346
if descending == isinstance(expression, Desc):
347
expression_group.append(expression)
348
memo_group.append(memo)
350
grouped_limits.append((expression_group, memo_group))
351
descending = isinstance(expression, Desc)
352
expression_group = [expression]
354
grouped_limits.append((expression_group, memo_group))
355
return grouped_limits
357
def lessThanOrGreaterThanExpression(self, expressions, memos):
358
"""Return an SQL expression "(expressions) OP (memos)".
360
OP is >, if the elements of expressions are PropertyColumns; else
361
the elements of expressions are instances of Desc(PropertyColumn)
364
descending = isinstance(expressions[0], Desc)
366
expressions = [expression.expr for expression in expressions]
367
expressions = map(compile, expressions)
368
expressions = ', '.join(expressions)
369
memos = ', '.join(sqlvalues(*memos))
371
return SQL('(%s) < (%s)' % (expressions, memos))
373
return SQL('(%s) > (%s)' % (expressions, memos))
375
def equalsExpressionsFromLimits(self, limits):
376
"""Return a list [expression == memo, ...] for the given limits."""
340
377
def plain_expression(expression):
341
# Strip a possible Desc from an expression.
342
378
if isinstance(expression, Desc):
343
379
return expression.expr
345
381
return expression
346
return [plain_expression(column) == memo for column, memo in limits]
348
def genericWhereExpressions(self, limits):
349
"""Generate WHERE expressions for the given sort columns and
352
:return: A list of where expressions which should be OR-ed
353
:param limits: A sequence of (column, mem_value) tuples.
355
Note that the result set may be ordered by more than one column.
356
Given the sort columns c[1], c[2] ... c[N] and assuming ascending
357
sorting, we must look for all rows where
358
* c[1] == memo[1], c[2] == memo[2] ... c[N-1] == memo[N-1] and
360
* c[1] == memo[1], c[2] == memo[2] ... c[N-2] == memo[N-2] and
363
* c[1] == memo[1], c[2] > memo[2]
384
for expressions, memos in limits:
386
plain_expression(expression) == memo
387
for expression, memo in zip(expressions, memos))
390
def whereExpressionsFromGroupedLimits(self, limits):
391
"""Build a sequence of WHERE expressions from the given limits.
393
limits is a list of tuples (expressions, memos), where
394
expressions is a list of PropertyColumn instances or of
395
instances of Desc(PropertyColumn). Desc(PropertyColumn)
396
and PropertyColumn instances must not appear in the same
399
memos are the memo values asociated with the columns in
402
Given a limits value of
403
[([c11, c12 ...], [m11, m12 ...]),
404
([c21, c22 ...], [m21, m22 ...]),
406
([cN1, cN2 ...], [mN1, mN2 ...])]
408
this method returns a sequence of these Storm/SQL expressions:
410
* (c11, c12 ...) = (m11, m12 ...) AND
411
(c21, c22 ...) = (m21, m22 ...) AND
413
(cN1, cN2 ...) < (mN1, mN2 ...)
414
* (c11, c12 ...) = (m11, m12 ...) AND
415
(c21, c22 ...) = (m21, m22 ...) AND
417
(cM1, cM2 ...) < (mM1, mM2 ...)
421
* (c11, c12 ...) < (m11, m12 ...)
423
The getSlice() should return rows matching any of these
424
expressions. Note that the result sets returned by each
425
expression are disjuct, hence they can be simply ORed,
426
as well as used in a UNION ALL query.
366
428
start = limits[:-1]
367
last_expression, last_memo = limits[-1]
368
if isinstance(last_expression, Desc):
369
last_expression = last_expression.expr
370
last_limit = last_expression < last_memo
372
last_limit = last_expression > last_memo
429
last_expressions, last_memos = limits[-1]
430
last_clause = self.lessThanOrGreaterThanExpression(
431
last_expressions, last_memos)
373
432
if len(start) > 0:
374
clauses = self.andClausesForLeadingColumns(start)
375
clauses.append(last_limit)
376
clause_for_last_column = reduce(And, clauses)
378
[clause_for_last_column]
379
+ self.genericWhereExpressions(start))
433
clauses = self.equalsExpressionsFromLimits(start)
434
clauses.append(last_clause)
435
clauses = [And(*clauses)]
436
return clauses + self.whereExpressionsFromGroupedLimits(start)
383
440
def whereExpressions(self, sort_expressions, memos):
384
441
"""WHERE expressions for the given sort columns and memos values."""
385
expression = sort_expressions[0]
386
descending = isinstance(expression, Desc)
388
for expression in sort_expressions[1:]:
389
if isinstance(expression, Desc) != descending:
392
if not consistent or len(sort_expressions) == 1:
393
return self.genericWhereExpressions(zip(sort_expressions, memos))
395
# If the columns are sorted either only ascending or only
396
# descending, we can specify a single WHERE condition
397
# (col1, col2...) > (memo1, memo2...)
400
expression.expr for expression in sort_expressions]
401
sort_expressions = map(compile, sort_expressions)
402
sort_expressions = ', '.join(sort_expressions)
403
memos = sqlvalues(*memos)
404
memos = ', '.join(memos)
406
return [SQL('(%s) < (%s)' % (sort_expressions, memos))]
408
return [SQL('(%s) > (%s)' % (sort_expressions, memos))]
442
grouped_limits = self.limitsGroupedByOrderDirection(
443
sort_expressions, memos)
444
return self.whereExpressionsFromGroupedLimits(grouped_limits)
410
446
def getSliceFromMemo(self, size, memo):
411
447
"""Return a result set for the given memo values.