Repository: cunla/fakeredis-py

Issue:
issue with `ZRANGE` and `ZRANGESTORE` with `BYLEX`.
**Describe the bug**
`BYLEX` does not work as expected. See `test_zrangestore`:
```python
    # TODO: fix
assert r.zrange("a", "[a2", "(a3", bylex=True, offset=0, num=1) == [b"a2"]
assert r.zrangestore("b", "a", "[a2", "(a3", bylex=True, offset=0, num=1)
assert r.zrange("b", 0, -1) == [b"a2"]
```


Discussion:

Patch:
diff --git a/fakeredis/_commands.py b/fakeredis/_commands.py
index 3d2ef57..1d25e0d 100644
--- a/fakeredis/_commands.py
+++ b/fakeredis/_commands.py
@@ -238,6 +238,9 @@ class BeforeAny:
     def __eq__(self, other):
         return isinstance(other, BeforeAny)
 
+    def __hash__(self):
+        return 1
+
 
 @functools.total_ordering
 class AfterAny:
@@ -247,6 +250,9 @@ class AfterAny:
     def __eq__(self, other):
         return isinstance(other, AfterAny)
 
+    def __hash__(self):
+        return 1
+
 
 class ScoreTest:
     """Argument converter for sorted set score endpoints."""
diff --git a/fakeredis/_zset.py b/fakeredis/_zset.py
index 2a7c090..c6c22d2 100644
--- a/fakeredis/_zset.py
+++ b/fakeredis/_zset.py
@@ -74,8 +74,10 @@ class ZSet:
     def irange_lex(self, start, stop, inclusive=(True, True), reverse=False):
         if not self._byscore:
             return iter([])
-        score = self._byscore[0][0]
-        it = self._byscore.irange((score, start), (score, stop),
+        default_score = self._byscore[0][0]
+        start_score = self._bylex.get(start, default_score)
+        stop_score = self._bylex.get(stop, default_score)
+        it = self._byscore.irange((start_score, start), (stop_score, stop),
                                   inclusive=inclusive, reverse=reverse)
         return (item[1] for item in it)
 


Test patch:
diff --git a/test/test_mixins/test_sortedset_commands.py b/test/test_mixins/test_sortedset_commands.py
index 6350a26..daecdee 100644
--- a/test/test_mixins/test_sortedset_commands.py
+++ b/test/test_mixins/test_sortedset_commands.py
@@ -1164,10 +1164,9 @@ def test_zrangestore(r: redis.Redis):
     assert r.zrangestore("b", "a", 2, 1, byscore=True, offset=0, num=1, desc=True)
     assert r.zrange("b", 0, -1) == [b"a2"]
     # by lex
-    # TODO: fix
-    # assert r.zrange("a", "[a2", "(a3", bylex=True, offset=0, num=1) == [b"a2"]
-    # assert r.zrangestore("b", "a", "[a2", "(a3", bylex=True, offset=0, num=1)
-    # assert r.zrange("b", 0, -1) == [b"a2"]
+    assert r.zrange("a", "[a2", "(a3", bylex=True, offset=0, num=1) == [b"a2"]
+    assert r.zrangestore("b", "a", "[a2", "(a3", bylex=True, offset=0, num=1)
+    assert r.zrange("b", 0, -1) == [b"a2"]
 
 
 @pytest.mark.min_server('7')
diff --git a/test/test_mixins/test_transactions_commands.py b/test/test_mixins/test_transactions_commands.py
index d1abe26..27399b9 100644
--- a/test/test_mixins/test_transactions_commands.py
+++ b/test/test_mixins/test_transactions_commands.py
@@ -318,6 +318,7 @@ def test_get_within_pipeline(r: redis.Redis):
         p.watch("test")
         assert set(r.keys()) == expected_keys
 
+
 @pytest.mark.fake
 def test_get_within_pipeline_w_host():
     r = fakeredis.FakeRedis('localhost')
@@ -329,6 +330,7 @@ def test_get_within_pipeline_w_host():
         p.watch("test")
         assert set(r.keys()) == expected_keys
 
+
 @pytest.mark.fake
 def test_get_within_pipeline_no_args():
     r = fakeredis.FakeRedis()