equal
deleted
inserted
replaced
75 - reserved words are case insensitive |
75 - reserved words are case insensitive |
76 - names are case sensitive |
76 - names are case sensitive |
77 |
77 |
78 The syntax for SELECT is fairly straightforward: |
78 The syntax for SELECT is fairly straightforward: |
79 |
79 |
80 SELECT * FROM <entity> |
80 SELECT [* | __key__ ] FROM <entity> |
81 [WHERE <condition> [AND <condition> ...]] |
81 [WHERE <condition> [AND <condition> ...]] |
82 [ORDER BY <property> [ASC | DESC] [, <property> [ASC | DESC] ...]] |
82 [ORDER BY <property> [ASC | DESC] [, <property> [ASC | DESC] ...]] |
83 [LIMIT [<offset>,]<count>] |
83 [LIMIT [<offset>,]<count>] |
84 [OFFSET <offset>] |
84 [OFFSET <offset>] |
85 [HINT (ORDER_FIRST | HINT FILTER_FIRST | HINT ANCESTOR_FIRST)] |
85 [HINT (ORDER_FIRST | HINT FILTER_FIRST | HINT ANCESTOR_FIRST)] |
142 - Literals can take the form of basic types or as type-cast literals. On |
142 - Literals can take the form of basic types or as type-cast literals. On |
143 the other hand, literals within lists can currently only take the form of |
143 the other hand, literals within lists can currently only take the form of |
144 simple types (strings, integers, floats). |
144 simple types (strings, integers, floats). |
145 |
145 |
146 |
146 |
147 SELECT * will return an iterable set of entries, but other operations (schema |
147 SELECT * will return an iterable set of entities; SELECT __key__ will return |
148 queries, updates, inserts or field selections) will return alternative |
148 an iterable set of Keys. |
149 result types. |
|
150 """ |
149 """ |
151 |
150 |
152 TOKENIZE_REGEX = re.compile(r""" |
151 TOKENIZE_REGEX = re.compile(r""" |
153 (?:'[^'\n\r]*')+| |
152 (?:'[^'\n\r]*')+| |
154 <=|>=|!=|=|<|>| |
153 <=|>=|!=|=|<|>| |
227 query_count = len(enumerated_queries) |
226 query_count = len(enumerated_queries) |
228 else: |
227 else: |
229 query_count = 1 |
228 query_count = 1 |
230 |
229 |
231 for i in xrange(query_count): |
230 for i in xrange(query_count): |
232 queries.append(datastore.Query(self._entity, _app=self.__app)) |
231 queries.append(datastore.Query(self._entity, _app=self.__app, |
|
232 keys_only=self._keys_only)) |
233 |
233 |
234 logging.log(LOG_LEVEL, |
234 logging.log(LOG_LEVEL, |
235 'Binding with %i positional args %s and %i keywords %s' |
235 'Binding with %i positional args %s and %i keywords %s' |
236 , len(args), args, len(keyword_args), keyword_args) |
236 , len(args), args, len(keyword_args), keyword_args) |
237 for ((identifier, condition), value_list) in self.__filters.iteritems(): |
237 for ((identifier, condition), value_list) in self.__filters.iteritems(): |
550 enumerated_queries: in/out list of already bound queries -> expanded list |
550 enumerated_queries: in/out list of already bound queries -> expanded list |
551 with the full enumeration required to satisfy the condition query |
551 with the full enumeration required to satisfy the condition query |
552 Raises: |
552 Raises: |
553 BadArgumentError if the filter is invalid (namely non-list with IN) |
553 BadArgumentError if the filter is invalid (namely non-list with IN) |
554 """ |
554 """ |
|
555 if condition.lower() in ('!=', 'in') and self._keys_only: |
|
556 raise datastore_errors.BadQueryError( |
|
557 'Keys only queries do not support IN or != filters.') |
555 |
558 |
556 def CloneQueries(queries, n): |
559 def CloneQueries(queries, n): |
557 """Do a full copy of the queries and append to the end of the queries. |
560 """Do a full copy of the queries and append to the end of the queries. |
558 |
561 |
559 Does an in-place replication of the input list and sorts the result to |
562 Does an in-place replication of the input list and sorts the result to |
673 """Return the result ordering list.""" |
676 """Return the result ordering list.""" |
674 return self.__orderings |
677 return self.__orderings |
675 |
678 |
676 __iter__ = Run |
679 __iter__ = Run |
677 |
680 |
|
681 __result_type_regex = re.compile(r'(\*|__key__)') |
678 __quoted_string_regex = re.compile(r'((?:\'[^\'\n\r]*\')+)') |
682 __quoted_string_regex = re.compile(r'((?:\'[^\'\n\r]*\')+)') |
679 __ordinal_regex = re.compile(r':(\d+)$') |
683 __ordinal_regex = re.compile(r':(\d+)$') |
680 __named_regex = re.compile(r':(\w+)$') |
684 __named_regex = re.compile(r':(\w+)$') |
681 __identifier_regex = re.compile(r'(\w+)$') |
685 __identifier_regex = re.compile(r'(\w+)$') |
682 __conditions_regex = re.compile(r'(<=|>=|!=|=|<|>|is|in)$', re.IGNORECASE) |
686 __conditions_regex = re.compile(r'(<=|>=|!=|=|<|>|is|in)$', re.IGNORECASE) |
781 |
785 |
782 Returns: |
786 Returns: |
783 True if parsing completed okay. |
787 True if parsing completed okay. |
784 """ |
788 """ |
785 self.__Expect('SELECT') |
789 self.__Expect('SELECT') |
786 self.__Expect('*') |
790 result_type = self.__AcceptRegex(self.__result_type_regex) |
|
791 self._keys_only = (result_type == '__key__') |
787 return self.__From() |
792 return self.__From() |
788 |
793 |
789 def __From(self): |
794 def __From(self): |
790 """Consume the FROM clause. |
795 """Consume the FROM clause. |
791 |
796 |