query: Add alias support in _PrepareFieldList
authorIustin Pop <iustin@google.com>
Wed, 19 Jan 2011 09:16:10 +0000 (10:16 +0100)
committerIustin Pop <iustin@google.com>
Thu, 20 Jan 2011 12:05:36 +0000 (13:05 +0100)
Signed-off-by: Iustin Pop <iustin@google.com>
Reviewed-by: RenĂ© Nussbaumer <rn@google.com>

lib/query.py
test/ganeti.query_unittest.py

index 4eba17e..84a8607 100644 (file)
@@ -277,14 +277,18 @@ def _VerifyResultRow(fields, row):
                     (utils.CommaJoin(errors), row))
 
 
-def _PrepareFieldList(fields):
+def _PrepareFieldList(fields, aliases):
   """Prepares field list for use by L{Query}.
 
   Converts the list to a dictionary and does some verification.
 
-  @type fields: list of tuples; (L{objects.QueryFieldDefinition}, data kind,
-    retrieval function)
-  @param fields: List of fields, see L{Query.__init__} for a better description
+  @type fields: list of tuples; (L{objects.QueryFieldDefinition}, data
+      kind, retrieval function)
+  @param fields: List of fields, see L{Query.__init__} for a better
+      description
+  @type aliases: list of tuples; (alias, target)
+  @param aliases: list of tuples containing aliases; for each
+      alias/target pair, a duplicate will be created in the field list
   @rtype: dict
   @return: Field dictionary for L{Query}
 
@@ -308,7 +312,15 @@ def _PrepareFieldList(fields):
 
     result[fdef.name] = field
 
-  assert len(result) == len(fields)
+  for alias, target in aliases:
+    assert alias not in result, "Alias %s overrides an existing field" % alias
+    assert target in result, "Missing target %s for alias %s" % (target, alias)
+    (fdef, k, fn) = result[target]
+    fdef = fdef.Copy()
+    fdef.name = alias
+    result[alias] = (fdef, k, fn)
+
+  assert len(result) == len(fields) + len(aliases)
   assert compat.all(name == fdef.name
                     for (name, (fdef, _, _)) in result.items())
 
@@ -644,7 +656,7 @@ def _BuildNodeFields():
   # Add timestamps
   fields.extend(_GetItemTimestampFields(NQ_CONFIG))
 
-  return _PrepareFieldList(fields)
+  return _PrepareFieldList(fields, [])
 
 
 class InstanceQueryData:
@@ -1119,7 +1131,7 @@ def _BuildInstanceFields():
   fields.extend(_GetInstanceNetworkFields())
   fields.extend(_GetItemTimestampFields(IQ_CONFIG))
 
-  return _PrepareFieldList(fields)
+  return _PrepareFieldList(fields, [])
 
 
 class LockQueryData:
@@ -1175,7 +1187,7 @@ def _BuildLockFields():
      lambda ctx, (name, mode, owners, pending): mode),
     (_MakeField("owner", "Owner", QFT_OTHER), LQ_OWNER, _GetLockOwners),
     (_MakeField("pending", "Pending", QFT_OTHER), LQ_PENDING, _GetLockPending),
-    ])
+    ], [])
 
 
 class GroupQueryData:
@@ -1247,7 +1259,7 @@ def _BuildGroupFields():
 
   fields.extend(_GetItemTimestampFields(GQ_CONFIG))
 
-  return _PrepareFieldList(fields)
+  return _PrepareFieldList(fields, [])
 
 
 #: Fields available for node queries
index 800c821..0472380 100755 (executable)
@@ -74,7 +74,7 @@ class TestQuery(unittest.TestCase):
       [(query._MakeField("disk%s.size" % i, "DiskSize%s" % i,
                          constants.QFT_UNIT),
         DISK, compat.partial(_GetDiskSize, i))
-       for i in range(4)])
+       for i in range(4)], [])
 
     q = query.Query(fielddef, ["name"])
     self.assertEqual(q.RequestedData(), set([STATIC]))
@@ -176,40 +176,40 @@ class TestQuery(unittest.TestCase):
          lambda *args: None),
         (query._MakeField("other", a, constants.QFT_TEXT), None,
          lambda *args: None),
-        ])
+        ], [])
 
     # Non-lowercase names
     self.assertRaises(AssertionError, query._PrepareFieldList, [
       (query._MakeField("NAME", "Name", constants.QFT_TEXT), None,
        lambda *args: None),
-      ])
+      ], [])
     self.assertRaises(AssertionError, query._PrepareFieldList, [
       (query._MakeField("Name", "Name", constants.QFT_TEXT), None,
        lambda *args: None),
-      ])
+      ], [])
 
     # Empty name
     self.assertRaises(AssertionError, query._PrepareFieldList, [
       (query._MakeField("", "Name", constants.QFT_TEXT), None,
        lambda *args: None),
-      ])
+      ], [])
 
     # Empty title
     self.assertRaises(AssertionError, query._PrepareFieldList, [
       (query._MakeField("name", "", constants.QFT_TEXT), None,
        lambda *args: None),
-      ])
+      ], [])
 
     # Whitespace in title
     self.assertRaises(AssertionError, query._PrepareFieldList, [
       (query._MakeField("name", "Co lu mn", constants.QFT_TEXT), None,
        lambda *args: None),
-      ])
+      ], [])
 
     # No callable function
     self.assertRaises(AssertionError, query._PrepareFieldList, [
       (query._MakeField("name", "Name", constants.QFT_TEXT), None, None),
-      ])
+      ], [])
 
   def testUnknown(self):
     fielddef = query._PrepareFieldList([
@@ -221,7 +221,7 @@ class TestQuery(unittest.TestCase):
        None, lambda *args: query._FS_NODATA ),
       (query._MakeField("unavail", "Unavail", constants.QFT_BOOL),
        None, lambda *args: query._FS_UNAVAIL),
-      ])
+      ], [])
 
     for selected in [["foo"], ["Hello", "World"],
                      ["name1", "other", "foo"]]:
@@ -254,6 +254,25 @@ class TestQuery(unittest.TestCase):
                        (constants.QRFS_UNKNOWN, None)]
                       for i in range(1, 10)])
 
+  def testAliases(self):
+    fields = [
+      (query._MakeField("a", "a-title", constants.QFT_TEXT), None,
+       lambda *args: None),
+      (query._MakeField("b", "b-title", constants.QFT_TEXT), None,
+       lambda *args: None),
+      ]
+    # duplicate field
+    self.assertRaises(AssertionError, query._PrepareFieldList, fields,
+                      [("b", "a")])
+    self.assertRaises(AssertionError, query._PrepareFieldList, fields,
+                      [("c", "b"), ("c", "a")])
+    # missing target
+    self.assertRaises(AssertionError, query._PrepareFieldList, fields,
+                      [("c", "d")])
+    fdefs = query._PrepareFieldList(fields, [("c", "b")])
+    self.assertEqual(len(fdefs), 3)
+    self.assertEqual(fdefs["b"][1:], fdefs["c"][1:])
+
 
 class TestGetNodeRole(unittest.TestCase):
   def testMaster(self):