@@ -5,57 +5,127 @@ use bytes::Bytes;
55use std:: time:: Duration ;
66use tracing:: { debug, instrument} ;
77
8+ /// Set `key` to hold the string `value`.
9+ ///
10+ /// If `key` already holds a value, it is overwritten, regardless of its type.
11+ /// Any previous time to live associated with the key is discarded on successful
12+ /// SET operation.
13+ ///
14+ /// # Options
15+ ///
16+ /// Currently, the following options are supported:
17+ ///
18+ /// * EX `seconds` -- Set the specified expire time, in seconds.
19+ /// * PX `milliseconds` -- Set the specified expire time, in milliseconds.
820#[ derive( Debug ) ]
921pub struct Set {
1022 /// the lookup key
11- pub ( crate ) key : String ,
23+ key : String ,
1224
1325 /// the value to be stored
14- pub ( crate ) value : Bytes ,
26+ value : Bytes ,
1527
1628 /// When to expire the key
17- pub ( crate ) expire : Option < Duration > ,
29+ expire : Option < Duration > ,
1830}
1931
2032impl Set {
21- #[ instrument]
22- pub ( crate ) fn parse_frames ( parse : & mut Parse ) -> Result < Set , ParseError > {
33+ /// Create a new `Set` command which sets `key` to `value`.
34+ ///
35+ /// If `expire` is `Some`, the value should expire after the specified
36+ /// duration.
37+ pub ( crate ) fn new ( key : impl ToString , value : Bytes , expire : Option < Duration > ) -> Set {
38+ Set {
39+ key : key. to_string ( ) ,
40+ value,
41+ expire,
42+ }
43+ }
44+
45+ /// Parse a `Set` instance from received data.
46+ ///
47+ /// The `Parse` argument provides a cursor like API to read fields from a
48+ /// received `Frame`. At this point, the data has already been received from
49+ /// the socket.
50+ ///
51+ /// The `SET` string has already been consumed.
52+ ///
53+ /// # Returns
54+ ///
55+ /// Returns the `Set` value on success. If the frame is malformed, `Err` is
56+ /// returned.
57+ ///
58+ /// # Format
59+ ///
60+ /// Expects an array frame containing at least 3 entries.
61+ ///
62+ /// ```text
63+ /// SET key value [EX seconds|PX milliseconds]
64+ /// ```
65+ pub ( crate ) fn parse_frames ( parse : & mut Parse ) -> crate :: Result < Set > {
2366 use ParseError :: EndOfStream ;
2467
68+ // Read the key to set. This is a required field
2569 let key = parse. next_string ( ) ?;
70+
71+ // Read the value to set. This is a required field.
2672 let value = parse. next_bytes ( ) ?;
73+
74+ // The expiration is optional. If nothing else follows, then it is
75+ // `None`.
2776 let mut expire = None ;
2877
78+ // Attempt to parse another string.
2979 match parse. next_string ( ) {
3080 Ok ( s) if s == "EX" => {
81+ // An expiration is specified in seconds. The next value is an
82+ // integer.
3183 let secs = parse. next_int ( ) ?;
3284 expire = Some ( Duration :: from_secs ( secs) ) ;
3385 }
3486 Ok ( s) if s == "PX" => {
87+ // An expiration is specified in milliseconds. The next value is
88+ // an integer.
3589 let ms = parse. next_int ( ) ?;
3690 expire = Some ( Duration :: from_millis ( ms) ) ;
3791 }
38- Ok ( _) => unimplemented ! ( ) ,
92+ // Currently, mini-redis does not support any of the other SET
93+ // options. An error here results in the connection being
94+ // terminated. Other connections will continue to operate normally.
95+ Ok ( _) => return Err ( "currently `SET` only supports the expiration option" . into ( ) ) ,
96+ // The `EndOfStream` error indicates there is no further data to
97+ // parse. In this case, it is a normal run time situation and
98+ // indicates there are no specified `SET` options.
3999 Err ( EndOfStream ) => { }
40- Err ( err) => return Err ( err) ,
100+ // All other errors are bubbled up, resulting in the connection
101+ // being terminated.
102+ Err ( err) => return Err ( err. into ( ) ) ,
41103 }
42104
43- debug ! ( ?key, ?value, ?expire) ;
44-
45105 Ok ( Set { key, value, expire } )
46106 }
47107
48- #[ instrument( skip( db) ) ]
108+ /// Apply the `Get` command to the specified `Db` instace.
109+ ///
110+ /// The response is written to `dst`. This is called by the server in order
111+ /// to execute a received command.
112+ #[ instrument( skip( self , db, dst) ) ]
49113 pub ( crate ) async fn apply ( self , db : & Db , dst : & mut Connection ) -> crate :: Result < ( ) > {
50- // Set the value
114+ // Set the value in the shared database state.
51115 db. set ( self . key , self . value , self . expire ) ;
52116
117+ // Create a success response and write it to `dst`.
53118 let response = Frame :: Simple ( "OK" . to_string ( ) ) ;
54119 debug ! ( ?response) ;
55120 dst. write_frame ( & response) . await ?;
121+
56122 Ok ( ( ) )
57123 }
58124
125+ /// Converts the command into an equivalent `Frame`.
126+ ///
127+ /// This is called by the client when encoding a `Set` command to send to
128+ /// the server.
59129 pub ( crate ) fn into_frame ( self ) -> Frame {
60130 let mut frame = Frame :: array ( ) ;
61131 frame. push_bulk ( Bytes :: from ( "set" . as_bytes ( ) ) ) ;
0 commit comments