--- 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))
-