def test_indexed_ordering01(self): "FakeOrganisation" self.assertEqual((('name', 'cremeentity_ptr'), ), FakeOrganisation._meta.index_together) self.assertIsNone(get_indexed_ordering(FakeOrganisation, ['phone'])) self.assertEqual(('sector_id', ), get_indexed_ordering(FakeOrganisation, ['sector_id'])) # TODO: ? # self.assertEqual(('sector',), # get_best_ordering(FakeOrganisation, ['sector_id']) # ) self.assertEqual(('name', 'cremeentity_ptr_id'), get_indexed_ordering(FakeOrganisation, ['name'])) # Order is important self.assertEqual(('name', 'cremeentity_ptr_id'), get_indexed_ordering(FakeOrganisation, ['name', 'cremeentity_ptr_id'])) self.assertIsNone( get_indexed_ordering(FakeOrganisation, ['cremeentity_ptr_id', 'name']))
def test_indexed_ordering06(self): "Avoid successive wildcards" with self.assertRaises(ValueError): get_indexed_ordering(FakeContact, ['*', '*', 'cremeentity_ptr_id']) with self.assertRaises(ValueError): get_indexed_ordering(FakeContact, ['last_name', '*', '*', 'cremeentity_ptr_id'])
def test_indexed_ordering03(self): "DESC order => inverted index" expected = ('-name', '-cremeentity_ptr_id') self.assertEqual(expected, get_indexed_ordering(FakeOrganisation, ['-name'])) self.assertEqual( expected, get_indexed_ordering(FakeOrganisation, ['-name', '-cremeentity_ptr_id']))
def test_indexed_ordering05(self): "Blurred query + other model + DESC" self.assertEqual(('name', 'cremeentity_ptr_id'), get_indexed_ordering(FakeOrganisation, ['name', '*'])) self.assertEqual(('-name', '-cremeentity_ptr_id'), get_indexed_ordering(FakeOrganisation, ['-name', '*'])) self.assertEqual( ('-last_name', '-first_name', '-cremeentity_ptr_id'), get_indexed_ordering( FakeContact, ['-last_name', '-first_name', '*', '-cremeentity_ptr_id']))
def test_indexed_ordering04(self): "Blurred query" expected = ('last_name', 'first_name', 'cremeentity_ptr_id') self.assertEqual( expected, get_indexed_ordering(FakeContact, ['last_name', '*', 'cremeentity_ptr_id'])) self.assertEqual( expected, get_indexed_ordering(FakeContact, ['*', 'first_name', 'cremeentity_ptr_id'])) self.assertEqual( expected, get_indexed_ordering(FakeContact, ['last_name', 'first_name', '*'])) self.assertEqual( expected, get_indexed_ordering( FakeContact, ['last_name', 'first_name', '*', 'cremeentity_ptr_id'])) # self.assertEqual(expected, get_indexed_ordering(FakeContact, ['*', 'cremeentity_ptr_id'])) # Ambiguous self.assertEqual( expected, get_indexed_ordering(FakeContact, ['*', 'first_name', '*'])) # self.assertEqual(expected, get_indexed_ordering(FakeContact, ['*', 'cremeentity_ptr_id', '*'])) # Ambiguous self.assertEqual( expected, get_indexed_ordering( FakeContact, ['*', 'first_name', '*', 'cremeentity_ptr_id'])) self.assertIsNone( get_indexed_ordering(FakeContact, ['last_name', '*', 'phone']))
def test_sort_twoorders_05(self): "set_sort(): one natural ordering field not in cells" self.assertEqual(('name', '-expiration_date'), FakeInvoice._meta.ordering ) self.assertIsNone(get_indexed_ordering(FakeInvoice, ['name', '-expiration_date'])) field_name1 = 'name' build_cell = partial(EntityCellRegularField.build, model=FakeInvoice) cells = [build_cell(name='number'), build_cell(name=field_name1), # Not expiration_date ] lvs = ListViewState() ordering = lvs.set_sort(model=FakeInvoice, cells=cells, cell_key=None, order=None) self.assertEqual((field_name1, 'cremeentity_ptr_id'), ordering) key = cells[1].key # First natural order self.assertEqual(key, lvs.sort_field) self.assertEqual('', lvs.sort_order)
def test_regularfield_default_twoorders_05(self): "One natural ordering field not in cells." sorter = QuerySorter() self.assertEqual(('name', '-expiration_date'), FakeInvoice._meta.ordering) self.assertIsNone( get_indexed_ordering(FakeInvoice, ['name', '-expiration_date'])) field_name1 = 'name' build_cell = partial(EntityCellRegularField.build, model=FakeInvoice) cells = [ build_cell(name='number'), build_cell(name=field_name1), # Not expiration_date ] sortinfo = sorter.get(model=FakeInvoice, cells=cells, cell_key=None) self.assertEqual((field_name1, 'cremeentity_ptr_id'), sortinfo.field_names) self.assertEqual(cells[1].key, sortinfo.main_cell_key) # First natural order self.assertTrue(sortinfo.main_order.asc)
def test_indexed_ordering02(self): "FakeContact" self.assertEqual((('last_name', 'first_name', 'cremeentity_ptr'), ), FakeContact._meta.index_together) self.assertIsNone(get_indexed_ordering(FakeContact, ['phone'])) self.assertIsNone(get_indexed_ordering(FakeContact, ['phone', 'email'])) expected = ('last_name', 'first_name', 'cremeentity_ptr_id') self.assertEqual(expected, get_indexed_ordering(FakeContact, ['last_name'])) self.assertEqual( expected, get_indexed_ordering(FakeContact, ['last_name', 'first_name'])) self.assertEqual( expected, get_indexed_ordering( FakeContact, ['last_name', 'first_name', 'cremeentity_ptr_id'])) self.assertIsNone( get_indexed_ordering(FakeContact, ['first_name', 'last_name']))
def get(self, model, cells, cell_key, order=None, fast_mode=False): """Get a QuerySortInfo instance for a model & a main ordering cell, using the natural ordering of this model & the DB-indices. @param model: CremeEntity subclass. @param: cells: Sequence of displayed EntityCells (eg: columns of the list-view) ; If the natural ordering fields of the model are not present within the cells, they are not used in the result (excepted if it allows to use a DB-index). @param: cell_key: Key of the main (ie: first) ordering cell (string). @param order: <creme_core.utils.meta.Order> instance (or None, meaning "ASC order"). @param fast_mode: Boolean ; <True> means "There are lots of entities, use a faster/simpler ordering". @return: A QuerySortInfo instance. """ if order is None: order = Order() cells_dict = {c.key: c for c in cells} build_cell = partial(EntityCellRegularField.build, model=model) ordering = [ ofield_str for ofield_str in model._meta.ordering if build_cell( name=OrderedField(ofield_str).field_name).key in cells_dict ] # Name of the main model-field used to perform the "ORDER BY" instruction. sort_field = self._get_field_name(cells_dict, cell_key) if sort_field: for ordered_field_str in (sort_field, '-' + sort_field): if ordered_field_str in ordering: ordering.remove(ordered_field_str) ordering.insert(0, sort_field) if order.desc: ordering = [ str(OrderedField(o).reversed()) for o in ordering ] break else: ordering.insert(0, order.prefix + sort_field) else: cell_key, order = self._default_key_n_order(model, ordering) sort_info = QuerySortInfo(cell_key=cell_key, order=order) if sort_field and self._is_field_unique(model, sort_field): ind_ordering = get_indexed_ordering(model, [*ordering, '*']) if ind_ordering is not None: sort_info.field_names = ind_ordering elif fast_mode: o_sort_field = order.prefix + sort_field ind_ordering = get_indexed_ordering(model, [o_sort_field, '*']) sort_info.field_names = ( o_sort_field, ) if ind_ordering is None else ind_ordering else: sort_info.field_names = tuple(ordering) else: # NB: we order by ID (like 'cremeentity_ptr_id' in entity sub-classes) # in order to be sure that successive queries give consistent contents # (if you order by 'name' & there are some duplicated names, # the order by directive can be respected, but the order of the # duplicates in the queries results be different -- so the # paginated contents are not consistent). last_field = order.prefix + self._get_local_id_field(model).attname if ordering: ind_ordering = get_indexed_ordering( model, [*ordering, '*', last_field]) if ind_ordering is not None: sort_info.field_names = ind_ordering elif fast_mode: first_order = ordering[0] ind_ordering = get_indexed_ordering( model, [first_order, '*', last_field]) sort_info.field_names = ( first_order, last_field) if ind_ordering is None else ind_ordering else: sort_info.field_names = (*ordering, last_field) else: sort_info.field_names = (last_field, ) return sort_info