Example #1
0
    def _execute_set_hash_pipeline(self, pipeline, name, update_map, inc_map, with_get, fields):
        """
        if fields is None, we assume it's raw mode, all fields will be retrieved, and no field encoder/decoder will be used
        """

        if with_get:
            if fields is not None:
                pipeline.hmget(name, fields)
            else:
                pipeline.hgetall(name)

        if len(update_map) > 0:
            pipeline.hmset(name, update_map)
        for field, inc_value in inc_map.items():
            if not isinstance(field, str):
                field = encode_string(field)
                if field is None:
                    raise Exception("redis/hash inc_map field name must be str, %s, %s, %s" % (name, field, inc_value))
            elif not isinstance(inc_value, int):
                raise Exception("redis/hash inc_map field value must be int, %s, %s, %s" % (name, field, inc_value))

            pipeline.hincrby(name, field, inc_value)
        if len(pipeline.command_stack) > 0:
            return pipeline.execute()
        else:
            return None
Example #2
0
    def get(self, data_type, ori_data_key, **kwargs):
        """
        text/json: returns dict object
        text/plan: returns str object
        redis/hash: needs fields, strict=False by default, returns dict object, returns None if strict and required field not exists
        redis/set: use data_key as query value, and returns True/False for existence
        """
        #logging.debug("redis get", data_type, ori_data_key, kwargs)
        data_key = copy.deepcopy(ori_data_key)

        if not self._enabled:
            return None

        name, content_type, enabled = self._prepare_op(data_type, data_key)
        if not enabled:
            return None

        parameters = RedisClient._get_parameters("get", content_type, **kwargs)

        if content_type == "text/json":
            data = self._client.get(name)
            return self._load_json_object(data)
        elif content_type == "text/plain":
            return self._client.get(name)
        elif content_type == "redis/hash":
            return self._get_hash(data_type, name, parameters["fields"], parameters["strict"])
        elif content_type == "redis/set":
            if not isinstance(data_key, str):
                data_key = encode_string(data_key)
                if data_key is None:
                    raise Exception("data_key must be str, %s" % data_key)

            return self._client.sismember(name, data_key)
        else:
            raise Exception("unsupported data_type for get, %s" % data_type)
Example #3
0
    def _set_hash(self, data_type, name, update_map, inc_map, with_get, fields, strict, cond):
        #refine update_map if not raw
        new_update_map = {}
        data_config = self._data_types.get(data_type)
        raw = data_config.get("raw", False)
        if len(fields) > 0 and raw:
            raise Exception("fields can't be used with raw")

        if raw:
            fields = None

        for field, value in update_map.items():
            if not isinstance(field, str):
                field = encode_string(field)
                if field is None:
                    raise Exception("redis/hash update_map field must be str, %s, %s, %s" % (name, field, value))

            if value is None:
                value = "\\None"
            else:
                if not raw:
                    field_configs = filter(lambda field_config : field_config == field if isinstance(field_config, str) else field_config[0] == field, data_config["fields"])
                    if len(field_configs) == 0:
                        raise Exception("unexpected field, %s, %s, %s" % (data_type, name, field))
                    field_config = field_configs[0]
                    if isinstance(field_config, tuple) and len(field_config) > 2 and field_config[2] != str:
                        encoder = field_config[2]
                        value = encoder(value)

                if isinstance(value, str) and RedisClient._special_none_pattern.match(value) is not None:
                    value = "\\" + value

            if not isinstance(value, str):
                value = str(value)

            new_update_map[field] = value

        update_map = new_update_map

        pipeline = self._client.pipeline(transaction=True)
        if cond is None:
            results = self._execute_set_hash_pipeline(pipeline, name, update_map, inc_map, with_get, fields)
        else:
            results = self._execute_set_hash_cond(pipeline, data_type, name, update_map, inc_map, with_get, fields, strict, cond)

        if results is None:
            return None if with_get else True
        elif results == False:
            return False
        elif len(filter(lambda result : result == False or isinstance(result, Exception), results)) > 0:
            raise Exception("set_hash failed, %s, %s, %s, %s" % (name, update_map, inc_map, results))
        elif with_get:
            values = results[0]
            return self._load_hash_object(values, data_type, name, fields, strict)
        else:
            return True
Example #4
0
    def _prepare_op(self, data_type, data_key):
        if not self._data_types.has_key(data_type):
            raise Exception("unsupported data type, data_type: %s" % data_type)

        if not isinstance(data_type, str):
            data_type = encode_string(data_type)
            if data_type is None:
                raise Exception("data_type must be str, %s" % data_type)

        data_config = self._data_types.get(data_type)
        enabled = data_config.get("enabled", True)
        content_type = data_config.get("content_type", "text/plain")
        name = RedisClient._generate_name(data_config.get("id_generator", "raw"), content_type, data_type, data_key)
        return name, content_type, enabled
Example #5
0
    def delete(self, data_type, ori_data_key, *fields):
        """
        text/json: delete the whole row
        text/plain: delete the whole row
        redis/hash: delete specified fields
        redis/set: delete the set member, data_key is the set member
        """
        data_key = copy.deepcopy(ori_data_key)
        if not self._enabled:
            return None

        name, content_type, enabled = self._prepare_op(data_type, data_key)
        if not enabled:
            return None

        if content_type == "text/json" or content_type == "text/plain":
            if len(fields) > 0:
                raise Exception("unexpected fields %s, %s, %s", data_type, data_key, fields)

            return self._client.delete(name)
        elif content_type == "redis/hash":
            if len(fields) == 0:
                return self._client.delete(name)
            else:
                return self._client.hdel(name, *fields)
        elif content_type == "redis/set":
            if len(fields) > 0:
                raise Exception("unexpected fields %s, %s, %s", data_type, data_key, fields)

            if data_key is None:
                return self._client.delete(name)
            elif not isinstance(data_key, str):
                data_key = encode_string(data_key)
                if data_key is None:
                    raise Exception("data_key must be str, %s" % data_key)
            else:
                return self._client.srem(name, data_key)
        else:
            raise Exception("unsupported data_type for delete, %s" % data_type)
Example #6
0
    def set(self, data_type, ori_data_key, with_get=False, **kwargs):
        """
        parameters:
            with_get: returns original value if True, default is False
            cond: just set values if cond is met, just support redis/hash now
            nx: if just set value if the key does not exist, just support text/json and text/plain, with_get can't be used with nx
            strict: whether set the non-existed field to none, default is True, just support redis/hash
            redis/hash: fields: get fields, just support redis/hash

        content_types:
            text/json: data is dict object, serialize to text, and override all the values,  with_get == False: returns True, else: returns original value
            text/plain: data is str object, set directly, with_get == False: returns True, else: returns original value
            redis/hash: update_map/inc_map are optional, will update specified fields, with_get == False: returns True if any update is not empty, else: returns original value
            redis/set: data_key is set value, with_get == False, returns True, else returns if existed
        """
        #logging.debug("redis set", data_type, ori_data_key, with_get, kwargs)
        data_key = copy.deepcopy(ori_data_key)
        if not self._enabled:
            return None

        name, content_type, enabled = self._prepare_op(data_type, data_key)
        if not enabled:
            return None

        parameters = RedisClient._get_parameters("set", content_type, **kwargs)

        if content_type == "text/json":
            data = parameters["data"]
            nx = parameters["nx"]

            if data is None:
                raise Exception("data can't be null")
            if not isinstance(data, dict):
                raise Exception("text/json type data before dumps should be dict type")
            data = misc.dumps_jsonx(data)
            if nx and with_get:
                raise Exception("nx can't be used with with_get")

            if not with_get:
                if nx:
                    return self._client.setnx(name, data)
                else:
                    return self._client.set(name, data)
            else:
                data = self._client.getset(name, data)
                return self._load_json_object(data)
        elif content_type == "text/plain":
            data = parameters["data"]
            nx = parameters["nx"]

            if not isinstance(data, str):
                data = encode_string(data)
                if data is None:
                    raise Exception("redis set value must be str, %s, %s, %s" % (data_type, data_key, type(data)))
            if nx and with_get:
                raise Exception("nx can't be used with with_get")

            if not with_get:
                if nx:
                    return self._client.setnx(name, data)
                else:
                    return self._client.set(name, data)
            else:
                return self._client.getset(name, data)
        elif content_type == "redis/hash":
            return self._set_hash(data_type, name, parameters["update_map"], parameters["inc_map"], with_get, parameters["fields"], parameters["strict"], parameters["cond"])
        elif content_type == "redis/set":
            if not isinstance(data_key, str):
                data_key = encode_string(data_key)
                if data_key is None:
                    raise Exception("data_key must be str, %s" % data_key)

            existed = self._client.sadd(name, data_key) == 0
            if not with_get:
                return True
            else:
                return existed
        else:
            raise Exception("unsupported data_type for set, %s" % data_type)