ZADD key score member [score member ...] Adds members with scores to a sorted index. The "key" is the sorted index name. Each score/member pair is inserted by writing to the underlying KV collection (which triggers sorted index auto-maintenance). For RESP compatibility, ZADD dispatches a KV PUT with the score embedded in the value, which auto-updates the sorted index.
(
cmd: &RespCommand,
session: &RespSession,
state: &SharedState,
)
| 27 | /// For RESP compatibility, ZADD dispatches a KV PUT with the score embedded |
| 28 | /// in the value, which auto-updates the sorted index. |
| 29 | pub(super) async fn handle_zadd( |
| 30 | cmd: &RespCommand, |
| 31 | session: &RespSession, |
| 32 | state: &SharedState, |
| 33 | ) -> RespValue { |
| 34 | // ZADD needs at least: key score member |
| 35 | if cmd.argc() < 3 || !cmd.argc().is_multiple_of(2) { |
| 36 | return RespValue::err("ERR wrong number of arguments for 'zadd' command"); |
| 37 | } |
| 38 | |
| 39 | // In RESP mode, the sorted index name = session.collection. |
| 40 | // The args are: score1 member1 [score2 member2 ...] |
| 41 | let index_name = session.collection.clone(); |
| 42 | let mut added = 0i64; |
| 43 | |
| 44 | let mut i = 0; |
| 45 | while i + 1 < cmd.argc() { |
| 46 | let score_str = match cmd.arg_str(i) { |
| 47 | Some(s) => s, |
| 48 | None => return RespValue::err("ERR value is not a valid float"), |
| 49 | }; |
| 50 | let score: f64 = match score_str.parse() { |
| 51 | Ok(v) => v, |
| 52 | Err(_) => return RespValue::err("ERR value is not a valid float"), |
| 53 | }; |
| 54 | let member = cmd.args[i + 1].clone(); |
| 55 | |
| 56 | // Write to the underlying KV collection as a MessagePack document |
| 57 | // containing the score and member. The sorted index auto-maintenance |
| 58 | // in KvEngine::put will update the order-statistic tree. |
| 59 | let value = nodedb_types::json_to_msgpack(&serde_json::json!({ |
| 60 | "score": score, |
| 61 | "member": String::from_utf8_lossy(&member), |
| 62 | })) |
| 63 | .unwrap_or_default(); |
| 64 | |
| 65 | let surrogate = match state.surrogate_assigner.assign(&index_name, &member) { |
| 66 | Ok(s) => s, |
| 67 | Err(e) => return RespValue::err(format!("ERR {e}")), |
| 68 | }; |
| 69 | let plan = PhysicalPlan::Kv(KvOp::Put { |
| 70 | collection: index_name.clone(), |
| 71 | key: member, |
| 72 | value, |
| 73 | ttl_ms: 0, |
| 74 | surrogate, |
| 75 | }); |
| 76 | |
| 77 | match dispatch_kv_write(state, session, plan).await { |
| 78 | Ok(_) => added += 1, |
| 79 | Err(e) => return RespValue::err(format!("ERR {e}")), |
| 80 | } |
| 81 | |
| 82 | i += 2; |
| 83 | } |
| 84 | |
| 85 | RespValue::integer(added) |
| 86 | } |
no test coverage detected