thirdparty/google_appengine/google/appengine/ext/gql/__init__.py
changeset 1278 a7766286a7be
parent 149 f2e327a7c5de
child 2273 e4cb9c53db3e
--- a/thirdparty/google_appengine/google/appengine/ext/gql/__init__.py	Thu Feb 12 10:24:37 2009 +0000
+++ b/thirdparty/google_appengine/google/appengine/ext/gql/__init__.py	Thu Feb 12 12:30:36 2009 +0000
@@ -28,7 +28,6 @@
 
 import calendar
 import datetime
-import heapq
 import logging
 import re
 import time
@@ -38,6 +37,7 @@
 from google.appengine.api import datastore_types
 from google.appengine.api import users
 
+MultiQuery = datastore.MultiQuery
 
 LOG_LEVEL = logging.DEBUG - 1
 
@@ -161,7 +161,7 @@
     \S+
     """, re.VERBOSE | re.IGNORECASE)
 
-  MAX_ALLOWABLE_QUERIES = 30
+  MAX_ALLOWABLE_QUERIES = datastore.MAX_ALLOWABLE_QUERIES
 
   __ANCESTOR = -1
 
@@ -347,37 +347,113 @@
     else:
       return users.User(email=values[0], _auth_domain=self.__auth_domain)
 
+  def __EncodeIfNeeded(self, value):
+    """Simple helper function to create an str from possibly unicode strings.
+    Args:
+      value: input string (should pass as an instance of str or unicode).
+    """
+    if isinstance(value, unicode):
+      return value.encode('utf8')
+    else:
+      return value
+
   def __CastDate(self, values):
-    """Cast date values to DATETIME() class using ISO string or tuple inputs."""
+    """Cast DATE values (year/month/day) from input (to datetime.datetime).
+
+    Casts DATE input values formulated as ISO string or time tuple inputs.
+
+    Args:
+      values: either a single string with ISO time representation or 3
+              integer valued date tuple (year, month, day).
+
+    Returns:
+      datetime.datetime value parsed from the input values.
+    """
+
+    if len(values) == 1:
+      value = self.__EncodeIfNeeded(values[0])
+      if isinstance(value, str):
+        try:
+          time_tuple = time.strptime(value, '%Y-%m-%d')[0:6]
+        except ValueError, err:
+          self.__CastError('DATE', values, err)
+      else:
+        self.__CastError('DATE', values, 'Single input value not a string')
+    elif len(values) == 3:
+      time_tuple = (values[0], values[1], values[2], 0, 0, 0)
+    else:
+      self.__CastError('DATE', values,
+                       'function takes 1 string or 3 integer values')
+
     try:
-      if len(values) == 1 and isinstance(values[0], str):
-        time_tuple = time.strptime(values[0], '%Y-%m-%d')
-        return datetime.datetime(*time_tuple[0:6])
-      else:
-        return datetime.datetime(values[0], values[1], values[2], 0, 0, 0)
+      return datetime.datetime(*time_tuple)
     except ValueError, err:
       self.__CastError('DATE', values, err)
 
   def __CastTime(self, values):
-    """Cast time values to DATETIME() class using ISO string or tuple inputs."""
+    """Cast TIME values (hour/min/sec) from input (to datetime.datetime).
+
+    Casts TIME input values formulated as ISO string or time tuple inputs.
+
+    Args:
+      values: either a single string with ISO time representation or 1-4
+              integer valued time tuple (hour), (hour, minute),
+              (hour, minute, second), (hour, minute, second, microsec).
+
+    Returns:
+      datetime.datetime value parsed from the input values.
+    """
+    if len(values) == 1:
+      value = self.__EncodeIfNeeded(values[0])
+      if isinstance(value, str):
+        try:
+          time_tuple = time.strptime(value, '%H:%M:%S')
+        except ValueError, err:
+          self.__CastError('TIME', values, err)
+        time_tuple = (1970, 1, 1) + time_tuple[3:]
+        time_tuple = time_tuple[0:6]
+      elif isinstance(value, int):
+        time_tuple = (1970, 1, 1, value)
+      else:
+        self.__CastError('TIME', values,
+                         'Single input value not a string or integer hour')
+    elif len(values) <= 4:
+      time_tuple = (1970, 1, 1) + tuple(values)
+    else:
+      self.__CastError('TIME', values, err)
+
     try:
-      if len(values) == 1 and isinstance(values[0], str):
-        time_tuple = time.strptime(values[0], '%H:%M:%S')
-        time_tuple = (1970, 1, 1) + time_tuple[3:]
-        return datetime.datetime(*time_tuple[0:6])
-      else:
-        return datetime.datetime(1970, 1, 1, *values)
+      return datetime.datetime(*time_tuple)
     except ValueError, err:
       self.__CastError('TIME', values, err)
 
   def __CastDatetime(self, values):
-    """Cast values to DATETIME() class using ISO string or tuple inputs."""
+    """Cast DATETIME values (string or tuple) from input (to datetime.datetime).
+
+    Casts DATETIME input values formulated as ISO string or datetime tuple
+    inputs.
+
+    Args:
+      values: either a single string with ISO representation or 3-7
+              integer valued time tuple (year, month, day, ...).
+
+    Returns:
+      datetime.datetime value parsed from the input values.
+    """
+    if len(values) == 1:
+      value = self.__EncodeIfNeeded(values[0])
+      if isinstance(value, str):
+        try:
+          time_tuple = time.strptime(str(value), '%Y-%m-%d %H:%M:%S')[0:6]
+        except ValueError, err:
+          self.__CastError('DATETIME', values, err)
+      else:
+        self.__CastError('DATETIME', values, 'Single input value not a string')
+    else:
+      time_tuple = values
+
     try:
-      if len(values) == 1 and isinstance(values[0], str):
-        time_tuple = time.strptime(values[0], '%Y-%m-%d %H:%M:%S')
-        return datetime.datetime(*time_tuple[0:6])
-      else:
-        return datetime.datetime(*values)
+      return datetime.datetime(*time_tuple)
     except ValueError, err:
       self.__CastError('DATETIME', values, err)
 
@@ -1062,220 +1138,3 @@
 
   def __repr__(self):
     return 'Literal(%s)' % repr(self.__value)
-
-
-class MultiQuery(datastore.Query):
-  """Class representing a GQL query requiring multiple datastore queries.
-
-  This class is actually a subclass of datastore.Query as it is intended to act
-  like a normal Query object (supporting the same interface).
-  """
-
-  def __init__(self, bound_queries, orderings):
-    self.__bound_queries = bound_queries
-    self.__orderings = orderings
-
-  def __str__(self):
-    res = 'MultiQuery: '
-    for query in self.__bound_queries:
-      res = '%s %s' % (res, str(query))
-    return res
-
-  def Get(self, limit, offset=0):
-    """Get results of the query with a limit on the number of results.
-
-    Args:
-      limit: maximum number of values to return.
-      offset: offset requested -- if nonzero, this will override the offset in
-              the original query
-
-    Returns:
-      A list of entities with at most "limit" entries (less if the query
-      completes before reading limit values).
-    """
-    count = 1
-    result = []
-
-    iterator = self.Run()
-
-    try:
-      for i in xrange(offset):
-        val = iterator.next()
-    except StopIteration:
-      pass
-
-    try:
-      while count <= limit:
-        val = iterator.next()
-        result.append(val)
-        count += 1
-    except StopIteration:
-      pass
-    return result
-
-  class SortOrderEntity(object):
-    def __init__(self, entity_iterator, orderings):
-      self.__entity_iterator = entity_iterator
-      self.__entity = None
-      self.__min_max_value_cache = {}
-      try:
-        self.__entity = entity_iterator.next()
-      except StopIteration:
-        pass
-      else:
-        self.__orderings = orderings
-
-    def __str__(self):
-      return str(self.__entity)
-
-    def GetEntity(self):
-      return self.__entity
-
-    def GetNext(self):
-      return MultiQuery.SortOrderEntity(self.__entity_iterator,
-                                        self.__orderings)
-
-    def CmpProperties(self, that):
-      """Compare two entities and return their relative order.
-
-      Compares self to that based on the current sort orderings and the
-      key orders between them. Returns negative, 0, or positive depending on
-      whether self is less, equal to, or greater than that. This
-      comparison returns as if all values were to be placed in ascending order
-      (highest value last).  Only uses the sort orderings to compare (ignores
-       keys).
-
-      Args:
-        self: SortOrderEntity
-        that: SortOrderEntity
-
-      Returns:
-        Negative if self < that
-        Zero if self == that
-        Positive if self > that
-      """
-      if not self.__entity:
-        return cmp(self.__entity, that.__entity)
-
-      for (identifier, order) in self.__orderings:
-        value1 = self.__GetValueForId(self, identifier, order)
-        value2 = self.__GetValueForId(that, identifier, order)
-
-        result = cmp(value1, value2)
-        if order == datastore.Query.DESCENDING:
-          result = -result
-        if result:
-          return result
-      return 0
-
-    def __GetValueForId(self, sort_order_entity, identifier, sort_order):
-      value = sort_order_entity.__entity[identifier]
-      entity_key = sort_order_entity.__entity.key()
-      if self.__min_max_value_cache.has_key((entity_key, identifier)):
-        value = self.__min_max_value_cache[(entity_key, identifier)]
-      elif isinstance(value, list):
-        if sort_order == datastore.Query.DESCENDING:
-          value = min(value)
-        else:
-          value = max(value)
-        self.__min_max_value_cache[(entity_key, identifier)] = value
-
-      return value
-
-    def __cmp__(self, that):
-      """Compare self to that w.r.t. values defined in the sort order.
-
-      Compare an entity with another, using sort-order first, then the key
-      order to break ties. This can be used in a heap to have faster min-value
-      lookup.
-
-      Args:
-        that: other entity to compare to
-      Returns:
-        negative: if self is less than that in sort order
-        zero: if self is equal to that in sort order
-        positive: if self is greater than that in sort order
-      """
-      property_compare = self.CmpProperties(that)
-      if property_compare:
-        return property_compare
-      else:
-        return cmp(self.__entity.key(), that.__entity.key())
-
-  def Run(self):
-    """Return an iterable output with all results in order."""
-    results = []
-    count = 1
-    for bound_query in self.__bound_queries:
-      logging.log(LOG_LEVEL, 'Running query #%i' % count)
-      results.append(bound_query.Run())
-      count += 1
-
-    def IterateResults(results):
-      """Iterator function to return all results in sorted order.
-
-      Iterate over the array of results, yielding the next element, in
-      sorted order. This function is destructive (results will be empty
-      when the operation is complete).
-
-      Args:
-        results: list of result iterators to merge and iterate through
-
-      Yields:
-        The next result in sorted order.
-      """
-      result_heap = []
-      for result in results:
-        heap_value = MultiQuery.SortOrderEntity(result, self.__orderings)
-        if heap_value.GetEntity():
-          heapq.heappush(result_heap, heap_value)
-
-      used_keys = set()
-
-      while result_heap:
-        top_result = heapq.heappop(result_heap)
-
-        results_to_push = []
-        if top_result.GetEntity().key() not in used_keys:
-          yield top_result.GetEntity()
-        else:
-          pass
-
-        used_keys.add(top_result.GetEntity().key())
-
-        results_to_push = []
-        while result_heap:
-          next = heapq.heappop(result_heap)
-          if cmp(top_result, next):
-            results_to_push.append(next)
-            break
-          else:
-            results_to_push.append(next.GetNext())
-        results_to_push.append(top_result.GetNext())
-
-        for popped_result in results_to_push:
-          if popped_result.GetEntity():
-            heapq.heappush(result_heap, popped_result)
-
-    return IterateResults(results)
-
-  def Count(self, limit=None):
-    """Return the number of matched entities for this query.
-
-    Will return the de-duplicated count of results.  Will call the more
-    efficient Get() function if a limit is given.
-
-    Args:
-      limit: maximum number of entries to count (for any result > limit, return
-      limit).
-    Returns:
-      count of the number of entries returned.
-    """
-    if limit is None:
-      count = 0
-      for value in self.Run():
-        count += 1
-      return count
-    else:
-      return len(self.Get(limit))
-