Skip to main content

glide/commands/
set.rs

1// Copyright Valkey GLIDE Project Contributors - SPDX Identifier: Apache-2.0
2//! Set commands. Mirrors Python's set command surface.
3
4use crate::ValkeyResult;
5use crate::cmd::Cmd;
6use crate::executor::CommandExecutor;
7use crate::value::FromValkeyValue;
8use crate::value::ValkeyValue;
9use crate::write::ToValkeyArgs;
10use async_trait::async_trait;
11use bytes::Bytes;
12use std::collections::HashSet;
13
14fn collect_bytes(v: ValkeyValue) -> ValkeyResult<Vec<Bytes>> {
15    match v {
16        ValkeyValue::Array(items) => items
17            .into_iter()
18            .map(Bytes::from_owned_valkey_value)
19            .collect(),
20        ValkeyValue::Set(items) => items
21            .into_iter()
22            .map(Bytes::from_owned_valkey_value)
23            .collect(),
24        ValkeyValue::Nil => Ok(Vec::new()),
25        other => Ok(vec![Bytes::from_owned_valkey_value(other)?]),
26    }
27}
28
29/// Set commands (`SADD`, `SREM`, `SMEMBERS`, `SINTER`, ...).
30#[async_trait]
31pub trait SetCommands: CommandExecutor {
32    // TODO #7082: add a `spop` variant that takes a `count` (cf. `srandmember_multiple`),
33    // to match the other GLIDE clients.
34
35    /// Cardinality of the intersection of the given sets (`SINTERCARD`).
36    async fn sintercard<K: ToValkeyArgs + Send + Sync>(&self, keys: &[K]) -> ValkeyResult<i64> {
37        let mut cmd = Cmd::new();
38        cmd.arg("SINTERCARD").arg(keys.len());
39        for k in keys {
40            cmd.arg(k);
41        }
42        i64::from_owned_valkey_value(self.execute_command(cmd, None).await?)
43    }
44
45    /// Cardinality of the intersection of the given sets with a `LIMIT`
46    /// (`SINTERCARD numkeys key [key ...] LIMIT limit`). A `limit` of `0` means
47    /// no limit.
48    async fn sintercard_limit<K: ToValkeyArgs + Send + Sync>(
49        &self,
50        keys: &[K],
51        limit: i64,
52    ) -> ValkeyResult<i64> {
53        let mut cmd = Cmd::new();
54        cmd.arg("SINTERCARD").arg(keys.len());
55        for k in keys {
56            cmd.arg(k);
57        }
58        cmd.arg("LIMIT").arg(limit);
59        i64::from_owned_valkey_value(self.execute_command(cmd, None).await?)
60    }
61
62    #[doc(hidden)]
63    async fn set_op<K: ToValkeyArgs + Send + Sync>(
64        &self,
65        op: &'static str,
66        keys: &[K],
67    ) -> ValkeyResult<HashSet<Bytes>> {
68        let mut cmd = Cmd::new();
69        cmd.arg(op);
70        for k in keys {
71            cmd.arg(k);
72        }
73        Ok(collect_bytes(self.execute_command(cmd, None).await?)?
74            .into_iter()
75            .collect())
76    }
77
78    #[doc(hidden)]
79    async fn set_op_store<D: ToValkeyArgs + Send, K: ToValkeyArgs + Send + Sync>(
80        &self,
81        op: &'static str,
82        destination: D,
83        keys: &[K],
84    ) -> ValkeyResult<i64> {
85        let mut cmd = Cmd::new();
86        cmd.arg(op).arg(destination);
87        for k in keys {
88            cmd.arg(k);
89        }
90        i64::from_owned_valkey_value(self.execute_command(cmd, None).await?)
91    }
92}
93
94impl<T: CommandExecutor + ?Sized> SetCommands for T {}