def _command(self,
                 sock_info,
                 command,
                 slave_ok=False,
                 value=1,
                 check=True,
                 allowable_errors=None,
                 read_preference=ReadPreference.PRIMARY,
                 codec_options=DEFAULT_CODEC_OPTIONS,
                 write_concern=None,
                 parse_write_concern_error=False,
                 **kwargs):
        """Internal command helper."""
        if isinstance(command, string_type):
            command = SON([(command, value)])

        if sock_info.max_wire_version >= 5 and write_concern:
            command['writeConcern'] = write_concern.document

        command.update(kwargs)

        return sock_info.command(
            self.__name,
            command,
            slave_ok,
            read_preference,
            codec_options,
            check,
            allowable_errors,
            parse_write_concern_error=parse_write_concern_error)
Exemple #2
0
def _gen_find_command(coll, spec, projection, skip, limit, batch_size,
                      options):
    """Generate a find command document."""
    cmd = SON([('find', coll)])
    if '$query' in spec:
        cmd.update([(_MODIFIERS[key], val) for key, val in spec.items()])
    else:
        cmd['filter'] = spec

    if projection:
        cmd['projection'] = projection
    if skip:
        cmd['skip'] = skip
    if limit:
        cmd['limit'] = limit
    if batch_size:
        cmd['batchSize'] = batch_size
    # XXX: Should the check for 1 be here?
    if limit < 0 or limit == 1:
        cmd['singleBatch'] = True

    if options:
        cmd.update([(opt, True) for opt, val in _OPTIONS.items()
                    if options & val])
    return cmd
Exemple #3
0
    def compact_versions(
        self,
        start_version: int,
        end_version: int,
        destroy_proofs: Optional[bool] = None,
    ) -> CompactResponse:
        """Compacts all proofs, versions and documents in the db between two given versions,
        deleting all data that only exists between the two versions.
        See https://provendb.readme.io/docs/compact

        :param start_version: The first version to compact from.
        :type start_version: int
        :param end_version: The last version to compact to.
        :type end_version: int
        :raises CompactException: pyproven exception when ProvenDB fails to compact between the two given versions.
        :return: A dict-like object containing the number of deleted proofs, versions and documents.
        :rtype: CompactResponse
        """
        command_args = SON({"startVersion": start_version, "endVersion": end_version})
        if destroy_proofs:
            command_args.update({"destroyProofs": destroy_proofs})
        try:
            response = self.db.command("compact", command_args)
            return CompactResponse(response)
        except PyMongoError as err:
            error_msg = extract_error_info(err)["errmsg"]
            if (
                error_msg
                == "There must be a full proof above the range to be compacted"
            ):
                raise CompactProofError(err)
            else:
                raise
    def create_index(self, sort_fields, **kwargs):
        def wrapper(result, name):
            return name

        if not isinstance(sort_fields, qf.sort):
            raise TypeError("sort_fields must be an instance of filter.sort")

        if "name" not in kwargs:
            name = self._gen_index_name(sort_fields["orderby"])
        else:
            name = kwargs.pop("name")

        key = SON()
        for k, v in sort_fields["orderby"]:
            key.update({k: v})

        index = SON(dict(ns=str(self), name=name, key=key))

        if "drop_dups" in kwargs:
            kwargs["dropDups"] = kwargs.pop("drop_dups")

        if "bucket_size" in kwargs:
            kwargs["bucketSize"] = kwargs.pop("bucket_size")

        index.update(kwargs)
        d = self._database.system.indexes.insert(index, safe=True)
        d.addCallback(wrapper, name)
        return d
Exemple #5
0
    def find_and_modify(self, spec, document, upsert=False, manipulate=False,
                        safe=True, multi=False, callback=None, **kwargs):

        if self._key_ in spec:
            spec[MONGODB_ID] = spec[self._key_]
            del spec[self._key_]
        # add conditions delete_flag is not 1
        spec[DELETE_FLAG] = {'$ne': '1'}
        old_update_data = document.get("$set", None)
        if old_update_data:
            old_update_data["last_modify"] = int(time.time())
            document['$set'] = old_update_data

        from bson.son import SON

        command = SON(
            [('findAndModify', self._table_), ('query', spec), ('update', document), ('upsert', False), ('new', True)])

        command.update(kwargs)

        result = yield tornado.gen.Task(self.async_client.connection("$cmd", self._db_).find_one, command,
                                        _must_use_master=True, _is_command=True)

        flag = result[0][0]['value']
        if flag and self.need_sync:
            self.sync_update_data(spec, document)

        callback(flag)
    def find_and_modify(self, query={}, update=None, upsert=False, **kwargs):
        def wrapper(result):
            no_obj_error = "No matching object found"
            if not result['ok']:
                if result["errmsg"] == no_obj_error:
                    return None
                else:
                    raise ValueError("Unexpected Error: %s" % (result, ))
            return result.get('value')

        if (not update and not kwargs.get('remove', None)):
            raise ValueError("Must either update or remove")

        if (update and kwargs.get('remove', None)):
            raise ValueError("Can't do both update and remove")

        cmd = SON([("findAndModify", self._collection_name)])
        cmd.update(kwargs)
        # No need to include empty args
        if query:
            cmd['query'] = query
        if update:
            cmd['update'] = update
        if upsert:
            cmd['upsert'] = upsert

        d = self._database["$cmd"].find_one(cmd)
        d.addCallback(wrapper)

        return d
Exemple #7
0
def __last_error(namespace, args):
    """Data to send to do a lastError.
    """
    cmd = SON([("getlasterror", 1)])
    cmd.update(args)
    splitns = namespace.split(".", 1)
    return query(0, splitns[0] + ".$cmd", 0, -1, cmd, None, DEFAULT_CODEC_OPTIONS)
def main():
    persistence = mpl.MongoPersistenceLayer()

    current_epoch = long(time.mktime(time.gmtime()))
    users = persistence.find_records('user', {'access_token': {"$exists": True}, 'access_token_expires': {"$gt": current_epoch}}, 
                                     {'_id':1, 'access_token':1, 'uname':1, 'friends':1})
    
    for user in users:

        client_longitude = -122.063796997
        client_latitude = 37.2538986206 

        friend_ids = user['friends']
        uid = user['_id']
        me_friend_ids = [user['_id']] + friend_ids

        logger.debug("uid: %s", uid)
        logger.debug("num of associated users: %s", len(me_friend_ids))
        logger.debug("associated users: %s", me_friend_ids)

        import pdb;pdb.set_trace()
        #me_friend_checkins = persistence.CHECKIN.find({"loc" : {"$near": [client_longitude, client_latitude]}, "author_uid": {"$in": me_friend_ids}})
        #me_friend_checkins = persistence.CHECKIN.find({"loc" : {"$near": [client_longitude, client_latitude], "$maxDistance": 2.5}, "author_uid": {"$in": me_friend_ids}})

        s = SON({'$near': [client_longitude, client_latitude]})
        s.update({'$maxDistance': 0.5})
        me_friend_checkins = persistence.CHECKIN.find({"loc" : s, "author_uid": {"$in": me_friend_ids}})   
        #me_friend_checkins = persistence.CHECKIN.find({"loc" : s}).limit(20)

        count = me_friend_checkins.count()
        logger.debug("length of no max distance checkins: %s", count)

        for c in me_friend_checkins:                                                                                                                                              
            logger.debug("%s", c)
Exemple #9
0
    def create_index(self, sort_fields, **kwargs):
        if not isinstance(sort_fields, qf.sort):
            raise TypeError("TxMongo: sort_fields must be an instance of filter.sort")

        if "name" not in kwargs:
            name = self._gen_index_name(sort_fields["orderby"])
        else:
            name = kwargs.pop("name")

        key = SON()
        for k, v in sort_fields["orderby"]:
            key.update({k: v})

        index = SON(dict(
            ns=str(self),
            name=name,
            key=key
        ))

        if "drop_dups" in kwargs:
            kwargs["dropDups"] = kwargs.pop("drop_dups")

        if "bucket_size" in kwargs:
            kwargs["bucketSize"] = kwargs.pop("bucket_size")

        index.update(kwargs)
        yield self._database.system.indexes.insert(index, safe=True, **kwargs)
        defer.returnValue(name)
Exemple #10
0
    def _new_find_and_modify(self, filter, projection, sort, upsert=None,
                             return_document=ReturnDocument.BEFORE, **kwargs):
        validate_is_mapping("filter", filter)
        if not isinstance(return_document, bool):
            raise ValueError("TxMongo: return_document must be ReturnDocument.BEFORE "
                             "or ReturnDocument.AFTER")

        cmd = SON([("findAndModify", self._collection_name),
                   ("query", filter),
                   ("new", return_document)])
        cmd.update(kwargs)

        if projection is not None:
            cmd["fields"] = self._normalize_fields_projection(projection)

        if sort is not None:
            cmd["sort"] = dict(sort["orderby"])
        if upsert is not None:
            validate_boolean("upsert", upsert)
            cmd["upsert"] = upsert

        no_obj_error = "No matching object found"

        result = yield self._database.command(cmd, allowable_errors=[no_obj_error], **kwargs)
        defer.returnValue(result.get("value"))
Exemple #11
0
def mapping(data, dictionary):
	"""Mapping a dictionary (SON) into a a MongoDB command.

	The idea is: all values are keywords of a lambda functions dictionary,
	each function take attribute as the only argument. Each lambda function
	will generate a SON file consist of proper form of MongoDB operation
	and a random values in designated place.

	Note:
		please notice that same keyword might represent different lambda
		function in different type of operation.
		E.g. Array.Num in update and insert represent different operator.

	Example:
		{'A1.B1': 'num_match'} + {'num_match' : lambda attr: {attr: self.values.randInt()},}
		--> return {'A1.B1': 130416}
	"""
	res = SON()
	for attr,cmd in data.items():
		if isinstance(cmd, dict): # nested document: {'A1': {'B1': 'num_match'}}
			res[attr] = mapping(cmd, dictionary)
		else:
			new = dictionary[cmd](attr)
			assert(len(new) == 1)
			k, v = new.items()[0]
			if k in res: # duplicate attribute -> operators in update, e.g. $set, $push
				res[k].update(v)
			else:
				res.update(new)
	return res
Exemple #12
0
    def command(
        self,
        command,
        value=1,
        check=True,
        allowable_errors=None,
        codec_options=DEFAULT_CODEC_OPTIONS,
        _deadline=None,
        **kwargs
    ):
        """command(command, value=1, check=True, allowable_errors=None, codec_options=DEFAULT_CODEC_OPTIONS)"""
        if isinstance(command, (bytes, unicode)):
            command = SON([(command, value)])
        options = kwargs.copy()
        command.update(options)

        def on_ok(response):
            if check:
                msg = "TxMongo: command {0} on namespace {1} failed with '%s'".format(repr(command), ns)
                _check_command_response(response, msg, allowable_errors)

            return response

        ns = self["$cmd"].with_options(codec_options=codec_options)
        return ns.find_one(command, _deadline=_deadline).addCallback(on_ok)
Exemple #13
0
def __last_error(namespace, args):
    """Data to send to do a lastError.
    """
    cmd = SON([("getlasterror", 1)])
    cmd.update(args)
    splitns = namespace.split('.', 1)
    return query(0, splitns[0] + '.$cmd', 0, -1, cmd)
Exemple #14
0
    def create_index(self, sort_fields, **kwargs):
        if not isinstance(sort_fields, qf.sort):
            raise TypeError("sort_fields must be an instance of filter.sort")

        if "name" not in kwargs:
            name = self._gen_index_name(sort_fields["orderby"])
        else:
            name = kwargs.pop("name")

        key = SON()
        for k, v in sort_fields["orderby"]:
            key.update({k: v})

        index = SON(dict(
            ns=str(self),
            name=name,
            key=key
        ))

        if "drop_dups" in kwargs:
            kwargs["dropDups"] = kwargs.pop("drop_dups")

        if "bucket_size" in kwargs:
            kwargs["bucketSize"] = kwargs.pop("bucket_size")

        index.update(kwargs)
        yield self._database.system.indexes.insert(index, safe=True)
        defer.returnValue(name)
Exemple #15
0
def _gen_find_command(coll, spec, projection, skip, limit, batch_size, options,
                      read_concern, collation=None):
    """Generate a find command document."""
    cmd = SON([('find', coll)])
    if '$query' in spec:
        cmd.update([(_MODIFIERS[key], val) if key in _MODIFIERS else (key, val)
                    for key, val in spec.items()])
        if '$explain' in cmd:
            cmd.pop('$explain')
        if '$readPreference' in cmd:
            cmd.pop('$readPreference')
    else:
        cmd['filter'] = spec

    if projection:
        cmd['projection'] = projection
    if skip:
        cmd['skip'] = skip
    if limit:
        cmd['limit'] = abs(limit)
        if limit < 0:
            cmd['singleBatch'] = True
    if batch_size:
        cmd['batchSize'] = batch_size
    if read_concern.level:
        cmd['readConcern'] = read_concern.document
    if collation:
        cmd['collation'] = collation
    if options:
        cmd.update([(opt, True)
                    for opt, val in _OPTIONS.items()
                    if options & val])
    return cmd
Exemple #16
0
    def __query_spec(self):
        """Get the spec to use for a query.
        """
        operators = {}
        if self.__ordering:
            operators["$orderby"] = self.__ordering
        if self.__explain:
            operators["$explain"] = True
        if self.__hint:
            operators["$hint"] = self.__hint
        if self.__snapshot:
            operators["$snapshot"] = True
        if self.__max_scan:
            operators["$maxScan"] = self.__max_scan

        if operators:
            # Make a shallow copy so we can cleanly rewind or clone.
            spec = self.__spec.copy()
            if "$query" not in spec:
                # $query has to come first
                spec = SON({"$query": spec})
            spec.update(operators)
            return spec
        # Have to wrap with $query if "query" is the first key.
        # We can't just use $query anytime "query" is a key as
        # that breaks commands like count and find_and_modify.
        # Checking spec.keys()[0] covers the case that the spec
        # was passed as an instance of SON or OrderedDict.
        elif ("query" in self.__spec and
              (len(self.__spec) == 1 or self.__spec.keys()[0] == "query")):
                return SON({"$query": self.__spec})

        return self.__spec
Exemple #17
0
    def command(self,
                command,
                value=1,
                callback=None,
                check=True,
                allowable_errors=[],
                **kwargs):
        """Issue a MongoDB command.

        Send command `command` to the database and return the
        response. If `command` is an instance of :class:`basestring`
        then the command {`command`: `value`} will be sent. Otherwise,
        `command` must be an instance of :class:`dict` and will be
        sent as is.

        Any additional keyword arguments will be added to the final
        command document before it is sent.

        For example, a command like ``{buildinfo: 1}`` can be sent
        using:

        >>> db.command("buildinfo")

        For a command where the value matters, like ``{collstats:
        collection_name}`` we can do:

        >>> db.command("collstats", collection_name)

        For commands that take additional arguments we can use
        kwargs. So ``{filemd5: object_id, root: file_root}`` becomes:

        >>> db.command("filemd5", object_id, root=file_root)

        :Parameters:
          - `command`: document representing the command to be issued,
            or the name of the command (for simple commands only).

            .. note:: the order of keys in the `command` document is
               significant (the "verb" must come first), so commands
               which require multiple keys (e.g. `findandmodify`)
               should use an instance of :class:`~bson.son.SON` or
               a string and kwargs instead of a Python `dict`.

          - `value` (optional): value to use for the command verb when
            `command` is passed as a string
          - `**kwargs` (optional): additional keyword arguments will
            be added to the command document before it is sent

        .. mongodoc:: commands
        """

        if isinstance(command, basestring):
            command = SON([(command, value)])

        command.update(kwargs)

        self.connection("$cmd").find_one(command,
                                         callback=callback,
                                         _must_use_master=True,
                                         _is_command=True)
    def _command(self,
                 sock_info,
                 command,
                 slave_ok=False,
                 value=1,
                 check=True,
                 allowable_errors=None,
                 read_preference=ReadPreference.PRIMARY,
                 codec_options=DEFAULT_CODEC_OPTIONS,
                 write_concern=None,
                 parse_write_concern_error=False,
                 session=None,
                 **kwargs):
        """Internal command helper."""
        if isinstance(command, str):
            command = SON([(command, value)])

        command.update(kwargs)
        with self.__client._tmp_session(session) as s:
            return sock_info.command(
                self.__name,
                command,
                slave_ok,
                read_preference,
                codec_options,
                check,
                allowable_errors,
                write_concern=write_concern,
                parse_write_concern_error=parse_write_concern_error,
                session=s,
                client=self.__client)
def _gen_find_command(coll, spec, projection, skip, limit, batch_size, options):
    """Generate a find command document."""
    cmd = SON([('find', coll)])
    if '$query' in spec:
        cmd.update([(_MODIFIERS[key], val) for key, val in spec.items()])
    else:
        cmd['filter'] = spec

    if projection:
        cmd['projection'] = projection
    if skip:
        cmd['skip'] = skip
    if limit:
        cmd['limit'] = limit
    if batch_size:
        cmd['batchSize'] = batch_size
    # XXX: Should the check for 1 be here?
    if limit < 0 or limit == 1:
        cmd['singleBatch'] = True

    if options:
        cmd.update([(opt, True)
                    for opt, val in _OPTIONS.items()
                    if options & val])
    return cmd
Exemple #20
0
class SortStage(object):
    key = '$sort'

    def __init__(self):
        self._sorts = SON()

    def by(self, *args):
        if not args:
            raise RuntimeError('This method needs at least one argument')

        if isinstance(args[0], list):
            return self.by(*args[0])

        if isinstance(args[0], tuple):
            sort_by = SON(args)
        else:
            raise ValueError('The arguments to this method must be tuples')

        self._sorts.update(sort_by)

        return self

    def sort(self, field, direction=1):
        if isinstance(direction, basestring):
            if direction.lower() == 'asc':
                direction = 1
            else:
                direction = -1
        self._sorts[field] = direction

        return self

    def build(self):
        return {self.key: self._sorts}
    def find_and_modify(self, query={}, update=None, upsert=False, **kwargs):
        def wrapper(result):
            no_obj_error = "No matching object found"
            if not result['ok']:
                if result["errmsg"] == no_obj_error:
                    return None
                else:
                    raise ValueError("Unexpected Error: %s" % (result,))
            return result.get('value')

        if (not update and not kwargs.get('remove', None)):
            raise ValueError("Must either update or remove")

        if (update and kwargs.get('remove', None)):
            raise ValueError("Can't do both update and remove")

        cmd = SON([("findAndModify", self._collection_name)])
        cmd.update(kwargs)
        # No need to include empty args
        if query:
            cmd['query'] = query
        if update:
            cmd['update'] = update
        if upsert:
            cmd['upsert'] = upsert

        d = self._database["$cmd"].find_one(cmd)
        d.addCallback(wrapper)

        return d
Exemple #22
0
    def _new_find_and_modify(self, filter, projection, sort, upsert=None,
                             return_document=ReturnDocument.BEFORE, **kwargs):
        validate_is_mapping("filter", filter)
        if not isinstance(return_document, bool):
            raise ValueError("TxMongo: return_document must be ReturnDocument.BEFORE "
                             "or ReturnDocument.AFTER")

        cmd = SON([("findAndModify", self._collection_name),
                   ("query", filter),
                   ("new", return_document)])
        cmd.update(kwargs)

        if projection is not None:
            cmd["fields"] = self._normalize_fields_projection(projection)

        if sort is not None:
            cmd["sort"] = dict(sort["orderby"])
        if upsert is not None:
            validate_boolean("upsert", upsert)
            cmd["upsert"] = upsert

        no_obj_error = "No matching object found"

        result = yield self._database.command(cmd, allowable_errors=[no_obj_error], **kwargs)
        defer.returnValue(result.get("value"))
class SortStage(object):
    key = '$sort'

    def __init__(self):
        self._sorts = SON()

    def by(self, *args):
        if not args:
            raise RuntimeError('This method needs at least one argument')

        if isinstance(args[0], list):
            return self.by(*args[0])

        if isinstance(args[0], tuple):
            sort_by = SON(args)
        else:
            raise ValueError('The arguments to this method must be tuples')

        self._sorts.update(sort_by)

        return self

    def sort(self, field, direction=1):
        if isinstance(direction, basestring):
            if direction.lower() == 'asc':
                direction = 1
            else:
                direction = -1
        self._sorts[field] = direction

        return self

    def build(self):
        return {self.key: self._sorts}
Exemple #24
0
def _gen_find_command(coll, spec, projection, skip, limit, batch_size, options, read_concern=DEFAULT_READ_CONCERN):
    """Generate a find command document."""
    cmd = SON([("find", coll)])
    if "$query" in spec:
        cmd.update([(_MODIFIERS[key], val) if key in _MODIFIERS else (key, val) for key, val in spec.items()])
        if "$explain" in cmd:
            cmd.pop("$explain")
        if "$readPreference" in cmd:
            cmd.pop("$readPreference")
    else:
        cmd["filter"] = spec

    if projection:
        cmd["projection"] = projection
    if skip:
        cmd["skip"] = skip
    if limit:
        cmd["limit"] = abs(limit)
        if limit < 0:
            cmd["singleBatch"] = True
    if batch_size:
        cmd["batchSize"] = batch_size
    if read_concern.level:
        cmd["readConcern"] = read_concern.document

    if options:
        cmd.update([(opt, True) for opt, val in _OPTIONS.items() if options & val])
    return cmd
Exemple #25
0
def __last_error(namespace, args):
    """Data to send to do a lastError.
    """
    cmd = SON([("getlasterror", 1)])
    cmd.update(args)
    splitns = namespace.split('.', 1)
    return query(0, splitns[0] + '.$cmd', 0, -1, cmd)
Exemple #26
0
 def get_document_proof(
     self,
     collection: str,
     filter: Dict[str, Any],
     version: int,
     proof_format: Optional[str] = None,
 ) -> GetDocumentProofResponse:
     """Filters documents in a collection and returns any proofs of those documents for a given version.
     See: https://provendb.readme.io/docs/getdocumentproof
     :param collection: The name of the collection to filter.
     :type collection: str
     :param filter: A mongodb filter that subsets the collection.
     :type filter: Dict[str, Any]
     :param version: The version number to fetch proofs for.
     :type version: int
     :param proof_format: The format of the proof, either 'binary' or 'json', defaults to "json"
     :type proof_format: str
     :raises GetDocumentProofException: [description]
     :return: A dict-like object containing an array of document proof documents.
     :rtype: GetDocumentProofResponse
     """
     command_args = SON(
         {
             "collection": collection,
             "filter": filter,
             "version": version,
         }
     )
     if proof_format:
         command_args.update({"proofFormat": proof_format})
     response = self.db.command("getDocumentProof", command_args)
     return GetDocumentProofResponse(response)
Exemple #27
0
def _gen_find_command(coll, spec, projection, skip, limit, batch_size,
                      options, read_concern=DEFAULT_READ_CONCERN):
    """Generate a find command document."""
    cmd = SON([('find', coll)])
    if '$query' in spec:
        cmd.update([(_MODIFIERS[key], val) if key in _MODIFIERS else (key, val)
                    for key, val in spec.items()])
        if '$explain' in cmd:
            cmd.pop('$explain')
        if '$readPreference' in cmd:
            cmd.pop('$readPreference')
    else:
        cmd['filter'] = spec

    if projection:
        cmd['projection'] = projection
    if skip:
        cmd['skip'] = skip
    if limit:
        cmd['limit'] = abs(limit)
        if limit < 0:
            cmd['singleBatch'] = True
    if batch_size:
        cmd['batchSize'] = batch_size
    if read_concern.level:
        cmd['readConcern'] = read_concern.document

    if options:
        cmd.update([(opt, True)
                    for opt, val in _OPTIONS.items()
                    if options & val])
    return cmd
Exemple #28
0
    def __query_spec(self):
        """Get the spec to use for a query.
        """
        operators = {}
        if self.__ordering:
            operators["$orderby"] = self.__ordering
        if self.__explain:
            operators["$explain"] = True
        if self.__hint:
            operators["$hint"] = self.__hint
        if self.__snapshot:
            operators["$snapshot"] = True
        if self.__max_scan:
            operators["$maxScan"] = self.__max_scan

        if operators:
            # Make a shallow copy so we can cleanly rewind or clone.
            spec = self.__spec.copy()
            if "$query" not in spec:
                # $query has to come first
                spec = SON({"$query": spec})
            spec.update(operators)
            return spec
        # Have to wrap with $query if "query" is the first key.
        # We can't just use $query anytime "query" is a key as
        # that breaks commands like count and find_and_modify.
        # Checking spec.keys()[0] covers the case that the spec
        # was passed as an instance of SON or OrderedDict.
        elif ("query" in self.__spec
              and (len(self.__spec) == 1 or self.__spec.keys()[0] == "query")):
            return SON({"$query": self.__spec})

        return self.__spec
    def _command(self, command, value=1,
                 check=True, allowable_errors=None,
                 uuid_subtype=OLD_UUID_SUBTYPE, compile_re=True,
                 read_preference=None, **kwargs):
        """Internal command helper.
        """

        if isinstance(command, basestring):
            command_name = command.lower()
            command = SON([(command, value)])
        else:
            command_name = command.keys()[0].lower()

        as_class = kwargs.pop('as_class', None)
        fields = kwargs.pop('fields', None)
        if fields is not None and not isinstance(fields, dict):
            fields = helpers._fields_list_to_dict(fields)
        command.update(kwargs)

        orig = mode = read_preference or self.read_preference
        if command_name not in SECONDARY_OK_COMMANDS:
            mode = ReadPreference.PRIMARY

        # Special-case: mapreduce can go to secondaries only if inline
        elif command_name == 'mapreduce':
            out = command.get('out')
            if not isinstance(out, dict) or not out.get('inline'):
                mode = ReadPreference.PRIMARY

        # Special-case: aggregate with $out cannot go to secondaries.
        elif command_name == 'aggregate':
            for stage in command.get('pipeline', []):
                if '$out' in stage:
                    mode = ReadPreference.PRIMARY
                    break

        # Warn if mode will override read_preference.
        if mode != orig:
            warnings.warn("%s does not support %s read preference "
                          "and will be routed to the primary instead." %
                          (command_name, orig.name), UserWarning)


        cursor = self["$cmd"].find(command,
                                   fields=fields,
                                   limit=-1,
                                   as_class=as_class,
                                   read_preference=mode,
                                   compile_re=compile_re,
                                   _uuid_subtype=uuid_subtype)
        for doc in cursor:
            result = doc

        if check:
            msg = "command %s failed: %%s" % repr(command).replace("%", "%%")
            helpers._check_command_response(result, self.connection.disconnect,
                                            msg, allowable_errors)

        return result, cursor.conn_id
def _create_user(authdb, user, pwd=None, roles=None, **kwargs):
    cmd = SON([('createUser', user)])
    # X509 doesn't use a password
    if pwd:
        cmd['pwd'] = pwd
    cmd['roles'] = roles or ['root']
    cmd.update(**kwargs)
    return authdb.command(cmd)
 def transform_incoming(self, son, collection):
     """Move _id to the front if it's there.
     """
     if not "_id" in son:
         return son
     transformed = SON({"_id": son["_id"]})
     transformed.update(son)
     return transformed
Exemple #32
0
 def transform_incoming(self, son, collection):
     """Move _id to the front if it's there.
     """
     if not "_id" in son:
         return son
     transformed = SON({"_id": son["_id"]})
     transformed.update(son)
     return transformed
def _create_user(authdb, user, pwd=None, roles=None, **kwargs):
    cmd = SON([('createUser', user)])
    # X509 doesn't use a password
    if pwd:
        cmd['pwd'] = pwd
    cmd['roles'] = roles or ['root']
    cmd.update(**kwargs)
    return authdb.command(cmd)
Exemple #34
0
 def fail_point(self, command_args):
     cmd_on = SON([('configureFailPoint', 'failCommand')])
     cmd_on.update(command_args)
     client_context.client.admin.command(cmd_on)
     try:
         yield
     finally:
         client_context.client.admin.command(
             'configureFailPoint', cmd_on['configureFailPoint'], mode='off')
    def __query_spec(self):
        """Get the spec to use for a query.
        """
        operators = {}
        if self.__ordering:
            operators["$orderby"] = self.__ordering
        if self.__explain:
            operators["$explain"] = True
        if self.__hint:
            operators["$hint"] = self.__hint
        if self.__let:
            operators["let"] = self.__let
        if self.__comment:
            operators["$comment"] = self.__comment
        if self.__max_scan:
            operators["$maxScan"] = self.__max_scan
        if self.__max_time_ms is not None:
            operators["$maxTimeMS"] = self.__max_time_ms
        if self.__max:
            operators["$max"] = self.__max
        if self.__min:
            operators["$min"] = self.__min
        if self.__return_key is not None:
            operators["$returnKey"] = self.__return_key
        if self.__show_record_id is not None:
            # This is upgraded to showRecordId for MongoDB 3.2+ "find" command.
            operators["$showDiskLoc"] = self.__show_record_id
        if self.__snapshot is not None:
            operators["$snapshot"] = self.__snapshot

        if operators:
            # Make a shallow copy so we can cleanly rewind or clone.
            spec = self.__spec.copy()

            # Allow-listed commands must be wrapped in $query.
            if "$query" not in spec:
                # $query has to come first
                spec = SON([("$query", spec)])

            if not isinstance(spec, SON):
                # Ensure the spec is SON. As order is important this will
                # ensure its set before merging in any extra operators.
                spec = SON(spec)

            spec.update(operators)
            return spec
        # Have to wrap with $query if "query" is the first key.
        # We can't just use $query anytime "query" is a key as
        # that breaks commands like count and find_and_modify.
        # Checking spec.keys()[0] covers the case that the spec
        # was passed as an instance of SON or OrderedDict.
        elif ("query" in self.__spec and
              (len(self.__spec) == 1 or next(iter(self.__spec)) == "query")):
            return SON({"$query": self.__spec})

        return self.__spec
Exemple #36
0
def repl_set_step_down(client, **kwargs):
    """Run replSetStepDown, first unfreezing a secondary with replSetFreeze."""
    cmd = SON([('replSetStepDown', 1)])
    cmd.update(kwargs)

    # Unfreeze a secondary to ensure a speedy election.
    client.admin.command('replSetFreeze',
                         0,
                         read_preference=ReadPreference.SECONDARY)
    client.admin.command(cmd)
    def as_doc(self):
        """Get the SON document representation of this DBRef.

        Generally not needed by application developers
        """
        doc = SON([("$ref", self.collection), ("$id", self.id)])
        if self.database is not None:
            doc["$db"] = self.database
        doc.update(self.__kwargs)
        return doc
Exemple #38
0
    def as_doc(self):
        """Get the SON document representation of this DBRef.

        Generally not needed by application developers
        """
        doc = SON([("$ref", self.collection), ("$id", self.id)])
        if self.database is not None:
            doc["$db"] = self.database
        doc.update(self.__kwargs)
        return doc
Exemple #39
0
    def __query_spec(self):
        """Get the spec to use for a query.
        """
        operators = self.__modifiers.copy()
        if self.__ordering:
            operators["$orderby"] = self.__ordering
        if self.__explain:
            operators["$explain"] = True
        if self.__hint:
            operators["$hint"] = self.__hint
        if self.__comment:
            operators["$comment"] = self.__comment
        if self.__max_scan:
            operators["$maxScan"] = self.__max_scan
        if self.__max_time_ms is not None:
            operators["$maxTimeMS"] = self.__max_time_ms
        if self.__max:
            operators["$max"] = self.__max
        if self.__min:
            operators["$min"] = self.__min
        if self.__return_key:
            operators["$returnKey"] = self.__return_key
        if self.__show_record_id:
            # This is upgraded to showRecordId for MongoDB 3.2+ "find" command.
            operators["$showDiskLoc"] = self.__show_record_id
        if self.__snapshot:
            operators["$snapshot"] = self.__snapshot

        if operators:
            # Make a shallow copy so we can cleanly rewind or clone.
            spec = self.__spec.copy()

            # White-listed commands must be wrapped in $query.
            if "$query" not in spec:
                # $query has to come first
                spec = SON([("$query", spec)])

            if not isinstance(spec, SON):
                # Ensure the spec is SON. As order is important this will
                # ensure its set before merging in any extra operators.
                spec = SON(spec)

            spec.update(operators)
            return spec
        # Have to wrap with $query if "query" is the first key.
        # We can't just use $query anytime "query" is a key as
        # that breaks commands like count and find_and_modify.
        # Checking spec.keys()[0] covers the case that the spec
        # was passed as an instance of SON or OrderedDict.
        elif ("query" in self.__spec and
              (len(self.__spec) == 1 or
               next(iter(self.__spec)) == "query")):
            return SON({"$query": self.__spec})

        return self.__spec
    def command(self, command, value=1, callback=None,
                check=True, allowable_errors=[], **kwargs):
        """Issue a MongoDB command.

        Send command `command` to the database and return the
        response. If `command` is an instance of :class:`basestring`
        then the command {`command`: `value`} will be sent. Otherwise,
        `command` must be an instance of :class:`dict` and will be
        sent as is.

        Any additional keyword arguments will be added to the final
        command document before it is sent.

        For example, a command like ``{buildinfo: 1}`` can be sent
        using:

        >>> db.command("buildinfo")

        For a command where the value matters, like ``{collstats:
        collection_name}`` we can do:

        >>> db.command("collstats", collection_name)

        For commands that take additional arguments we can use
        kwargs. So ``{filemd5: object_id, root: file_root}`` becomes:

        >>> db.command("filemd5", object_id, root=file_root)

        :Parameters:
          - `command`: document representing the command to be issued,
            or the name of the command (for simple commands only).

            .. note:: the order of keys in the `command` document is
               significant (the "verb" must come first), so commands
               which require multiple keys (e.g. `findandmodify`)
               should use an instance of :class:`~bson.son.SON` or
               a string and kwargs instead of a Python `dict`.

          - `value` (optional): value to use for the command verb when
            `command` is passed as a string
          - `**kwargs` (optional): additional keyword arguments will
            be added to the command document before it is sent

        .. mongodoc:: commands
        """

        if isinstance(command, str):
            command = SON([(command, value)])

        command.update(kwargs)

        self.connection("$cmd").find_one(command,callback=callback,
                                       _must_use_master=True,
                                       _is_command=True)
    def map_reduce(self, map, reduce, full_response=False, **kwargs):
        def wrapper(result, full_response):
            if full_response:
                return result
            return result.get("result")

        cmd = SON([("mapreduce", self._collection_name),
                       ("map", map), ("reduce", reduce)])
        cmd.update(**kwargs)
        d = self._database["$cmd"].find_one(cmd)
        d.addCallback(wrapper, full_response)
        return d
    def map_reduce(self, map, reduce, full_response=False, **kwargs):
        def wrapper(result, full_response):
            if full_response:
                return result
            return result.get("result")

        cmd = SON([("mapreduce", self._collection_name), ("map", map),
                   ("reduce", reduce)])
        cmd.update(**kwargs)
        d = self._database["$cmd"].find_one(cmd)
        d.addCallback(wrapper, full_response)
        return d
def custom_parallel_scan(collection, num_cursors, **kwargs):
    cmd = SON([('parallelCollectionScan', collection._Collection__name),
               ('numCursors', num_cursors)])
    cmd.update(kwargs)
    with collection._socket_for_reads() as (sock_info, slave_ok):
        result = collection._command(sock_info,
                                     cmd,
                                     slave_ok,
                                     read_concern=collection.read_concern)


#    return [cursor['cursor'] for cursor in result['cursors']]
    return result['cursors']
Exemple #44
0
    def command(self, command, value=1, check=True, allowable_errors=None, **kwargs):
        if isinstance(command, basestring):
            command = SON([(command, value)])
        command.update(kwargs)

        ns = self["$cmd"]
        response = yield ns.find_one(command)

        if check:
            msg = "command {0} on namespace {1} failed: %s".format(repr(command), ns)
            _check_command_response(response, msg, allowable_errors)

        defer.returnValue(response)
Exemple #45
0
    def list_versions(
        self,
        start_date: Optional[datetime.datetime] = None,
        end_date: Optional[datetime.datetime] = None,
        limit: Optional[int] = None,
        sort_direction: Optional[int] = None,
    ) -> ListVersionsResponse:
        """Retrieves a list of versions given a search parameter.
        See https://provendb.readme.io/docs/listversions

        :param start_date: Specifies first date to retrieve versions, defaults to 24 hours from now
        :type start_date: Optional[datetime.datetime]
        :param end_date: Last date to retrieve documents, defaults to now
        :type end_date: Optional[datetime.datetime]
        :param limit: Number of version documents to retrieve, defaults to 10
        :type limit: Optional[int], optional
        :param sort_direction: -1 to retrieve versions in descending order, 1 ascending order. Defaults to -1.
        :type sort_direction: Optional[int], optional
        :raises ListVersionException: pyproven exception when fails to retrieve version list.
        :return: A dict-like object representing the ProvenDB response document.
        :rtype: ListVersionsResponse
        """
        command_args = SON()
        if start_date:
            command_args.update({"startDate": start_date})
        if end_date:
            command_args.update({"endDate": end_date})
        if limit:
            command_args.update({"limit": limit})
        if sort_direction:
            command_args.update({"sortDirection": sort_direction})
        response = self.db.command({"listVersions": command_args})
        return ListVersionsResponse(response)
Exemple #46
0
    def createDBUsers(self):
        conn = self.__get_connection()
        yield conn["admin"].authenticate(self.ua_login, self.ua_password)

        create_user = SON({"createUser": self.login1})
        create_user.update({"pwd": self.password1, "roles": [{"role": "readWrite",
                                                              "db": self.db1}]})
        yield conn[self.db1]["$cmd"].find_one(create_user)

        create_user = SON({"createUser": self.login2})
        create_user.update({"pwd": self.password2, "roles": [{"role": "readWrite",
                                                              "db": self.db2}]})
        yield conn[self.db2]["$cmd"].find_one(create_user)

        yield conn.disconnect()
Exemple #47
0
    def _on_get_nonce(self, response, error=None):
        if error:
            raise AuthenticationError(error)
        nonce = response['data'][0]['nonce']
        key = hashlib.md5(nonce + self._dbuser + hashlib.md5(self._dbuser + ":mongo:" + self._dbpass).hexdigest()).hexdigest()

        command = SON([('authenticate', 1)])
        command.update({'user' : self._dbuser, 'nonce' : nonce, 'key' : key})
        self.conn.send_message(
                message.query(0,
                              "%s.$cmd" % self._dbname,
                              0,
                              1,
                              command,
                              SON({})),callback=self._on_authenticate)
Exemple #48
0
    def command(self, command, value=1, check=True, allowable_errors=None, **kwargs):
        if isinstance(command, (bytes, unicode)):
            command = SON([(command, value)])
        options = kwargs.copy()
        options.pop("_deadline", None)
        command.update(options)

        ns = self["$cmd"]
        response = yield ns.find_one(command, **kwargs)

        if check:
            msg = "TxMongo: command {0} on namespace {1} failed with '%s'".format(repr(command), ns)
            _check_command_response(response, msg, allowable_errors)

        defer.returnValue(response)
Exemple #49
0
    def count(self, query=None, callback=None):
        command = SON({
            "count": self.collection.__collection__
        })

        if query:
            command.update({'query': query})

        result, error = yield gen.Task(Database().command, command)

        total = 0
        if result and len(result) > 0 and 'n' in result:
            total = int(result['n'])

        callback(total)
Exemple #50
0
    async def list_collections(self,
                               *,
                               session: Optional[AsyncClientSession] = None,
                               query: Optional[MutableMapping[str,
                                                              Any]] = None,
                               **kwargs: Any) -> AsyncCommandCursor:
        cmd = SON([("listCollections", 1)])
        cmd.update(query, **kwargs)

        res: MutableMapping[str, Any] = await util.run_sync(
            self.dispatch._retryable_read_command,  # skipcq: PYL-W0212
            cmd,
            session=session.dispatch if session else session)
        return AsyncCommandCursor(
            CommandCursor(self["$cmd"], res["cursor"], None))
    def _command(self, sock_info, command, slave_ok=False, value=1, check=True,
                 allowable_errors=None, read_preference=ReadPreference.PRIMARY,
                 codec_options=CodecOptions(), **kwargs):
        """Internal command helper."""
        if isinstance(command, string_type):
            command = SON([(command, value)])
        command.update(kwargs)

        return sock_info.command(self.__name,
                                 command,
                                 slave_ok,
                                 read_preference,
                                 codec_options,
                                 check,
                                 allowable_errors)
Exemple #52
0
    def _command(self, sock_info, command, slave_ok=False, value=1, check=True,
                 allowable_errors=None, read_preference=ReadPreference.PRIMARY,
                 codec_options=DEFAULT_CODEC_OPTIONS, **kwargs):
        """Internal command helper."""
        if isinstance(command, string_type):
            command = SON([(command, value)])
        command.update(kwargs)

        return sock_info.command(self.__name,
                                 command,
                                 slave_ok,
                                 read_preference,
                                 codec_options,
                                 check,
                                 allowable_errors)
Exemple #53
0
    def __query_spec(self) -> SON:
        """Get the spec to use for a query.
        """
        operators = self.__modifiers
        if self.__ordering:
            operators['$orderby'] = self.__ordering
        if self.__explain:
            operators['$explain'] = True
        if self.__hint:
            operators['$hint'] = self.__hint
        if self.__comment:
            operators['$comment'] = self.__comment
        if self.__max_scan:
            operators['$maxScan'] = self.__max_scan
        if self.__max_time_ms is not None:
            operators['$maxTimeMS'] = self.__max_time_ms
        if self.__max:
            operators['$max'] = self.__max
        if self.__min:
            operators['$min'] = self.__min

        if operators:
            # Make a shallow copy so we can cleanly rewind or clone.
            spec = self.__spec.copy()

            # White-listed commands must be wrapped in $query.
            if '$query' not in spec:
                # $query has to come first
                spec = SON([('$query', spec)])

            if not isinstance(spec, SON):
                # Ensure the spec is SON. As order is important this will
                # ensure its set before merging in any extra operators.
                spec = SON(spec)

            spec.update(operators)
            return spec
        # Have to wrap with $query if 'query' is the first key.
        # We can't just use $query anytime 'query' is a key as
        # that breaks commands like count and find_and_modify.
        # Checking spec.keys()[0] covers the case that the spec
        # was passed as an instance of SON or OrderedDict.
        elif ('query' in self.__spec and
                  (len(self.__spec) == 1 or
                           next(iter(self.__spec)) == 'query')):
            return SON({'$query': self.__spec})

        return self.__spec
Exemple #54
0
    def distinct(self, key, callback, query=None):
        """Returns a list of distinct values for the given
        key across collection"""
        command = SON({
            "distinct": self.collection.__collection__,
            "key": key,
        })
        if query:
            command.update({'query': query})

        result, error = yield gen.Task(Database().command, command)

        if result and result['ok']:
            callback(result['values'])
        else:
            callback(None)
Exemple #55
0
    def command(self, command, value=1, check=True, allowable_errors=None,
                codec_options=DEFAULT_CODEC_OPTIONS, _deadline=None, **kwargs):
        """command(command, value=1, check=True, allowable_errors=None, codec_options=DEFAULT_CODEC_OPTIONS)"""
        if isinstance(command, (bytes, unicode)):
            command = SON([(command, value)])
        options = kwargs.copy()
        command.update(options)

        def on_ok(response):
            if check:
                msg = "TxMongo: command {0} on namespace {1} failed with '%s'".format(repr(command), ns)
                _check_command_response(response, msg, allowable_errors)

            return response

        ns = self["$cmd"].with_options(codec_options=codec_options)
        return ns.find_one(command, _deadline=_deadline).addCallback(on_ok)
def _gen_find_command(
    coll,
    spec,
    projection,
    skip,
    limit,
    batch_size,
    options,
    read_concern,
    collation=None,
    session=None,
    allow_disk_use=None,
):
    """Generate a find command document."""
    cmd = SON([("find", coll)])
    if "$query" in spec:
        cmd.update([(_MODIFIERS[key], val) if key in _MODIFIERS else (key, val)
                    for key, val in spec.items()])
        if "$explain" in cmd:
            cmd.pop("$explain")
        if "$readPreference" in cmd:
            cmd.pop("$readPreference")
    else:
        cmd["filter"] = spec

    if projection:
        cmd["projection"] = projection
    if skip:
        cmd["skip"] = skip
    if limit:
        cmd["limit"] = abs(limit)
        if limit < 0:
            cmd["singleBatch"] = True
    if batch_size:
        cmd["batchSize"] = batch_size
    if read_concern.level and not (session and session.in_transaction):
        cmd["readConcern"] = read_concern.document
    if collation:
        cmd["collation"] = collation
    if allow_disk_use is not None:
        cmd["allowDiskUse"] = allow_disk_use
    if options:
        cmd.update([(opt, True) for opt, val in _OPTIONS.items()
                    if options & val])

    return cmd
Exemple #57
0
    def _command(self, sock_info, command, slave_ok=False, value=1, check=True,
                 allowable_errors=None, read_preference=ReadPreference.PRIMARY,
                 codec_options=CodecOptions(), **kwargs):
        """Internal command helper."""
        if isinstance(command, string_type):
            command = SON([(command, value)])
        command.update(kwargs)

        result = sock_info.command(self.__name,
                                   command,
                                   slave_ok,
                                   read_preference,
                                   codec_options,
                                   check,
                                   allowable_errors)

        # TODO: don't return address, caller knows it
        return result, sock_info.address
    def _list_collections(self, sock_info, slave_okay, session,
                          read_preference, **kwargs):
        """Internal listCollections helper."""

        coll = self.get_collection("$cmd", read_preference=read_preference)
        if sock_info.max_wire_version > 2:
            cmd = SON([("listCollections", 1), ("cursor", {})])
            cmd.update(kwargs)
            with self.__client._tmp_session(session,
                                            close=False) as tmp_session:
                cursor = self._command(sock_info,
                                       cmd,
                                       slave_okay,
                                       read_preference=read_preference,
                                       session=tmp_session)["cursor"]
                cmd_cursor = CommandCursor(coll,
                                           cursor,
                                           sock_info.address,
                                           session=tmp_session,
                                           explicit_session=session
                                           is not None)
        else:
            match = _INDEX_REGEX
            if "filter" in kwargs:
                match = {"$and": [_INDEX_REGEX, kwargs["filter"]]}
            dblen = len(self.name.encode("utf8") + b".")
            pipeline = [{
                "$project": {
                    "name": {
                        "$substr": ["$name", dblen, -1]
                    },
                    "options": 1
                }
            }, {
                "$match": match
            }]
            cmd = SON([("aggregate", "system.namespaces"),
                       ("pipeline", pipeline),
                       ("cursor", kwargs.get("cursor", {}))])
            cursor = self._command(sock_info, cmd, slave_okay)["cursor"]
            cmd_cursor = CommandCursor(coll, cursor, sock_info.address)
        cmd_cursor._maybe_pin_connection(sock_info)
        return cmd_cursor
Exemple #59
0
    def createUserAdmin(self):
        conn = self.__get_connection()

        try:
            create_user = SON({"createUser": self.ua_login})
            create_user.update({"pwd": self.ua_password, "roles": [{"role": "userAdminAnyDatabase",
                                                                    "db": "admin"}]})
            r = yield conn["admin"]["$cmd"].find_one(create_user)

            try:
                # This should fail if authentication enabled in MongoDB since
                # we've created user but didn't authenticated
                yield conn[self.db1][self.coll].find_one()

                yield conn["admin"]["$cmd"].find_one({"dropUser": self.ua_login})
                raise unittest.SkipTest("Authentication tests require authorization enabled "
                                        "in MongoDB configuration file")
            except OperationFailure:
                pass
        finally:
            yield conn.disconnect()
    def create_collection(self, name, options={}):
        def wrapper(result, deferred, collection):
            if result.get("ok", 0.0):
                deferred.callback(collection)
            else:
                deferred.errback(RuntimeError(result.get("errmsg", "unknown error")))

        deferred = defer.Deferred()
        collection = Collection(self, name)

        if options:
            if "size" in options:
                options["size"] = float(options["size"])

            command = SON({"create": name})
            command.update(options)
            d = self["$cmd"].find_one(command)
            d.addCallback(wrapper, deferred, collection)
        else:
            deferred.callback(collection)

        return deferred