Coverage Report

Created: 2026-02-23 10:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/build/source/nativelink-store/src/redis_utils/ft_cursor_read.rs
Line
Count
Source
1
// Copyright 2025 The NativeLink Authors. All rights reserved.
2
//
3
// Licensed under the Functional Source License, Version 1.1, Apache 2.0 Future License (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//    See LICENSE file for details
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
use redis::aio::ConnectionLike;
16
use redis::{ErrorKind, RedisError, Value};
17
18
use crate::redis_utils::aggregate_types::RedisCursorData;
19
20
0
pub(crate) async fn ft_cursor_read<C>(
21
0
    connection_manager: &mut C,
22
0
    index: String,
23
0
    cursor_id: u64,
24
0
) -> Result<RedisCursorData, RedisError>
25
0
where
26
0
    C: ConnectionLike + Send,
27
0
{
28
0
    let mut cmd = redis::cmd("ft.cursor");
29
0
    let ft_cursor_cmd = cmd.arg("read").arg(index).cursor_arg(cursor_id);
30
0
    let data = ft_cursor_cmd
31
0
        .to_owned()
32
0
        .query_async::<Value>(connection_manager)
33
0
        .await?;
34
0
    let Value::Array(value) = data else {
  Branch (34:9): [True: 0, False: 0]
  Branch (34:9): [Folded - Ignored]
  Branch (34:9): [Folded - Ignored]
  Branch (34:9): [True: 0, False: 0]
  Branch (34:9): [True: 0, False: 0]
35
0
        return Err(RedisError::from((ErrorKind::Parse, "Expected array")));
36
    };
37
0
    if value.len() < 2 {
  Branch (37:8): [True: 0, False: 0]
  Branch (37:8): [Folded - Ignored]
  Branch (37:8): [Folded - Ignored]
  Branch (37:8): [True: 0, False: 0]
  Branch (37:8): [True: 0, False: 0]
38
0
        return Err(RedisError::from((
39
0
            ErrorKind::Parse,
40
0
            "Expected at least 2 elements",
41
0
        )));
42
0
    }
43
0
    let mut value = value.into_iter();
44
0
    let Value::Array(data_ary) = value.next().unwrap() else {
  Branch (44:9): [True: 0, False: 0]
  Branch (44:9): [Folded - Ignored]
  Branch (44:9): [Folded - Ignored]
  Branch (44:9): [True: 0, False: 0]
  Branch (44:9): [True: 0, False: 0]
45
0
        return Err(RedisError::from((ErrorKind::Parse, "Non map item")));
46
    };
47
0
    if data_ary.is_empty() {
  Branch (47:8): [True: 0, False: 0]
  Branch (47:8): [Folded - Ignored]
  Branch (47:8): [Folded - Ignored]
  Branch (47:8): [True: 0, False: 0]
  Branch (47:8): [True: 0, False: 0]
48
0
        return Err(RedisError::from((
49
0
            ErrorKind::Parse,
50
0
            "Expected at least 1 element in data array",
51
0
        )));
52
0
    }
53
0
    let Value::Int(new_cursor_id) = value.next().unwrap() else {
  Branch (53:9): [True: 0, False: 0]
  Branch (53:9): [Folded - Ignored]
  Branch (53:9): [Folded - Ignored]
  Branch (53:9): [True: 0, False: 0]
  Branch (53:9): [True: 0, False: 0]
54
0
        return Err(RedisError::from((
55
0
            ErrorKind::Parse,
56
0
            "Expected cursor id as second element",
57
0
        )));
58
    };
59
60
0
    Ok(RedisCursorData {
61
0
        // this should generally be impossible, but -1 provides a decent "obviously bad" value just in case
62
0
        total: i64::try_from(data_ary.len()).unwrap_or(-1),
63
0
        cursor: new_cursor_id as u64,
64
0
        data: data_ary.into(),
65
0
    })
66
0
}