Skip to content

Commit

Permalink
Timeseries cmds (#310)
Browse files Browse the repository at this point in the history
  • Loading branch information
cunla authored Aug 6, 2024
1 parent cd58a7c commit 65ec1f6
Show file tree
Hide file tree
Showing 15 changed files with 1,718 additions and 39 deletions.
10 changes: 5 additions & 5 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ on:
push:
branches:
- master
pull_request_target:
pull_request:
branches:
- master

Expand Down Expand Up @@ -55,17 +55,17 @@ jobs:
max-parallel: 8
fail-fast: false
matrix:
redis-image: [ "redis:6.2.14", "redis:7.0.15", "redis:7.2.4" ]
redis-image: [ "redis:6.2.14", "redis:7.0.15", "redis:7.2.5", "redis:7.4.0" ]
python-version: [ "3.8", "3.9", "3.10", "3.11", "3.12" ]
redis-py: [ "4.3.6", "4.6.0", "5.0.8", "5.1.0b7" ]
redis-py: ["4.6.0", "5.0.8", "5.1.0b7" ]
include:
- python-version: "3.12"
redis-image: "redis/redis-stack:6.2.6-v13"
redis-image: "redis/redis-stack:6.2.6-v15"
redis-py: "5.0.8"
extra: true # json, bf, lupa, cf
hypothesis: true
- python-version: "3.12"
redis-image: "redis/redis-stack-server:7.2.0-v9"
redis-image: "redis/redis-stack-server:7.2.0-v11"
redis-py: "5.0.8"
extra: true # json, bf, lupa, cf
coverage: true
Expand Down
6 changes: 6 additions & 0 deletions docs/about/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ title: Change log
description: Change log of all fakeredis releases
---

## v2.24.0

### 🚀 Features

- Support for TIME SERIES commands (no support for align arguments on some commands) #310

## v2.23.5

### 🐛 Bug Fixes
Expand Down
10 changes: 5 additions & 5 deletions docs/redis-commands/Redis.md
Original file line number Diff line number Diff line change
Expand Up @@ -512,7 +512,11 @@ Enables read-only queries for a connection to a Redis Cluster replica node.
Enables read-write queries for a connection to a Reids Cluster replica node.


## `connection` commands (3/25 implemented)
## `connection` commands (4/25 implemented)

### [CLIENT SETINFO](https://redis.io/commands/client-setinfo/)

Sets information specific to the client or connection.

### [ECHO](https://redis.io/commands/echo/)

Expand Down Expand Up @@ -582,10 +586,6 @@ Suspends commands processing.

Instructs the server whether to reply to commands.

#### [CLIENT SETINFO](https://redis.io/commands/client-setinfo/) <small>(not implemented)</small>

Sets information specific to the client or connection.

#### [CLIENT SETNAME](https://redis.io/commands/client-setname/) <small>(not implemented)</small>

Sets the connection name.
Expand Down
41 changes: 19 additions & 22 deletions docs/redis-commands/RedisTimeSeries.md
Original file line number Diff line number Diff line change
@@ -1,77 +1,74 @@
# Time Series commands

Module currently not implemented in fakeredis.
## `timeseries` commands (17/17 implemented)


### Unsupported timeseries commands
> To implement support for a command, see [here](../../guides/implement-command/)
#### [TS.CREATE](https://redis.io/commands/ts.create/) <small>(not implemented)</small>
### [TS.CREATE](https://redis.io/commands/ts.create/)

Create a new time series

#### [TS.DEL](https://redis.io/commands/ts.del/) <small>(not implemented)</small>
### [TS.DEL](https://redis.io/commands/ts.del/)

Delete all samples between two timestamps for a given time series

#### [TS.ALTER](https://redis.io/commands/ts.alter/) <small>(not implemented)</small>
### [TS.ALTER](https://redis.io/commands/ts.alter/)

Update the retention, chunk size, duplicate policy, and labels of an existing time series

#### [TS.ADD](https://redis.io/commands/ts.add/) <small>(not implemented)</small>
### [TS.ADD](https://redis.io/commands/ts.add/)

Append a sample to a time series

#### [TS.MADD](https://redis.io/commands/ts.madd/) <small>(not implemented)</small>
### [TS.MADD](https://redis.io/commands/ts.madd/)

Append new samples to one or more time series

#### [TS.INCRBY](https://redis.io/commands/ts.incrby/) <small>(not implemented)</small>
### [TS.INCRBY](https://redis.io/commands/ts.incrby/)

Increase the value of the sample with the maximum existing timestamp, or create a new sample with a value equal to the value of the sample with the maximum existing timestamp with a given increment

#### [TS.DECRBY](https://redis.io/commands/ts.decrby/) <small>(not implemented)</small>
### [TS.DECRBY](https://redis.io/commands/ts.decrby/)

Decrease the value of the sample with the maximum existing timestamp, or create a new sample with a value equal to the value of the sample with the maximum existing timestamp with a given decrement

#### [TS.CREATERULE](https://redis.io/commands/ts.createrule/) <small>(not implemented)</small>
### [TS.CREATERULE](https://redis.io/commands/ts.createrule/)

Create a compaction rule

#### [TS.DELETERULE](https://redis.io/commands/ts.deleterule/) <small>(not implemented)</small>
### [TS.DELETERULE](https://redis.io/commands/ts.deleterule/)

Delete a compaction rule

#### [TS.RANGE](https://redis.io/commands/ts.range/) <small>(not implemented)</small>
### [TS.RANGE](https://redis.io/commands/ts.range/)

Query a range in forward direction

#### [TS.REVRANGE](https://redis.io/commands/ts.revrange/) <small>(not implemented)</small>
### [TS.REVRANGE](https://redis.io/commands/ts.revrange/)

Query a range in reverse direction

#### [TS.MRANGE](https://redis.io/commands/ts.mrange/) <small>(not implemented)</small>
### [TS.MRANGE](https://redis.io/commands/ts.mrange/)

Query a range across multiple time series by filters in forward direction

#### [TS.MREVRANGE](https://redis.io/commands/ts.mrevrange/) <small>(not implemented)</small>
### [TS.MREVRANGE](https://redis.io/commands/ts.mrevrange/)

Query a range across multiple time-series by filters in reverse direction

#### [TS.GET](https://redis.io/commands/ts.get/) <small>(not implemented)</small>
### [TS.GET](https://redis.io/commands/ts.get/)

Get the sample with the highest timestamp from a given time series

#### [TS.MGET](https://redis.io/commands/ts.mget/) <small>(not implemented)</small>
### [TS.MGET](https://redis.io/commands/ts.mget/)

Get the sample with the highest timestamp from each time series matching a specific filter

#### [TS.INFO](https://redis.io/commands/ts.info/) <small>(not implemented)</small>
### [TS.INFO](https://redis.io/commands/ts.info/)

Returns information and statistics for a time series

#### [TS.QUERYINDEX](https://redis.io/commands/ts.queryindex/) <small>(not implemented)</small>
### [TS.QUERYINDEX](https://redis.io/commands/ts.queryindex/)

Get all time series keys matching a filter list



16 changes: 16 additions & 0 deletions fakeredis/_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import functools
import math
import re
import sys
import time
from typing import Tuple, Union, Optional, Any, Type, List, Callable, Sequence, Dict, Set

from . import _msgs as msgs
Expand Down Expand Up @@ -469,3 +471,17 @@ def fix_range_string(start: int, end: int, length: int) -> Tuple[int, int]:
end = max(0, end + length)
end = min(end, length - 1)
return start, end + 1


class Timestamp(Int):
"""Argument converter for timestamps"""

@classmethod
def decode(cls, value: bytes, decode_error: Optional[str] = None) -> int:
if value == b"*":
return int(time.time())
if value == b"-":
return -1
if value == b"+":
return sys.maxsize
return super().decode(value, decode_error=msgs.INVALID_EXPIRE_MSG)
2 changes: 2 additions & 0 deletions fakeredis/_fakesocket.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
CMSCommandsMixin,
TopkCommandsMixin,
TDigestCommandsMixin,
TimeSeriesCommandsMixin,
)
from ._server import FakeServer
from ._basefakesocket import BaseFakeSocket
Expand Down Expand Up @@ -58,6 +59,7 @@ class FakeSocket(
CMSCommandsMixin,
TopkCommandsMixin,
TDigestCommandsMixin,
TimeSeriesCommandsMixin,
):
def __init__(
self,
Expand Down
29 changes: 25 additions & 4 deletions fakeredis/_msgs.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,6 @@
"ERR The XGROUP subcommand requires the key to exist."
" Note that for CREATE you may want to use the MKSTREAM option to create an empty stream automatically."
)
FLAG_NO_SCRIPT = "s" # Command not allowed in scripts
FLAG_LEAVE_EMPTY_VAL = "v"
FLAG_TRANSACTION = "t"
FLAG_DO_NOT_CREATE = "i"
GEO_UNSUPPORTED_UNIT = "unsupported unit provided. please use M, KM, FT, MI"
LPOS_RANK_CAN_NOT_BE_ZERO = (
"RANK can't be zero: use 1 to start from the first match, 2 from the second ... "
Expand All @@ -93,8 +89,33 @@
)
INVALID_OVERFLOW_TYPE = "ERR Invalid OVERFLOW type specified"

# TDigest error messages
TDIGEST_KEY_EXISTS = "T-Digest: key already exists"
TDIGEST_KEY_NOT_EXISTS = "T-Digest: key does not exist"
TDIGEST_ERROR_PARSING_VALUE = "T-Digest: error parsing val parameter"
TDIGEST_BAD_QUANTILE = "T-Digest: quantile should be in [0,1]"
TDIGEST_BAD_RANK = "T-Digest: rank needs to be non negative"

# TimeSeries error messages
TIMESERIES_KEY_EXISTS = "TSDB: key already exists"
TIMESERIES_INVALID_DUPLICATE_POLICY = "TSDB: Unknown DUPLICATE_POLICY"
TIMESERIES_KEY_DOES_NOT_EXIST = "TSDB: the key does not exist"
TIMESERIES_RULE_EXISTS = "TSDB: the destination key already has a src rule"
TIMESERIES_BAD_AGGREGATION_TYPE = "TSDB: Unknown aggregation type"
TIMESERIES_INVALID_TIMESTAMP = "TSDB: invalid timestamp"
TIMESERIES_TIMESTAMP_OLDER_THAN_RETENTION = "TSDB: Timestamp is older than retention"
TIMESERIES_TIMESTAMP_LOWER_THAN_MAX_V7 = (
"TSDB: timestamp must be equal to or higher than the maximum existing timestamp"
)
TIMESERIES_TIMESTAMP_LOWER_THAN_MAX_V6 = "TSDB: for incrby/decrby, timestamp should be newer than the lastest one"
TIMESERIES_BAD_CHUNK_SIZE = "TSDB: CHUNK_SIZE value must be a multiple of 8 in the range [48 .. 1048576]"
TIMESERIES_DUPLICATE_POLICY_BLOCK = (
"TSDB: Error at upsert, update is not supported when DUPLICATE_POLICY is set to BLOCK mode"
)
TIMESERIES_BAD_FILTER_EXPRESSION = "TSDB: failed parsing labels"

# Command flags
FLAG_NO_SCRIPT = "s" # Command not allowed in scripts
FLAG_LEAVE_EMPTY_VAL = "v"
FLAG_TRANSACTION = "t"
FLAG_DO_NOT_CREATE = "i"
2 changes: 1 addition & 1 deletion fakeredis/commands.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions fakeredis/stack/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from ._tdigest_mixin import TDigestCommandsMixin
from ._timeseries_mixin import TimeSeriesCommandsMixin
from ._topk_mixin import TopkCommandsMixin # noqa: F401

try:
Expand Down Expand Up @@ -41,4 +42,5 @@ class CMSCommandsMixin: # type: ignore # noqa: E303
"CFCommandsMixin",
"CMSCommandsMixin",
"TDigestCommandsMixin",
"TimeSeriesCommandsMixin",
]
3 changes: 1 addition & 2 deletions fakeredis/stack/_json_mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,10 +167,9 @@ class JSONCommandsMixin:
ZSet: b"zset",
}

_db: helpers.Database

def __init__(self, *args: Any, **kwargs: Any) -> None:
super().__init__(*args, **kwargs)
self._db: helpers.Database

@staticmethod
def _get_single(
Expand Down
Loading

0 comments on commit 65ec1f6

Please sign in to comment.