def test_getSlice__forward_without_memo(self): resultset = self.makeStormResultSet() resultset.order_by(Person.name, Person.id) all_results = list(resultset) range_factory = StormRangeFactory(resultset) sliced_result = range_factory.getSlice(3) self.assertEqual(all_results[:3], list(sliced_result))
def _getBatchNavigator(self, grantees): """Return the batch navigator to be used to batch the grantees.""" return BatchNavigator(grantees, self.request, hide_counts=True, size=config.launchpad.default_batch_size, range_factory=StormRangeFactory(grantees))
def test_parseMemo__json_no_sequence(self): # parseMemo() accepts only JSON representations of lists. resultset = self.makeStormResultSet() range_factory = StormRangeFactory(resultset, self.logError) self.assertIs(None, range_factory.parseMemo(simplejson.dumps(1))) self.assertEqual(['memo must be the JSON representation of a list.'], self.error_messages)
def test_getSlice__returns_ShadowedList(self): # getSlice() returns lists. resultset = self.makeStormResultSet() resultset.order_by(Person.id) range_factory = StormRangeFactory(resultset) sliced_result = range_factory.getSlice(3) self.assertIsInstance(sliced_result, ShadowedList)
def test_parseMemo__descending_sort_order(self): # Validation of a memo string against a descending sort order works. resultset = self.makeStormResultSet() resultset.order_by(Desc(Person.id)) range_factory = StormRangeFactory(resultset, self.logError) self.assertEqual( [1], range_factory.parseMemo(simplejson.dumps([1])))
def test_parseMemo__json_error(self): # parseMemo() returns None for formally invalid JSON strings. resultset = self.makeStormResultSet() range_factory = StormRangeFactory(resultset, self.logError) self.assertIs(None, range_factory.parseMemo('foo')) self.assertEqual( ['memo is not a valid JSON string.'], self.error_messages)
def test_rough_length_decorated_result_set(self): # StormRangeFactory.rough_length can handle DecoratedResultSets. resultset = self.makeDecoratedStormResultSet() range_factory = StormRangeFactory(resultset) estimated_length = range_factory.rough_length self.assertThat(estimated_length, LessThan(10)) self.assertThat(estimated_length, Not(LessThan(1)))
def test_getOrderValuesFor__decorated_result_set(self): # getOrderValuesFor() knows how to retrieve SQL sort values # from DecoratedResultSets. resultset = self.makeDecoratedStormResultSet() range_factory = StormRangeFactory(resultset) self.assertEqual( [resultset[0].id], range_factory.getOrderValuesFor(resultset[0]))
def test_StormRangeFactory__EmptyResultSet(self): # It is possible to create StormRangeFactory instances for # EmptyResultSets, resultset = EmptyResultSet() range_factory = StormRangeFactory(resultset) self.assertEqual(0, range_factory.rough_length) self.assertEmptyResultSetsWorking(range_factory)
def test_limitsGroupedByOrderDirection(self): # limitsGroupedByOrderDirection() returns a sequence of # (expressions, memos), where expressions is a list of # ORDER BY expressions which either are all instances of # PropertyColumn, or are all instances of Desc(PropertyColumn). # memos are the related limit values. resultset = self.makeStormResultSet() range_factory = StormRangeFactory(resultset, self.logError) order_by = [ Person.id, Person.datecreated, Person.name, Person.display_name ] limits = [1, datetime(2011, 7, 25, 0, 0, 0), 'foo', 'bar'] result = range_factory.limitsGroupedByOrderDirection(order_by, limits) self.assertEqual([(order_by, limits)], result) order_by = [ Desc(Person.id), Desc(Person.datecreated), Desc(Person.name), Desc(Person.display_name) ] result = range_factory.limitsGroupedByOrderDirection(order_by, limits) self.assertEqual([(order_by, limits)], result) order_by = [ Person.id, Person.datecreated, Desc(Person.name), Desc(Person.display_name) ] result = range_factory.limitsGroupedByOrderDirection(order_by, limits) self.assertEqual([(order_by[:2], limits[:2]), (order_by[2:], limits[2:])], result)
def test_getOrderValuesFor__descending_sort_order(self): # getOrderValuesFor() can retrieve values from reverse sorted # columns. resultset = self.makeStormResultSet() resultset = resultset.order_by(Desc(Person.id)) range_factory = StormRangeFactory(resultset) self.assertEqual( [resultset[0].id], range_factory.getOrderValuesFor(resultset[0]))
def test_getOrderValuesFor__two_sort_columns(self): # Sorting by more than one column is supported. resultset = self.makeStormResultSet() resultset.order_by(Person.displayname, Person.name) range_factory = StormRangeFactory(resultset) order_values = range_factory.getOrderValuesFor(resultset[0]) self.assertEqual( [resultset[0].displayname, resultset[0].name], order_values)
def test_whereExpressions__asc(self): """For ascending sort order, whereExpressions() returns the WHERE clause expression > memo. """ resultset = self.makeStormResultSet() range_factory = StormRangeFactory(resultset, self.logError) [where_clause] = range_factory.whereExpressions([Person.id], [1]) self.assertEquals('(Person.id) > (1)', compile(where_clause))
def test_getSlice__forward_with_memo(self): resultset = self.makeStormResultSet() resultset.order_by(Person.name, Person.id) all_results = list(resultset) memo = simplejson.dumps([all_results[0].name, all_results[0].id]) range_factory = StormRangeFactory(resultset) sliced_result = range_factory.getSlice(3, memo) self.assertEqual(all_results[1:4], list(sliced_result))
def test_getOrderValuesFor__value_from_second_element_of_result_row(self): # getOrderValuesFor() can retrieve values from attributes # of any Storm table class instance which appear in a result row. resultset = self.makeDecoratedStormResultSet() resultset = resultset.order_by(LibraryFileAlias.id) plain_resultset = resultset.get_plain_result_set() range_factory = StormRangeFactory(resultset) self.assertEqual([plain_resultset[0][1].id], range_factory.getOrderValuesFor(plain_resultset[0]))
def test_rough_length_distinct_query(self): # StormRangeFactory.rough_length with SELECT DISTINCT queries. resultset = self.makeStormResultSet() resultset.config(distinct=True) resultset.order_by(Person.name, Person.id) range_factory = StormRangeFactory(resultset) estimated_length = range_factory.rough_length self.assertThat(estimated_length, LessThan(10)) self.assertThat(estimated_length, Not(LessThan(1)))
def test_getOrderValuesFor__one_sort_column(self): # StormRangeFactory.getOrderValuesFor() returns the values # of the fields used in order_by expresssions for a given # result row. resultset = self.makeStormResultSet() resultset.order_by(Person.id) range_factory = StormRangeFactory(resultset) order_values = range_factory.getOrderValuesFor(resultset[0]) self.assertEqual([resultset[0].id], order_values)
def test_rough_length_first_sort_column_desc(self): # StormRangeFactory.rough_length can handle result sets where # the first sort column has descendig order. resultset = self.makeStormResultSet() resultset.order_by(Desc(Person.id)) range_factory = StormRangeFactory(resultset) estimated_length = range_factory.rough_length self.assertThat(estimated_length, LessThan(10)) self.assertThat(estimated_length, Not(LessThan(1)))
def test_getSlice__backward_without_memo(self): resultset = self.makeStormResultSet() resultset.order_by(Person.name, Person.id) all_results = list(resultset) expected = all_results[-3:] expected.reverse() range_factory = StormRangeFactory(resultset) sliced_result = range_factory.getSlice(3, forwards=False) self.assertEqual(expected, list(sliced_result))
def test_rough_length(self): # StormRangeFactory.rough_length returns an estimate of the # length of the result set. resultset = self.makeStormResultSet() resultset.order_by(Person.id) range_factory = StormRangeFactory(resultset) estimated_length = range_factory.rough_length self.assertThat(estimated_length, LessThan(10)) self.assertThat(estimated_length, Not(LessThan(1)))
def test_parseMemo__invalid_iso_timestamp_value(self): # An ISO timestamp with an invalid date is rejected as a memo # string. resultset = self.makeStormResultSet() resultset.order_by(Person.datecreated) range_factory = StormRangeFactory(resultset, self.logError) invalid_timestamp_json = '["2011-05-35T11:30:30"]' self.assertIs(None, range_factory.parseMemo(invalid_timestamp_json)) self.assertEqual(["Invalid datetime value: '2011-05-35T11:30:30'"], self.error_messages)
def test_parseMemo__memo_type_check(self): # parseMemo() accepts only lists containing values that can # be used in sort expression of the given result set. resultset = self.makeStormResultSet() resultset.order_by(Person.datecreated, Person.name, Person.id) range_factory = StormRangeFactory(resultset, self.logError) invalid_memo = [datetime(2011, 7, 25, 11, 30, 30, 45), 'foo', 'bar'] json_data = simplejson.dumps(invalid_memo, cls=DateTimeJSONEncoder) self.assertIs(None, range_factory.parseMemo(json_data)) self.assertEqual(["Invalid parameter: 'bar'"], self.error_messages)
def test_parseMemo__valid_data(self): # If a memo string contains valid data, parseMemo returns this data. resultset = self.makeStormResultSet() resultset.order_by(Person.datecreated, Person.name, Person.id) range_factory = StormRangeFactory(resultset, self.logError) valid_memo = [ datetime(2011, 7, 25, 11, 30, 30, 45, tzinfo=pytz.UTC), 'foo', 1] json_data = simplejson.dumps(valid_memo, cls=DateTimeJSONEncoder) self.assertEqual(valid_memo, range_factory.parseMemo(json_data)) self.assertEqual(0, len(self.error_messages))
def test_getSlice__decorated_resultset(self): resultset = self.makeDecoratedStormResultSet() resultset.order_by(LibraryFileAlias.id) all_results = list(resultset) plain_results = list(resultset.get_plain_result_set()) memo = simplejson.dumps([resultset.get_plain_result_set()[0][1].id]) range_factory = StormRangeFactory(resultset) sliced_result = range_factory.getSlice(3, memo) self.assertEqual(all_results[1:4], list(sliced_result)) self.assertEqual(plain_results[1:4], sliced_result.shadow_values)
def test_getSlice_backward_with_memo(self): resultset = self.makeStormResultSet() resultset.order_by(Person.name, Person.id) all_results = list(resultset) expected = all_results[1:4] expected.reverse() memo = simplejson.dumps([all_results[4].name, all_results[4].id]) range_factory = StormRangeFactory(resultset) sliced_result = range_factory.getSlice(3, memo, forwards=False) self.assertEqual(expected, list(sliced_result))
def test_lessThanOrGreaterThanExpression__desc(self): # beforeOrAfterExpression() returns an expression # (col1, col2,..) < (memo1, memo2...) for descending sort order. resultset = self.makeStormResultSet() range_factory = StormRangeFactory(resultset, self.logError) expressions = [Desc(Person.id), Desc(Person.name)] limits = [1, 'foo'] limit_expression = range_factory.lessThanOrGreaterThanExpression( expressions, limits) self.assertEqual("(Person.id, Person.name) < (1, E'foo')", compile(limit_expression))
def test_StormRangeFactory__empty_real_resultset(self): # StormRangeFactory works with empty regular result sets, product = self.factory.makeProduct() resultset = product.development_focus.searchTasks( BugTaskSet().open_bugtask_search) self.assertEqual(0, resultset.count()) range_factory = StormRangeFactory(resultset) # rough_length is supposed to be zero, but the ANALYZE SELECT # is not always precise. self.assertThat(range_factory.rough_length, LessThan(10)) self.assertEmptyResultSetsWorking(range_factory)
def test_getOrderValuesFor__generic_storm_expression_as_sort_expr(self): # Sorting by a generic Strom expression is not supported. resultset = self.makeStormResultSet() range_factory = StormRangeFactory(resultset) exception = self.assertRaises( StormRangeFactoryError, range_factory.getOrderValuesFor, resultset[0]) self.assertTrue( str(exception).startswith( 'StormRangeFactory only supports sorting by PropertyColumn, ' 'not by <storm.expr.SQL object at'))
def test_parseMemo__nonsensical_iso_timestamp_value(self): # A memo string is rejected when an ISO timespamp is expected # but a nonsensical string is provided. resultset = self.makeStormResultSet() resultset.order_by(Person.datecreated) range_factory = StormRangeFactory(resultset, self.logError) nonsensical_timestamp_json = '["bar"]' self.assertIs(None, range_factory.parseMemo(nonsensical_timestamp_json)) self.assertEqual(["Invalid datetime value: 'bar'"], self.error_messages)
def test_reverseSortOrder(self): # reverseSortOrder() wraps a plain PropertyColumn instance into # Desc(), and it returns the plain PropertyCOlumn for a Desc() # expression. resultset = self.makeStormResultSet() resultset.order_by(Person.id, Desc(Person.name)) range_factory = StormRangeFactory(resultset, self.logError) reverse_person_id, person_name = range_factory.reverseSortOrder() self.assertTrue(isinstance(reverse_person_id, Desc)) self.assertIs(Person.id, reverse_person_id.expr) self.assertIs(Person.name, person_name)