1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
//! Abstraction of HGET command.
//!
//! For general information about this command, see the [Redis documentation](<https://redis.io/commands/hget/>).
//!
//! # Using command object
//! ```
//!# use core::str::FromStr;
//!# use embedded_nal::SocketAddr;
//!# use std_embedded_nal::Stack;
//!# use std_embedded_time::StandardClock;
//!# use embedded_redis::commands::builder::CommandBuilder;
//!# use embedded_redis::commands::hget::HashGetCommand;
//!# use embedded_redis::network::ConnectionHandler;
//!#
//! let mut stack = Stack::default();
//! let clock = StandardClock::default();
//!
//! let mut connection_handler = ConnectionHandler::resp2(SocketAddr::from_str("127.0.0.1:6379").unwrap());
//! let client = connection_handler.connect(&mut stack, Some(&clock)).unwrap();
//! client.hset("test_hash", "color", "green").unwrap().wait().unwrap();
//!
//! let command = HashGetCommand::new("test_hash", "color");
//! let response = client.send(command).unwrap().wait().unwrap().unwrap();
//!
//! assert_eq!("green", response.as_str().unwrap())
//! ```
//!
//! # Missing key or field
//! In case key or field is missing. [None] is returned.
//! ```
//!# use core::str::FromStr;
//!# use embedded_nal::SocketAddr;
//!# use std_embedded_nal::Stack;
//!# use std_embedded_time::StandardClock;
//!# use embedded_redis::commands::builder::CommandBuilder;
//!# use embedded_redis::commands::hget::HashGetCommand;
//!# use embedded_redis::network::ConnectionHandler;
//!#
//!# let mut stack = Stack::default();
//!# let clock = StandardClock::default();
//!#
//!# let mut connection_handler = ConnectionHandler::resp2(SocketAddr::from_str("127.0.0.1:6379").unwrap());
//!# let client = connection_handler.connect(&mut stack, Some(&clock)).unwrap();
//!#
//! let command = HashGetCommand::new("not_existing", "field");
//! let response = client.send(command).unwrap().wait().unwrap();
//!
//! assert!(response.is_none())
//! ```
//!
//! # Shorthand
//! [Client](Client#method.hget) provides a shorthand method for this command.
//! ```
//!# use core::str::FromStr;
//!# use bytes::Bytes;
//!# use embedded_nal::SocketAddr;
//!# use std_embedded_nal::Stack;
//!# use std_embedded_time::StandardClock;
//!# use embedded_redis::commands::hset::HashSetCommand;
//!# use embedded_redis::network::ConnectionHandler;
//!#
//!# let mut stack = Stack::default();
//!# let clock = StandardClock::default();
//!#
//!# let mut connection_handler = ConnectionHandler::resp2(SocketAddr::from_str("127.0.0.1:6379").unwrap());
//!# let client = connection_handler.connect(&mut stack, Some(&clock)).unwrap();
//!#
//!# let _ = client.send(HashSetCommand::new("hash_key", "hash_field", "example")).unwrap().wait();
//!#
//! // Using &str arguments
//! let response = client.hget("hash_key", "hash_field").unwrap().wait().unwrap().unwrap();
//! assert_eq!("example", response.as_str().unwrap());
//!
//! // Using String arguments
//! let _ = client.hget("hash_key".to_string(), "hash_field".to_string());
//!
//! // Using Bytes arguments
//! let _ = client.hget(Bytes::from_static(b"hash_key"), Bytes::from_static(b"hash_field"));
//! ```
use crate::commands::auth::AuthCommand;
use crate::commands::builder::{CommandBuilder, IsNullFrame, ToStringBytes};
use crate::commands::get::GetResponse;
use crate::commands::hello::HelloCommand;
use crate::commands::{Command, ResponseTypeError};
use crate::network::protocol::Protocol;
use crate::network::{Client, CommandErrors, Future};
use bytes::Bytes;
use embedded_nal::TcpClientStack;
use embedded_time::Clock;

/// Abstraction for HGET command
pub struct HashGetCommand {
    /// Hash key
    key: Bytes,

    /// Hash field to receive
    field: Bytes,
}

impl HashGetCommand {
    pub fn new<K, F>(key: K, field: F) -> Self
    where
        Bytes: From<K>,
        Bytes: From<F>,
    {
        Self {
            key: key.into(),
            field: field.into(),
        }
    }
}

impl<F> Command<F> for HashGetCommand
where
    F: From<CommandBuilder> + IsNullFrame + ToStringBytes,
{
    type Response = Option<GetResponse>;

    fn encode(&self) -> F {
        CommandBuilder::new("HGET").arg(&self.key).arg(&self.field).into()
    }

    fn eval_response(&self, frame: F) -> Result<Self::Response, ResponseTypeError> {
        GetResponse::from_frame(frame)
    }
}

impl<'a, N: TcpClientStack, C: Clock, P: Protocol> Client<'a, N, C, P>
where
    AuthCommand: Command<<P as Protocol>::FrameType>,
    HelloCommand: Command<<P as Protocol>::FrameType>,
{
    /// Shorthand for [HashGetCommand]
    pub fn hget<K, F>(
        &'a self,
        key: K,
        field: F,
    ) -> Result<Future<'a, N, C, P, HashGetCommand>, CommandErrors>
    where
        <P as Protocol>::FrameType: ToStringBytes,
        <P as Protocol>::FrameType: IsNullFrame,
        <P as Protocol>::FrameType: From<CommandBuilder>,
        Bytes: From<K>,
        Bytes: From<F>,
    {
        self.send(HashGetCommand::new(key, field))
    }
}