def __CastKey(self, values): """Cast input values to Key() class using encoded string or tuple list.""" if not len(values) % 2: return datastore_types.Key.from_path(_app=self.__app, *values) elif len(values) == 1 and isinstance(values[0], basestring): return datastore_types.Key(values[0]) else: self.__CastError('KEY', values, 'requires an even number of operands ' 'or a single encoded string')
def GetOrInsert(key, kindName=None, parent=None, **kwargs): """ Either creates a new entity with the given key, or returns the existing one. Its guaranteed that there is no race-condition here; it will never overwrite an previously created entity. Extra keyword arguments passed to this function will be used to populate the entity if it has to be created; otherwise they are ignored. :param key: The key which will be fetched or created. \ If key is a string, it will be used as the name for the new entity, therefore the \ collectionName is required in this case. :type key: server.db.Key | String :param kindName: The data kind to use for that entity. Ignored if key is a db.Key. :type kindName: str :param parent: The parent entity of the entity. :type parent: db.Key or None :returns: Returns the wanted Entity. :rtype: server.db.Entity """ def txn(key, kwargs): try: res = datastore.Get(key) except datastore_errors.EntityNotFoundError: res = Entity(kind=key.kind(), parent=key.parent(), name=key.name(), id=key.id()) for k, v in kwargs.items(): res[k] = v datastore.Put(res) return (res) if not isinstance(key, datastore_types.Key): try: key = datastore_types.Key(encoded=key) except: assert kindName key = datastore_types.Key.from_path(kindName, key, parent=parent) if datastore.IsInTransaction(): return txn(key, kwargs) return datastore.RunInTransaction(txn, key, kwargs)
def decodeStringKey(value): # first try to decode the whole string as one key try: key = datastore_types.Key(value) return encode(key) except BadKeyError as e: # check for the case of two keys split by a '_' if re.search('^' + key_regex + '_' + key_regex + '$', value): keys = value.split('_ah') return encode(keys[0]) + '_' + encode('ah' + keys[1]) # check for the case of one key and one string split by a '_' if re.search('^' + key_regex + '_[^\s]+$', value): strings = value.split('_') # one key and one string if len(strings) == 2: return encode(strings[0]) + '_' + encode(strings[1]) # one key (which includes a '_') and one string elif len(strings) == 3: return encode('_'.join(strings[0:2])) + '_' + encode( strings[2]) raise Exception('bad key string: ' + str(value), e)
def mergeExternalFilter(self, filters): """ Safely merges filters according to the data model. Its only valid to call this function if the query has been created using :func:`server.skeleton.Skeleton.all`. Its safe to pass filters received from an external source (a user); unknown/invalid filters will be ignored, so the query-object is kept in a valid state even when processing malformed data. If complex queries are needed (e.g. filter by relations), this function shall also be used. See also :func:`server.db.Query.filter` for simple filters. :param filters: A dictionary of attributes and filter pairs. :type filters: dict :returns: Returns the query itself for chaining. :rtype: server.db.Query """ from server.bones import baseBone, relationalBone if "id" in filters: self.datastoreQuery = None logging.error( "Filtering by id is no longer supported. Use key instead.") return self if self.srcSkel is None: raise NotImplementedError( "This query has not been created using skel.all()") if self.datastoreQuery is None: #This query is allready unsatifiable and adding more constrains to this wont change this return (self) skel = self.srcSkel if skel.searchIndex and "search" in filters: #We perform a Search via Google API - all other parameters are ignored try: searchRes = search.Index(name=skel.searchIndex).search( query=search.Query(query_string=filters["search"], options=search.QueryOptions(limit=25))) except search.QueryError: #We cant parse the query, treat it as verbatim qstr = u"\"%s\"" % filters["search"].replace(u"\"", u"") try: searchRes = search.Index(name=skel.searchIndex).search( query=search.Query(query_string=qstr, options=search.QueryOptions( limit=25))) except search.QueryError: # Still cant parse it searchRes = [] tmpRes = [ datastore_types.Key(encoded=x.doc_id[2:]) for x in searchRes ] if tmpRes: filters = [] for x in tmpRes: filters.append( datastore.Query( self.getKind(), {"%s =" % datastore_types.KEY_SPECIAL_PROPERTY: x })) self.datastoreQuery = datastore.MultiQuery(filters, ()) else: self.datastoreQuery = None return (self) #bones = [ (getattr( skel, key ), key) for key in dir( skel ) if not "__" in key and isinstance( getattr( skel, key ) , baseBone ) ] bones = [(y, x) for x, y in skel.items()] try: #First, filter non-relational bones for bone, key in [ x for x in bones if not isinstance(x[0], relationalBone) ]: bone.buildDBFilter(key, skel, self, filters) #Second, process orderings of non-relational bones for bone, key in [ x for x in bones if not isinstance(x[0], relationalBone) ]: bone.buildDBSort(key, skel, self, filters) #Now filter relational bones for bone, key in [ x for x in bones if isinstance(x[0], relationalBone) ]: bone.buildDBFilter(key, skel, self, filters) #finally process orderings of relational bones for bone, key in [ x for x in bones if isinstance(x[0], relationalBone) ]: bone.buildDBSort(key, skel, self, filters) except RuntimeError as e: logging.exception(e) self.datastoreQuery = None return (self) if "search" in filters and filters["search"]: if isinstance(filters["search"], list): taglist = [ "".join([ y for y in unicode(x).lower() if y in conf["viur.searchValidChars"] ]) for x in filters["search"] ] else: taglist = [ "".join([ y for y in unicode(x).lower() if y in conf["viur.searchValidChars"] ]) for x in unicode(filters["search"]).split(" ") ] assert not isinstance( self.datastoreQuery, datastore.MultiQuery ), "Searching using viur-tags is not possible on a query that already uses an IN-filter!" origFilter = self.datastoreQuery queries = [] for tag in taglist[:30]: #Limit to max 30 keywords q = datastore.Query(kind=origFilter.__kind) q["viur_tags"] = tag queries.append(q) self.datastoreQuery = datastore.MultiQuery(queries, origFilter.__orderings) for k, v in origFilter.items(): self.datastoreQuery[k] = v if "cursor" in filters and filters[ "cursor"] and filters["cursor"].lower() != "none": self.cursor(filters["cursor"]) if "amount" in filters and str(filters["amount"]).isdigit() and int( filters["amount"]) > 0 and int(filters["amount"]) <= 100: self.limit(int(filters["amount"])) if "postProcessSearchFilter" in dir(skel): skel.postProcessSearchFilter(self, filters) return (self)
def parse(self, value): return datastore_types.Key(value)
def to_old_key(self): return datastore_types.Key(encoded=self.urlsafe())