Revision fbc263a9
b/lib/cmdlib.py | ||
---|---|---|
464 | 464 |
self.requested_data = self.query.RequestedData() |
465 | 465 |
self.names = self.query.RequestedNames() |
466 | 466 |
|
467 |
# Sort only if no names were requested |
|
468 |
self.sort_by_name = not self.names |
|
469 |
|
|
467 | 470 |
self.do_locking = None |
468 | 471 |
self.wanted = None |
469 | 472 |
|
... | ... | |
530 | 533 |
"""Collect data and execute query. |
531 | 534 |
|
532 | 535 |
""" |
533 |
return query.GetQueryResponse(self.query, self._GetQueryData(lu)) |
|
536 |
return query.GetQueryResponse(self.query, self._GetQueryData(lu), |
|
537 |
sort_by_name=self.sort_by_name) |
|
534 | 538 |
|
535 | 539 |
def OldStyleQuery(self, lu): |
536 | 540 |
"""Collect data and execute query. |
537 | 541 |
|
538 | 542 |
""" |
539 |
return self.query.OldStyleQuery(self._GetQueryData(lu)) |
|
543 |
return self.query.OldStyleQuery(self._GetQueryData(lu), |
|
544 |
sort_by_name=self.sort_by_name) |
|
540 | 545 |
|
541 | 546 |
|
542 | 547 |
def _GetWantedNodes(lu, nodes): |
b/lib/query.py | ||
---|---|---|
629 | 629 |
""" |
630 | 630 |
return GetAllFields(self._fields) |
631 | 631 |
|
632 |
def Query(self, ctx): |
|
632 |
def Query(self, ctx, sort_by_name=True):
|
|
633 | 633 |
"""Execute a query. |
634 | 634 |
|
635 | 635 |
@param ctx: Data container passed to field retrieval functions, must |
636 | 636 |
support iteration using C{__iter__} |
637 |
@type sort_by_name: boolean |
|
638 |
@param sort_by_name: Whether to sort by name or keep the input data's |
|
639 |
ordering |
|
637 | 640 |
|
638 | 641 |
""" |
642 |
sort = (self._name_fn and sort_by_name) |
|
643 |
|
|
639 | 644 |
result = [] |
640 | 645 |
|
641 | 646 |
for idx, item in enumerate(ctx): |
... | ... | |
648 | 653 |
if __debug__: |
649 | 654 |
_VerifyResultRow(self._fields, row) |
650 | 655 |
|
651 |
if self._name_fn:
|
|
656 |
if sort:
|
|
652 | 657 |
(status, name) = _ProcessResult(self._name_fn(ctx, item)) |
653 | 658 |
assert status == constants.RS_NORMAL |
654 | 659 |
# TODO: Are there cases where we wouldn't want to use NiceSort? |
655 |
sortname = utils.NiceSortKey(name)
|
|
660 |
result.append((utils.NiceSortKey(name), idx, row))
|
|
656 | 661 |
else: |
657 |
sortname = None
|
|
662 |
result.append(row)
|
|
658 | 663 |
|
659 |
result.append((sortname, idx, row)) |
|
664 |
if not sort: |
|
665 |
return result |
|
660 | 666 |
|
661 | 667 |
# TODO: Would "heapq" be more efficient than sorting? |
662 | 668 |
|
... | ... | |
667 | 673 |
|
668 | 674 |
return map(operator.itemgetter(2), result) |
669 | 675 |
|
670 |
def OldStyleQuery(self, ctx): |
|
676 |
def OldStyleQuery(self, ctx, sort_by_name=True):
|
|
671 | 677 |
"""Query with "old" query result format. |
672 | 678 |
|
673 | 679 |
See L{Query.Query} for arguments. |
... | ... | |
681 | 687 |
errors.ECODE_INVAL) |
682 | 688 |
|
683 | 689 |
return [[value for (_, value) in row] |
684 |
for row in self.Query(ctx)] |
|
690 |
for row in self.Query(ctx, sort_by_name=sort_by_name)]
|
|
685 | 691 |
|
686 | 692 |
|
687 | 693 |
def _ProcessResult(value): |
... | ... | |
776 | 782 |
return result |
777 | 783 |
|
778 | 784 |
|
779 |
def GetQueryResponse(query, ctx): |
|
785 |
def GetQueryResponse(query, ctx, sort_by_name=True):
|
|
780 | 786 |
"""Prepares the response for a query. |
781 | 787 |
|
782 | 788 |
@type query: L{Query} |
783 | 789 |
@param ctx: Data container, see L{Query.Query} |
790 |
@type sort_by_name: boolean |
|
791 |
@param sort_by_name: Whether to sort by name or keep the input data's |
|
792 |
ordering |
|
784 | 793 |
|
785 | 794 |
""" |
786 |
return objects.QueryResponse(data=query.Query(ctx), |
|
795 |
return objects.QueryResponse(data=query.Query(ctx, sort_by_name=sort_by_name),
|
|
787 | 796 |
fields=query.GetFields()).ToDict() |
788 | 797 |
|
789 | 798 |
|
b/test/ganeti.query_unittest.py | ||
---|---|---|
1118 | 1118 |
["node1", "node44"], |
1119 | 1119 |
]) |
1120 | 1120 |
|
1121 |
# Name field, but no sorting, result must be in incoming order |
|
1122 |
q = query.Query(fielddefs, ["pnode", "snode"], namefield="pnode") |
|
1123 |
self.assertFalse(q.RequestedData()) |
|
1124 |
self.assertEqual(q.Query(data, sort_by_name=False), |
|
1125 |
[[(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, "node44")], |
|
1126 |
[(constants.RS_NORMAL, "node30"), (constants.RS_NORMAL, "node90")], |
|
1127 |
[(constants.RS_NORMAL, "node25"), (constants.RS_NORMAL, "node1")], |
|
1128 |
[(constants.RS_NORMAL, "node20"), (constants.RS_NORMAL, "node1")]]) |
|
1129 |
self.assertEqual(q.OldStyleQuery(data, sort_by_name=False), [ |
|
1130 |
["node1", "node44"], |
|
1131 |
["node30", "node90"], |
|
1132 |
["node25", "node1"], |
|
1133 |
["node20", "node1"], |
|
1134 |
]) |
|
1135 |
self.assertEqual(q.Query(reversed(data), sort_by_name=False), |
|
1136 |
[[(constants.RS_NORMAL, "node20"), (constants.RS_NORMAL, "node1")], |
|
1137 |
[(constants.RS_NORMAL, "node25"), (constants.RS_NORMAL, "node1")], |
|
1138 |
[(constants.RS_NORMAL, "node30"), (constants.RS_NORMAL, "node90")], |
|
1139 |
[(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, "node44")]]) |
|
1140 |
self.assertEqual(q.OldStyleQuery(reversed(data), sort_by_name=False), [ |
|
1141 |
["node20", "node1"], |
|
1142 |
["node25", "node1"], |
|
1143 |
["node30", "node90"], |
|
1144 |
["node1", "node44"], |
|
1145 |
]) |
|
1146 |
|
|
1147 |
def testEqualNamesOrder(self): |
|
1148 |
fielddefs = query._PrepareFieldList([ |
|
1149 |
(query._MakeField("pnode", "PNode", constants.QFT_TEXT, "Primary"), |
|
1150 |
None, 0, lambda ctx, item: item["pnode"]), |
|
1151 |
(query._MakeField("num", "Num", constants.QFT_NUMBER, "Num"), |
|
1152 |
None, 0, lambda ctx, item: item["num"]), |
|
1153 |
], []) |
|
1154 |
|
|
1155 |
data = [ |
|
1156 |
{ "pnode": "node1", "num": 100, }, |
|
1157 |
{ "pnode": "node1", "num": 25, }, |
|
1158 |
{ "pnode": "node2", "num": 90, }, |
|
1159 |
{ "pnode": "node2", "num": 30, }, |
|
1160 |
] |
|
1161 |
|
|
1162 |
q = query.Query(fielddefs, ["pnode", "num"], namefield="pnode", |
|
1163 |
filter_=["|", ["=", "pnode", "node1"], |
|
1164 |
["=", "pnode", "node2"], |
|
1165 |
["=", "pnode", "node1"]]) |
|
1166 |
self.assertEqual(q.RequestedNames(), ["node1", "node2"], |
|
1167 |
msg="Did not return unique names") |
|
1168 |
self.assertFalse(q.RequestedData()) |
|
1169 |
self.assertEqual(q.Query(data), |
|
1170 |
[[(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, 100)], |
|
1171 |
[(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, 25)], |
|
1172 |
[(constants.RS_NORMAL, "node2"), (constants.RS_NORMAL, 90)], |
|
1173 |
[(constants.RS_NORMAL, "node2"), (constants.RS_NORMAL, 30)]]) |
|
1174 |
self.assertEqual(q.Query(data, sort_by_name=False), |
|
1175 |
[[(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, 100)], |
|
1176 |
[(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, 25)], |
|
1177 |
[(constants.RS_NORMAL, "node2"), (constants.RS_NORMAL, 90)], |
|
1178 |
[(constants.RS_NORMAL, "node2"), (constants.RS_NORMAL, 30)]]) |
|
1179 |
|
|
1180 |
data = [ |
|
1181 |
{ "pnode": "nodeX", "num": 50, }, |
|
1182 |
{ "pnode": "nodeY", "num": 40, }, |
|
1183 |
{ "pnode": "nodeX", "num": 30, }, |
|
1184 |
{ "pnode": "nodeX", "num": 20, }, |
|
1185 |
{ "pnode": "nodeM", "num": 10, }, |
|
1186 |
] |
|
1187 |
|
|
1188 |
q = query.Query(fielddefs, ["pnode", "num"], namefield="pnode", |
|
1189 |
filter_=["|", ["=", "pnode", "nodeX"], |
|
1190 |
["=", "pnode", "nodeY"], |
|
1191 |
["=", "pnode", "nodeY"], |
|
1192 |
["=", "pnode", "nodeY"], |
|
1193 |
["=", "pnode", "nodeM"]]) |
|
1194 |
self.assertEqual(q.RequestedNames(), ["nodeX", "nodeY", "nodeM"], |
|
1195 |
msg="Did not return unique names") |
|
1196 |
self.assertFalse(q.RequestedData()) |
|
1197 |
|
|
1198 |
# First sorted by name, then input order |
|
1199 |
self.assertEqual(q.Query(data, sort_by_name=True), |
|
1200 |
[[(constants.RS_NORMAL, "nodeM"), (constants.RS_NORMAL, 10)], |
|
1201 |
[(constants.RS_NORMAL, "nodeX"), (constants.RS_NORMAL, 50)], |
|
1202 |
[(constants.RS_NORMAL, "nodeX"), (constants.RS_NORMAL, 30)], |
|
1203 |
[(constants.RS_NORMAL, "nodeX"), (constants.RS_NORMAL, 20)], |
|
1204 |
[(constants.RS_NORMAL, "nodeY"), (constants.RS_NORMAL, 40)]]) |
|
1205 |
|
|
1206 |
# Input order |
|
1207 |
self.assertEqual(q.Query(data, sort_by_name=False), |
|
1208 |
[[(constants.RS_NORMAL, "nodeX"), (constants.RS_NORMAL, 50)], |
|
1209 |
[(constants.RS_NORMAL, "nodeY"), (constants.RS_NORMAL, 40)], |
|
1210 |
[(constants.RS_NORMAL, "nodeX"), (constants.RS_NORMAL, 30)], |
|
1211 |
[(constants.RS_NORMAL, "nodeX"), (constants.RS_NORMAL, 20)], |
|
1212 |
[(constants.RS_NORMAL, "nodeM"), (constants.RS_NORMAL, 10)]]) |
|
1213 |
|
|
1121 | 1214 |
def testFilter(self): |
1122 | 1215 |
(DK_A, DK_B) = range(1000, 1002) |
1123 | 1216 |
|
Also available in: Unified diff