1use yo_common::num::DIGITS_MAX;
59use yo_common::{Code, Error, Result};
60
61use crate::elem::Elements;
62use crate::keyspace::Keyspace;
63use crate::scan::Cursor;
64use crate::strings;
65use crate::value::{self, Kind};
66use crate::zset::{Added, Bound, Lex, Member, Zset};
67use crate::zsetops::{self, Aggregate, Op, Operand};
68
69#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
71pub enum Gate {
72 #[default]
74 Always,
75 IfMissing,
77 IfPresent,
79}
80
81#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
83pub enum Move {
84 #[default]
86 Any,
87 Up,
89 Down,
91}
92
93#[derive(Debug, Clone, Copy, Default)]
100pub struct ZAdd {
101 pub gate: Gate,
103 pub only: Move,
105 pub changed: bool,
107}
108
109#[derive(Debug, Clone, Copy, PartialEq, Eq)]
111pub enum From {
112 Min,
114 Max,
116}
117
118#[derive(Debug, Clone, Copy)]
120pub enum By<'a> {
121 Rank {
123 start: i64,
125 stop: i64,
127 },
128 Score {
130 min: Bound,
132 max: Bound,
134 },
135 Lex {
138 min: Lex<'a>,
140 max: Lex<'a>,
142 },
143}
144
145#[derive(Debug, Clone, Copy)]
152pub struct Query<'a> {
153 pub by: By<'a>,
155 pub rev: bool,
157 pub offset: usize,
159 pub count: Option<usize>,
162}
163
164impl<'a> Query<'a> {
165 #[must_use]
167 pub const fn rank(start: i64, stop: i64) -> Query<'a> {
168 Query {
169 by: By::Rank { start, stop },
170 rev: false,
171 offset: 0,
172 count: None,
173 }
174 }
175
176 #[must_use]
178 pub const fn score(min: Bound, max: Bound) -> Query<'a> {
179 Query {
180 by: By::Score { min, max },
181 rev: false,
182 offset: 0,
183 count: None,
184 }
185 }
186
187 #[must_use]
189 pub const fn lex(min: Lex<'a>, max: Lex<'a>) -> Query<'a> {
190 Query {
191 by: By::Lex { min, max },
192 rev: false,
193 offset: 0,
194 count: None,
195 }
196 }
197
198 #[must_use]
200 pub const fn rev(mut self, rev: bool) -> Query<'a> {
201 self.rev = rev;
202 self
203 }
204
205 #[must_use]
207 pub const fn limit(mut self, offset: usize, count: Option<usize>) -> Query<'a> {
208 self.offset = offset;
209 self.count = count;
210 self
211 }
212}
213
214#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
221pub struct Window {
222 pub from: usize,
224 pub count: usize,
226 pub rev: bool,
228}
229
230fn nan() -> Error {
232 Error::new(Code::Invalid, "resulting score is not a number (NaN)")
233}
234
235impl Keyspace {
236 pub fn zadd<'m, I>(&mut self, key: &[u8], pairs: I, opts: ZAdd) -> Result<usize>
246 where
247 I: Iterator<Item = (f64, &'m [u8])> + Clone,
248 {
249 for (score, m) in pairs.clone() {
250 strings::check_len(key, m.len())?;
251 if score.is_nan() {
252 return Err(nan());
253 }
254 }
255 let at = match self.zset_slot(key)? {
256 Some(at) => at,
257 None => {
258 if opts.gate == Gate::IfPresent || pairs.clone().next().is_none() {
264 return Ok(0);
265 }
266 self.new_zset(key)
267 }
268 };
269 let limits = self.zset_limits;
270 let z = self
271 .zsets
272 .get_mut(at)
273 .expect("the record points at its body");
274 let mut added = 0usize;
275 let mut changed = 0usize;
276 for (score, m) in pairs {
277 let Some(want) = gated(z, m, score, opts) else {
278 continue;
279 };
280 if z.add(m, score, &limits) == Added::Full {
283 continue;
284 }
285 match want {
286 Added::New => added += 1,
287 Added::Changed => changed += 1,
288 _ => {}
289 }
290 }
291 if z.is_empty() {
295 self.drop_key(key);
296 }
297 Ok(if opts.changed { added + changed } else { added })
298 }
299
300 pub fn zincrby(
309 &mut self,
310 key: &[u8],
311 member: &[u8],
312 by: f64,
313 opts: ZAdd,
314 ) -> Result<Option<f64>> {
315 strings::check_len(key, member.len())?;
316 if by.is_nan() {
317 return Err(nan());
318 }
319 let at = match self.zset_slot(key)? {
320 Some(at) => at,
321 None => {
322 if opts.gate == Gate::IfPresent {
323 return Ok(None);
324 }
325 self.new_zset(key)
326 }
327 };
328 let limits = self.zset_limits;
329 let z = self
330 .zsets
331 .get_mut(at)
332 .expect("the record points at its body");
333 let now = z.score(member);
334 let want = now.unwrap_or(0.0) + by;
335 if want.is_nan() {
338 if z.is_empty() {
339 self.drop_key(key);
340 }
341 return Err(nan());
342 }
343 let allowed = match (now, opts.gate, opts.only) {
344 (Some(_), Gate::IfMissing, _) | (None, Gate::IfPresent, _) => false,
345 (Some(was), _, Move::Up) => want > was,
346 (Some(was), _, Move::Down) => want < was,
347 _ => true,
348 };
349 if !allowed || z.add(member, want, &limits) == Added::Full {
350 if z.is_empty() {
351 self.drop_key(key);
352 }
353 return Ok(None);
354 }
355 Ok(Some(want))
356 }
357
358 pub fn zcard(&mut self, key: &[u8]) -> Result<usize> {
360 Ok(match self.zset_slot(key)? {
361 Some(at) => self.zset_at(at).len(),
362 None => 0,
363 })
364 }
365
366 pub fn zscore(&mut self, key: &[u8], member: &[u8]) -> Result<Option<f64>> {
368 Ok(match self.zset_slot(key)? {
369 Some(at) => self.zset_at(at).score(member),
370 None => None,
371 })
372 }
373
374 pub fn zmscore<'m>(
379 &mut self,
380 key: &[u8],
381 members: impl Iterator<Item = &'m [u8]>,
382 out: &mut Vec<Option<f64>>,
383 ) -> Result<()> {
384 out.clear();
385 let Some(at) = self.zset_slot(key)? else {
386 out.extend(members.map(|_| None));
387 return Ok(());
388 };
389 let z = self.zset_at(at);
390 out.extend(members.map(|m| z.score(m)));
391 Ok(())
392 }
393
394 pub fn zrem<'m>(
399 &mut self,
400 key: &[u8],
401 members: impl Iterator<Item = &'m [u8]>,
402 ) -> Result<usize> {
403 let Some(at) = self.zset_slot(key)? else {
404 return Ok(0);
405 };
406 let z = self
407 .zsets
408 .get_mut(at)
409 .expect("the record points at its body");
410 let mut gone = 0;
411 for m in members {
412 if z.remove(m) {
413 gone += 1;
414 }
415 }
416 if z.is_empty() {
417 self.drop_key(key);
418 }
419 Ok(gone)
420 }
421
422 pub fn zrank(&mut self, key: &[u8], member: &[u8], rev: bool) -> Result<Option<(usize, f64)>> {
427 let Some(at) = self.zset_slot(key)? else {
428 return Ok(None);
429 };
430 let z = self.zset_at(at);
431 let Some(rank) = z.rank(member) else {
432 return Ok(None);
433 };
434 let score = z.score(member).unwrap_or(0.0);
435 Ok(Some((if rev { z.len() - 1 - rank } else { rank }, score)))
436 }
437
438 pub fn zwindow(&mut self, key: &[u8], q: &Query<'_>) -> Result<Window> {
445 let Some(at) = self.zset_slot(key)? else {
446 return Ok(Window::default());
447 };
448 Ok(window(self.zset_at(at), q))
449 }
450
451 pub fn zwalk<F>(&mut self, key: &[u8], w: Window, f: F) -> Result<()>
457 where
458 F: FnMut(Member<'_>, f64),
459 {
460 let Some(at) = self.zset_slot(key)? else {
461 return Ok(());
462 };
463 self.zset_at(at).walk(w.from, w.count, w.rev, f);
464 Ok(())
465 }
466
467 pub fn zcount(&mut self, key: &[u8], q: &Query<'_>) -> Result<usize> {
469 Ok(self.zwindow(key, q)?.count)
470 }
471
472 pub fn zremrange(&mut self, key: &[u8], q: &Query<'_>) -> Result<usize> {
479 let Some(at) = self.zset_slot(key)? else {
480 return Ok(0);
481 };
482 let w = window(self.zset_at(at), q);
483 let z = self
484 .zsets
485 .get_mut(at)
486 .expect("the record points at its body");
487 let low = if w.rev { w.from + 1 - w.count } else { w.from };
490 for i in (0..w.count).rev() {
491 z.remove_at(low + i);
492 }
493 if z.is_empty() {
494 self.drop_key(key);
495 }
496 Ok(w.count)
497 }
498
499 pub fn zpop<F>(&mut self, key: &[u8], end: From, count: usize, mut f: F) -> Result<usize>
505 where
506 F: FnMut(Member<'_>, f64),
507 {
508 let Some(at) = self.zset_slot(key)? else {
509 return Ok(0);
510 };
511 let z = self
512 .zsets
513 .get_mut(at)
514 .expect("the record points at its body");
515 let count = count.min(z.len());
516 for _ in 0..count {
517 let rank = if end == From::Min { 0 } else { z.len() - 1 };
521 let Some((m, s)) = z.at(rank) else { break };
522 f(m, s);
523 z.remove_at(rank);
524 }
525 if z.is_empty() {
526 self.drop_key(key);
527 }
528 Ok(count)
529 }
530
531 pub fn zpop_one(&mut self, key: &[u8], end: From) -> Result<Option<(Vec<u8>, f64)>> {
538 let mut got = None;
539 let mut name = [0u8; yo_common::num::DIGITS_MAX];
540 self.zpop(key, end, 1, |m, s| {
541 got = Some((member_bytes(m, &mut name).to_vec(), s));
542 })?;
543 Ok(got)
544 }
545
546 pub fn zrandmember<F>(&mut self, key: &[u8], count: i64, mut f: F) -> Result<usize>
557 where
558 F: FnMut(Member<'_>, f64),
559 {
560 let Some(at) = self.zset_slot(key)? else {
561 return Ok(0);
562 };
563 let len = self.zset_at(at).len();
564 if len == 0 || count == 0 {
565 return Ok(0);
566 }
567 if count < 0 {
568 let want = count.unsigned_abs() as usize;
569 for _ in 0..want {
570 let pick = self.rng.below(len);
571 let Some((m, s)) = self.zset_at(at).pick(pick) else {
572 break;
573 };
574 f(m, s);
575 }
576 return Ok(want);
577 }
578 let want = (count as usize).min(len);
579 if want == len {
583 for i in 0..len {
584 let Some((m, s)) = self.zset_at(at).pick(i) else {
585 break;
586 };
587 f(m, s);
588 }
589 return Ok(len);
590 }
591 let mut rows = std::mem::take(&mut self.rows);
601 rows.clear();
602 yo_alloc::high_water(|| rows.extend(0..len));
603 for i in 0..want {
604 let pick = i + self.rng.below(len - i);
605 rows.swap(i, pick);
606 let Some((m, s)) = self.zset_at(at).pick(rows[i]) else {
607 break;
608 };
609 f(m, s);
610 }
611 self.rows = rows;
612 Ok(want)
613 }
614
615 pub fn zscan<F>(&mut self, key: &[u8], cursor: Cursor, count: usize, f: F) -> Result<Cursor>
621 where
622 F: FnMut(Member<'_>, f64),
623 {
624 let Some(at) = self.zset_slot(key)? else {
625 return Ok(Cursor::END);
626 };
627 Ok(self.zset_at(at).scan(cursor, count, f))
628 }
629
630 pub fn zsetop<'k, F>(
637 &mut self,
638 op: Op,
639 keys: impl Iterator<Item = &'k [u8]>,
640 weights: &[f64],
641 agg: Aggregate,
642 f: F,
643 ) -> Result<usize>
644 where
645 F: FnMut(Member<'_>, f64),
646 {
647 let slots = self.operand_slots(keys)?;
648 let got = zsetops::gather(op, &self.operands_of(&slots), weights, agg);
649 let limits = self.zset_limits;
650 let Some(z) = Zset::from_elements(got, &limits) else {
651 return Ok(0);
652 };
653 let len = z.len();
654 z.walk(0, len, false, f);
655 Ok(len)
656 }
657
658 pub fn zsetop_store<'k>(
665 &mut self,
666 op: Op,
667 destination: &[u8],
668 keys: impl Iterator<Item = &'k [u8]>,
669 weights: &[f64],
670 agg: Aggregate,
671 ) -> Result<usize> {
672 let slots = self.operand_slots(keys)?;
673 let got = zsetops::gather(op, &self.operands_of(&slots), weights, agg);
674 let limits = self.zset_limits;
675 Ok(self.put_zset(destination, Zset::from_elements(got, &limits)))
676 }
677
678 pub fn zintercard<'k>(
684 &mut self,
685 keys: impl Iterator<Item = &'k [u8]>,
686 limit: usize,
687 ) -> Result<usize> {
688 let slots = self.operand_slots(keys)?;
689 Ok(zsetops::intercard(&self.operands_of(&slots), limit))
690 }
691
692 pub fn zrangestore(
699 &mut self,
700 destination: &[u8],
701 source: &[u8],
702 q: &Query<'_>,
703 ) -> Result<usize> {
704 let built = match self.zset_slot(source)? {
705 None => None,
706 Some(at) => {
707 let z = self.zset_at(at);
708 let w = window(z, q);
709 let mut got = Elements::with_capacity(w.count.max(16));
710 let mut digits = [0u8; DIGITS_MAX];
711 let from = if w.rev { w.from + 1 - w.count } else { w.from };
716 z.walk(from, w.count, false, |m, s| {
717 let _ = got.insert(member_bytes(m, &mut digits), s);
718 });
719 let limits = self.zset_limits;
720 Zset::from_elements(got, &limits)
721 }
722 };
723 Ok(self.put_zset(destination, built))
724 }
725
726 fn operand_slots<'k>(
733 &mut self,
734 keys: impl Iterator<Item = &'k [u8]>,
735 ) -> Result<Vec<Option<(Kind, u32)>>> {
736 let mut out = Vec::with_capacity(keys.size_hint().0);
737 for key in keys {
738 out.push(self.live_slot_either(key, Kind::Zset, Kind::Set)?);
739 }
740 Ok(out)
741 }
742
743 fn operands_of(&self, slots: &[Option<(Kind, u32)>]) -> Vec<Operand<'_>> {
746 slots
747 .iter()
748 .map(|got| match got {
749 Some((Kind::Zset, at)) => Operand::Zset(self.zset_at(*at)),
750 Some((Kind::Set, at)) => {
751 Operand::Set(self.sets.get(*at).expect("the record points at its body"))
752 }
753 _ => Operand::Missing,
754 })
755 .collect()
756 }
757
758 pub(crate) fn put_zset(&mut self, key: &[u8], z: Option<Zset>) -> usize {
768 let Some(z) = z else {
769 self.drop_key(key);
770 return 0;
771 };
772 self.free_body(key);
773 let len = z.len();
774 let at = self.zsets.insert(z);
775 let record = value::slot_record_len(false);
776 self.write_rec(key, record, |out| {
777 value::write_slot_record(out, Kind::Zset, at, None);
778 });
779 self.bodies += 1;
780 len
781 }
782
783 #[inline]
785 pub(crate) fn zset_slot(&mut self, key: &[u8]) -> Result<Option<u32>> {
786 self.live_slot(key, Kind::Zset)
787 }
788
789 #[inline]
794 pub(crate) fn zset_at(&self, at: u32) -> &Zset {
795 self.zsets.get(at).expect("the record points at its body")
796 }
797
798 fn new_zset(&mut self, key: &[u8]) -> u32 {
804 let at = yo_alloc::first_touch(|| self.zsets.insert(Zset::new()));
808 let len = value::slot_record_len(false);
809 self.write_rec(key, len, |out| {
810 value::write_slot_record(out, Kind::Zset, at, None);
811 });
812 self.bodies += 1;
813 at
814 }
815}
816
817fn gated(z: &Zset, member: &[u8], score: f64, opts: ZAdd) -> Option<Added> {
823 match z.score(member) {
824 None => match opts.gate {
825 Gate::IfPresent => None,
826 _ => Some(Added::New),
829 },
830 Some(was) => {
831 if opts.gate == Gate::IfMissing {
832 return None;
833 }
834 let ok = match opts.only {
835 Move::Any => true,
836 Move::Up => score > was,
837 Move::Down => score < was,
838 };
839 if !ok {
840 return None;
841 }
842 Some(if score == was {
845 Added::Same
846 } else {
847 Added::Changed
848 })
849 }
850 }
851}
852
853fn window(z: &Zset, q: &Query<'_>) -> Window {
855 let len = z.len();
856 let range = match q.by {
857 By::Rank { start, stop } => {
858 let (from, count) = rank_span(start, stop, len);
862 if q.rev {
863 return apply_limit(
864 Window {
865 from: len - from - 1,
866 count,
867 rev: true,
868 },
869 q,
870 true,
871 );
872 }
873 return apply_limit(
874 Window {
875 from,
876 count,
877 rev: false,
878 },
879 q,
880 true,
881 );
882 }
883 By::Score { min, max } => z.window_by_score(min, max),
884 By::Lex { min, max } => z.window_by_lex(min, max),
885 };
886 let count = range.end - range.start;
887 let from = if q.rev {
888 range.end.saturating_sub(1)
889 } else {
890 range.start
891 };
892 apply_limit(
893 Window {
894 from,
895 count,
896 rev: q.rev,
897 },
898 q,
899 false,
900 )
901}
902
903fn apply_limit(w: Window, q: &Query<'_>, skip: bool) -> Window {
912 if skip {
913 return w;
914 }
915 let offset = q.offset.min(w.count);
916 let count = q.count.unwrap_or(usize::MAX).min(w.count - offset);
917 let from = if w.rev {
918 w.from.saturating_sub(offset)
919 } else {
920 w.from + offset
921 };
922 Window {
923 from,
924 count,
925 rev: w.rev,
926 }
927}
928
929fn rank_span(start: i64, stop: i64, len: usize) -> (usize, usize) {
936 if len == 0 {
937 return (0, 0);
938 }
939 let len = len as i64;
940 let from = if start < 0 {
941 (len + start).max(0)
942 } else {
943 start.min(len)
944 };
945 let to = if stop < 0 {
946 len + stop
947 } else {
948 stop.min(len - 1)
949 };
950 if to < from {
951 return (from as usize, 0);
952 }
953 (from as usize, (to - from + 1) as usize)
954}
955
956pub(crate) fn member_bytes<'a>(
959 m: Member<'a>,
960 digits: &'a mut [u8; yo_common::num::DIGITS_MAX],
961) -> &'a [u8] {
962 match m {
963 Member::Str(s) => s,
964 Member::Int(n) => yo_common::num::i64_digits(digits, n),
965 }
966}
967
968#[cfg(test)]
969mod tests {
970 use super::*;
971 use yo_common::num::DIGITS_MAX;
972
973 fn ks() -> Keyspace {
974 Keyspace::new()
975 }
976
977 fn add(k: &mut Keyspace, key: &[u8], pairs: &[(f64, &[u8])]) -> usize {
979 k.zadd(key, pairs.iter().copied(), ZAdd::default()).unwrap()
980 }
981
982 fn names(k: &mut Keyspace, key: &[u8], q: &Query<'_>) -> Vec<String> {
984 let w = k.zwindow(key, q).unwrap();
985 let mut out = Vec::new();
986 let mut digits = [0u8; DIGITS_MAX];
987 k.zwalk(key, w, |m, _| {
988 out.push(String::from_utf8(member_bytes(m, &mut digits).to_vec()).unwrap());
989 })
990 .unwrap();
991 assert_eq!(
992 out.len(),
993 w.count,
994 "the window said {} and the walk gave {}",
995 w.count,
996 out.len()
997 );
998 out
999 }
1000
1001 #[test]
1006 fn zrandmember_stops_allocating_once_its_buffer_is_grown() {
1007 let mut k = ks();
1008 add(
1009 &mut k,
1010 b"z",
1011 &[(1.0, b"a"), (2.0, b"b"), (3.0, b"c"), (4.0, b"d")],
1012 );
1013 k.zrandmember(b"z", 2, |_, _| {}).expect("a sorted set");
1014 let (_, allocs) = crate::tally::counted(|| {
1015 for _ in 0..100 {
1016 k.zrandmember(b"z", 2, |_, _| {}).expect("a sorted set");
1017 }
1018 });
1019 assert_eq!(
1020 allocs, 0,
1021 "zrandmember allocated {allocs} times in a hundred"
1022 );
1023 }
1024
1025 #[test]
1029 fn zrandmember_hands_its_buffer_back() {
1030 let mut k = ks();
1031 add(&mut k, b"z", &[(1.0, b"a"), (2.0, b"b"), (3.0, b"c")]);
1032 for _ in 0..3 {
1033 let mut seen = Vec::new();
1034 let n = k
1035 .zrandmember(b"z", 2, |m, _| {
1036 let mut digits = [0u8; DIGITS_MAX];
1037 seen.push(String::from_utf8(member_bytes(m, &mut digits).to_vec()).unwrap());
1038 })
1039 .expect("a sorted set");
1040 assert_eq!(n, 2);
1041 assert_eq!(seen.len(), 2);
1042 assert_ne!(seen[0], seen[1], "a positive count draws without replacing");
1043 }
1044 }
1045
1046 #[test]
1047 fn a_missing_key_is_an_empty_sorted_set() {
1048 let mut k = ks();
1049 assert_eq!(k.zcard(b"nope").unwrap(), 0);
1050 assert_eq!(k.zscore(b"nope", b"m").unwrap(), None);
1051 assert_eq!(k.zrank(b"nope", b"m", false).unwrap(), None);
1052 assert_eq!(k.zrem(b"nope", [b"m".as_slice()].into_iter()).unwrap(), 0);
1053 assert_eq!(
1054 names(&mut k, b"nope", &Query::rank(0, -1)),
1055 Vec::<String>::new()
1056 );
1057 assert!(!k.exists(b"nope"));
1058 }
1059
1060 #[test]
1061 fn a_key_holding_something_else_is_a_wrongtype() {
1062 let mut k = ks();
1063 k.set(b"s", b"hello", strings::SetOptions::default())
1064 .unwrap();
1065 assert_eq!(k.zcard(b"s").unwrap_err().code(), Code::WrongType);
1066 assert_eq!(
1067 k.zadd(b"s", [(1.0, b"m".as_slice())].into_iter(), ZAdd::default())
1068 .unwrap_err()
1069 .code(),
1070 Code::WrongType
1071 );
1072 assert_eq!(k.zscore(b"s", b"m").unwrap_err().code(), Code::WrongType);
1073 }
1074
1075 #[test]
1076 fn adding_answers_how_many_were_new() {
1077 let mut k = ks();
1078 assert_eq!(add(&mut k, b"z", &[(1.0, b"a"), (2.0, b"b")]), 2);
1079 assert_eq!(add(&mut k, b"z", &[(1.0, b"a"), (3.0, b"c")]), 1);
1080 assert_eq!(k.zcard(b"z").unwrap(), 3);
1081 assert_eq!(k.zscore(b"z", b"c").unwrap(), Some(3.0));
1082 assert_eq!(k.kind_of(b"z").map(Kind::name), Some("zset"));
1083 assert_eq!(k.encoding_name(b"z"), Some("listpack"));
1084 }
1085
1086 #[test]
1087 fn the_ch_flag_counts_moved_scores_too() {
1088 let mut k = ks();
1089 add(&mut k, b"z", &[(1.0, b"a"), (2.0, b"b")]);
1090 let ch = ZAdd {
1091 changed: true,
1092 ..ZAdd::default()
1093 };
1094 let pairs = [
1096 (9.0, b"a".as_slice()),
1097 (2.0, b"b".as_slice()),
1098 (3.0, b"c".as_slice()),
1099 ];
1100 assert_eq!(k.zadd(b"z", pairs.into_iter(), ch).unwrap(), 2);
1101 assert_eq!(k.zadd(b"z", pairs.into_iter(), ZAdd::default()).unwrap(), 0);
1102 }
1103
1104 #[test]
1105 fn the_gates_let_the_right_members_through() {
1106 let mut k = ks();
1107 add(&mut k, b"z", &[(1.0, b"a")]);
1108 let nx = ZAdd {
1109 gate: Gate::IfMissing,
1110 ..ZAdd::default()
1111 };
1112 let xx = ZAdd {
1113 gate: Gate::IfPresent,
1114 ..ZAdd::default()
1115 };
1116 assert_eq!(
1117 k.zadd(b"z", [(5.0, b"a".as_slice())].into_iter(), nx)
1118 .unwrap(),
1119 0
1120 );
1121 assert_eq!(k.zscore(b"z", b"a").unwrap(), Some(1.0));
1122 assert_eq!(
1123 k.zadd(b"z", [(5.0, b"b".as_slice())].into_iter(), nx)
1124 .unwrap(),
1125 1
1126 );
1127 assert_eq!(
1128 k.zadd(b"z", [(7.0, b"c".as_slice())].into_iter(), xx)
1129 .unwrap(),
1130 0
1131 );
1132 assert_eq!(k.zscore(b"z", b"c").unwrap(), None);
1133 assert_eq!(
1134 k.zadd(b"z", [(7.0, b"a".as_slice())].into_iter(), xx)
1135 .unwrap(),
1136 0
1137 );
1138 assert_eq!(k.zscore(b"z", b"a").unwrap(), Some(7.0));
1139 assert_eq!(
1141 k.zadd(b"gone", [(1.0, b"a".as_slice())].into_iter(), xx)
1142 .unwrap(),
1143 0
1144 );
1145 assert!(!k.exists(b"gone"));
1146 }
1147
1148 #[test]
1149 fn gt_and_lt_only_move_a_score_one_way() {
1150 let mut k = ks();
1151 add(&mut k, b"z", &[(5.0, b"a")]);
1152 let gt = ZAdd {
1153 only: Move::Up,
1154 changed: true,
1155 ..ZAdd::default()
1156 };
1157 let lt = ZAdd {
1158 only: Move::Down,
1159 changed: true,
1160 ..ZAdd::default()
1161 };
1162 assert_eq!(
1163 k.zadd(b"z", [(3.0, b"a".as_slice())].into_iter(), gt)
1164 .unwrap(),
1165 0
1166 );
1167 assert_eq!(k.zscore(b"z", b"a").unwrap(), Some(5.0));
1168 assert_eq!(
1169 k.zadd(b"z", [(9.0, b"a".as_slice())].into_iter(), gt)
1170 .unwrap(),
1171 1
1172 );
1173 assert_eq!(k.zscore(b"z", b"a").unwrap(), Some(9.0));
1174 assert_eq!(
1175 k.zadd(b"z", [(9.0, b"a".as_slice())].into_iter(), lt)
1176 .unwrap(),
1177 0
1178 );
1179 assert_eq!(
1180 k.zadd(b"z", [(2.0, b"a".as_slice())].into_iter(), lt)
1181 .unwrap(),
1182 1
1183 );
1184 assert_eq!(k.zscore(b"z", b"a").unwrap(), Some(2.0));
1185 assert_eq!(
1187 k.zadd(b"z", [(1.0, b"new".as_slice())].into_iter(), gt)
1188 .unwrap(),
1189 1
1190 );
1191 }
1192
1193 #[test]
1194 fn incrementing_adds_to_what_is_there_or_to_nothing() {
1195 let mut k = ks();
1196 let plain = ZAdd::default();
1197 assert_eq!(k.zincrby(b"z", b"a", 5.0, plain).unwrap(), Some(5.0));
1198 assert_eq!(k.zincrby(b"z", b"a", -2.5, plain).unwrap(), Some(2.5));
1199 assert_eq!(k.zscore(b"z", b"a").unwrap(), Some(2.5));
1200 let nx = ZAdd {
1201 gate: Gate::IfMissing,
1202 ..ZAdd::default()
1203 };
1204 assert_eq!(k.zincrby(b"z", b"a", 1.0, nx).unwrap(), None);
1205 assert_eq!(k.zscore(b"z", b"a").unwrap(), Some(2.5));
1206 let xx = ZAdd {
1207 gate: Gate::IfPresent,
1208 ..ZAdd::default()
1209 };
1210 assert_eq!(k.zincrby(b"z", b"never", 1.0, xx).unwrap(), None);
1211 assert!(k.zscore(b"z", b"never").unwrap().is_none());
1212 let gt = ZAdd {
1213 only: Move::Up,
1214 ..ZAdd::default()
1215 };
1216 assert_eq!(k.zincrby(b"z", b"a", -1.0, gt).unwrap(), None);
1217 assert_eq!(k.zincrby(b"z", b"a", 1.0, gt).unwrap(), Some(3.5));
1218 }
1219
1220 #[test]
1221 fn a_score_that_is_not_a_number_is_refused() {
1222 let mut k = ks();
1223 let plain = ZAdd::default();
1224 assert_eq!(
1225 k.zadd(b"z", [(f64::NAN, b"a".as_slice())].into_iter(), plain)
1226 .unwrap_err()
1227 .code(),
1228 Code::Invalid
1229 );
1230 assert!(!k.exists(b"z"));
1231 k.zincrby(b"z", b"a", f64::INFINITY, plain).unwrap();
1232 let err = k.zincrby(b"z", b"a", f64::NEG_INFINITY, plain).unwrap_err();
1233 assert_eq!(err.code(), Code::Invalid);
1234 assert_eq!(k.zscore(b"z", b"a").unwrap(), Some(f64::INFINITY));
1236 }
1237
1238 #[test]
1239 fn a_sorted_set_that_loses_its_last_member_loses_its_key() {
1240 let mut k = ks();
1241 add(&mut k, b"z", &[(1.0, b"a"), (2.0, b"b")]);
1242 assert_eq!(
1243 k.zrem(b"z", [b"a".as_slice(), b"b".as_slice()].into_iter())
1244 .unwrap(),
1245 2
1246 );
1247 assert!(!k.exists(b"z"));
1248 assert_eq!(k.zcard(b"z").unwrap(), 0);
1249 }
1250
1251 #[test]
1252 fn ranks_count_from_both_ends() {
1253 let mut k = ks();
1254 add(&mut k, b"z", &[(1.0, b"a"), (2.0, b"b"), (3.0, b"c")]);
1255 assert_eq!(k.zrank(b"z", b"a", false).unwrap(), Some((0, 1.0)));
1256 assert_eq!(k.zrank(b"z", b"c", false).unwrap(), Some((2, 3.0)));
1257 assert_eq!(k.zrank(b"z", b"a", true).unwrap(), Some((2, 1.0)));
1258 assert_eq!(k.zrank(b"z", b"c", true).unwrap(), Some((0, 3.0)));
1259 assert_eq!(k.zrank(b"z", b"nope", false).unwrap(), None);
1260 }
1261
1262 #[test]
1263 fn a_rank_range_clamps_every_way_it_can_be_wrong() {
1264 let mut k = ks();
1265 add(&mut k, b"z", &[(1.0, b"a"), (2.0, b"b"), (3.0, b"c")]);
1266 assert_eq!(names(&mut k, b"z", &Query::rank(0, -1)), ["a", "b", "c"]);
1267 assert_eq!(names(&mut k, b"z", &Query::rank(1, 1)), ["b"]);
1268 assert_eq!(names(&mut k, b"z", &Query::rank(-2, -1)), ["b", "c"]);
1269 assert_eq!(names(&mut k, b"z", &Query::rank(-99, 99)), ["a", "b", "c"]);
1270 assert_eq!(
1271 names(&mut k, b"z", &Query::rank(2, 1)),
1272 Vec::<String>::new()
1273 );
1274 assert_eq!(
1275 names(&mut k, b"z", &Query::rank(5, 9)),
1276 Vec::<String>::new()
1277 );
1278 assert_eq!(
1279 names(&mut k, b"z", &Query::rank(0, -1).rev(true)),
1280 ["c", "b", "a"]
1281 );
1282 assert_eq!(
1283 names(&mut k, b"z", &Query::rank(0, 1).rev(true)),
1284 ["c", "b"]
1285 );
1286 }
1287
1288 #[test]
1289 fn a_score_range_walks_either_way_and_takes_a_limit() {
1290 let mut k = ks();
1291 add(
1292 &mut k,
1293 b"z",
1294 &[(1.0, b"a"), (2.0, b"b"), (3.0, b"c"), (4.0, b"d")],
1295 );
1296 let all = Query::score(
1297 Bound::closed(f64::NEG_INFINITY),
1298 Bound::closed(f64::INFINITY),
1299 );
1300 assert_eq!(names(&mut k, b"z", &all), ["a", "b", "c", "d"]);
1301 assert_eq!(names(&mut k, b"z", &all.rev(true)), ["d", "c", "b", "a"]);
1302 assert_eq!(
1303 names(
1304 &mut k,
1305 b"z",
1306 &Query::score(Bound::closed(2.0), Bound::closed(3.0))
1307 ),
1308 ["b", "c"]
1309 );
1310 assert_eq!(
1311 names(
1312 &mut k,
1313 b"z",
1314 &Query::score(Bound::open(2.0), Bound::open(4.0))
1315 ),
1316 ["c"]
1317 );
1318 assert_eq!(names(&mut k, b"z", &all.limit(1, Some(2))), ["b", "c"]);
1321 assert_eq!(
1322 names(&mut k, b"z", &all.rev(true).limit(1, Some(2))),
1323 ["c", "b"]
1324 );
1325 assert_eq!(
1326 names(&mut k, b"z", &all.limit(9, Some(2))),
1327 Vec::<String>::new()
1328 );
1329 assert_eq!(names(&mut k, b"z", &all.limit(2, None)), ["c", "d"]);
1330 assert_eq!(
1331 k.zcount(b"z", &Query::score(Bound::closed(2.0), Bound::closed(3.0)))
1332 .unwrap(),
1333 2
1334 );
1335 }
1336
1337 #[test]
1338 fn a_member_range_orders_by_member_when_every_score_is_the_same() {
1339 let mut k = ks();
1340 add(
1341 &mut k,
1342 b"z",
1343 &[(0.0, b"a"), (0.0, b"b"), (0.0, b"c"), (0.0, b"d")],
1344 );
1345 assert_eq!(
1346 names(&mut k, b"z", &Query::lex(Lex::Min, Lex::Max)),
1347 ["a", "b", "c", "d"]
1348 );
1349 assert_eq!(
1350 names(&mut k, b"z", &Query::lex(Lex::Incl(b"b"), Lex::Incl(b"c"))),
1351 ["b", "c"]
1352 );
1353 assert_eq!(
1354 names(&mut k, b"z", &Query::lex(Lex::Excl(b"a"), Lex::Excl(b"d"))),
1355 ["b", "c"]
1356 );
1357 assert_eq!(
1358 names(&mut k, b"z", &Query::lex(Lex::Min, Lex::Max).rev(true)),
1359 ["d", "c", "b", "a"]
1360 );
1361 assert_eq!(
1362 k.zcount(b"z", &Query::lex(Lex::Incl(b"b"), Lex::Max))
1363 .unwrap(),
1364 3
1365 );
1366 }
1367
1368 #[test]
1369 fn removing_a_range_takes_out_exactly_what_the_walk_would_have_given() {
1370 let mut k = ks();
1371 for (q, left) in [
1372 (Query::rank(0, 1), vec!["c", "d", "e"]),
1373 (Query::rank(-2, -1), vec!["a", "b", "c"]),
1374 (
1375 Query::score(Bound::closed(2.0), Bound::closed(4.0)),
1376 vec!["a", "e"],
1377 ),
1378 (
1379 Query::lex(Lex::Incl(b"b"), Lex::Excl(b"d")),
1380 vec!["a", "d", "e"],
1381 ),
1382 (Query::rank(0, -1).rev(true), vec![]),
1383 ] {
1384 k.del(b"z");
1385 add(
1386 &mut k,
1387 b"z",
1388 &[
1389 (1.0, b"a"),
1390 (2.0, b"b"),
1391 (3.0, b"c"),
1392 (4.0, b"d"),
1393 (5.0, b"e"),
1394 ],
1395 );
1396 let want = names(&mut k, b"z", &q).len();
1397 assert_eq!(k.zremrange(b"z", &q).unwrap(), want, "{q:?}");
1398 assert_eq!(names(&mut k, b"z", &Query::rank(0, -1)), left, "{q:?}");
1399 }
1400 assert!(!k.exists(b"z"));
1402 }
1403
1404 #[test]
1405 fn popping_takes_from_the_end_it_was_told_to() {
1406 let mut k = ks();
1407 add(&mut k, b"z", &[(1.0, b"a"), (2.0, b"b"), (3.0, b"c")]);
1408 let mut got = Vec::new();
1409 let mut digits = [0u8; DIGITS_MAX];
1410 k.zpop(b"z", From::Min, 2, |m, s| {
1411 got.push((
1412 String::from_utf8(member_bytes(m, &mut digits).to_vec()).unwrap(),
1413 s,
1414 ));
1415 })
1416 .unwrap();
1417 assert_eq!(got, [("a".to_string(), 1.0), ("b".to_string(), 2.0)]);
1418 assert_eq!(
1419 k.zpop_one(b"z", From::Max).unwrap(),
1420 Some((b"c".to_vec(), 3.0))
1421 );
1422 assert!(!k.exists(b"z"));
1423 add(&mut k, b"z", &[(1.0, b"a")]);
1425 assert_eq!(k.zpop(b"z", From::Max, 99, |_, _| {}).unwrap(), 1);
1426 assert!(!k.exists(b"z"));
1427 assert_eq!(k.zpop_one(b"z", From::Min).unwrap(), None);
1428 }
1429
1430 #[test]
1431 fn a_random_draw_is_with_or_without_replacement_by_the_sign_of_the_count() {
1432 let mut k = ks();
1433 add(&mut k, b"z", &[(1.0, b"a"), (2.0, b"b"), (3.0, b"c")]);
1434 let mut digits = [0u8; DIGITS_MAX];
1435 let mut seen = Vec::new();
1436 k.zrandmember(b"z", 2, |m, _| {
1437 seen.push(String::from_utf8(member_bytes(m, &mut digits).to_vec()).unwrap());
1438 })
1439 .unwrap();
1440 assert_eq!(seen.len(), 2);
1441 seen.sort();
1442 seen.dedup();
1443 assert_eq!(seen.len(), 2, "a positive count does not repeat a member");
1444 let mut all = Vec::new();
1446 k.zrandmember(b"z", 99, |m, _| {
1447 all.push(String::from_utf8(member_bytes(m, &mut digits).to_vec()).unwrap());
1448 })
1449 .unwrap();
1450 all.sort();
1451 assert_eq!(all, ["a", "b", "c"]);
1452 let mut many = 0;
1454 k.zrandmember(b"z", -10, |_, _| many += 1).unwrap();
1455 assert_eq!(many, 10);
1456 assert_eq!(k.zrandmember(b"nope", 3, |_, _| {}).unwrap(), 0);
1457 }
1458
1459 #[test]
1460 fn a_scan_of_either_band_walks_every_member_once() {
1461 let mut k = ks();
1462 for entries in [8usize, 4096] {
1463 k.del(b"z");
1464 let pairs: Vec<(f64, Vec<u8>)> = (0..entries)
1465 .map(|i| (i as f64, format!("m{i:05}").into_bytes()))
1466 .collect();
1467 k.zadd(
1468 b"z",
1469 pairs.iter().map(|(s, m)| (*s, m.as_slice())),
1470 ZAdd::default(),
1471 )
1472 .unwrap();
1473 let mut seen = Vec::new();
1474 let mut digits = [0u8; DIGITS_MAX];
1475 let mut cursor = Cursor::START;
1476 loop {
1477 cursor = k
1478 .zscan(b"z", cursor, 16, |m, _| {
1479 seen.push(
1480 String::from_utf8(member_bytes(m, &mut digits).to_vec()).unwrap(),
1481 );
1482 })
1483 .unwrap();
1484 if cursor.is_end() {
1485 break;
1486 }
1487 }
1488 seen.sort();
1489 seen.dedup();
1490 assert_eq!(seen.len(), entries, "{entries} members");
1491 }
1492 }
1493
1494 #[test]
1495 fn a_big_sorted_set_promotes_and_still_answers_every_rank() {
1496 let mut k = ks();
1497 let pairs: Vec<(f64, Vec<u8>)> = (0..5_000)
1498 .map(|i| (f64::from(i), format!("m{i:05}").into_bytes()))
1499 .collect();
1500 assert_eq!(
1501 k.zadd(
1502 b"z",
1503 pairs.iter().map(|(s, m)| (*s, m.as_slice())),
1504 ZAdd::default()
1505 )
1506 .unwrap(),
1507 5_000
1508 );
1509 assert_eq!(k.encoding_name(b"z"), Some("skiplist"));
1510 assert_eq!(k.zcard(b"z").unwrap(), 5_000);
1511 assert_eq!(
1512 k.zrank(b"z", b"m02500", false).unwrap(),
1513 Some((2_500, 2500.0))
1514 );
1515 let q = Query::score(Bound::closed(1000.0), Bound::open(1010.0));
1516 assert_eq!(k.zcount(b"z", &q).unwrap(), 10);
1517 assert_eq!(
1518 names(&mut k, b"z", &q).first().map(String::as_str),
1519 Some("m01000")
1520 );
1521 assert_eq!(k.zremrange(b"z", &Query::rank(0, 2_499)).unwrap(), 2_500);
1523 assert_eq!(k.zcard(b"z").unwrap(), 2_500);
1524 assert_eq!(k.zrank(b"z", b"m02500", false).unwrap(), Some((0, 2500.0)));
1525 assert_eq!(k.zrank(b"z", b"m00000", false).unwrap(), None);
1526 }
1527
1528 #[test]
1529 fn a_deadline_on_a_sorted_set_leaves_its_members_alone() {
1530 let mut k = ks();
1531 add(&mut k, b"z", &[(1.0, b"a"), (2.0, b"b")]);
1532 assert!(k.set_expiry(b"z", Some(u64::MAX / 2)));
1533 assert_eq!(k.zcard(b"z").unwrap(), 2);
1534 assert_eq!(k.zscore(b"z", b"b").unwrap(), Some(2.0));
1535 assert!(k.set_expiry(b"z", None));
1536 assert_eq!(k.zcard(b"z").unwrap(), 2);
1537 }
1538
1539 #[test]
1540 fn writing_a_string_over_a_sorted_set_gives_its_body_back() {
1541 let mut k = ks();
1542 add(&mut k, b"z", &[(1.0, b"a")]);
1543 let held = k.memory_bytes();
1544 k.set(b"z", b"now a string", strings::SetOptions::default())
1545 .unwrap();
1546 assert_eq!(k.kind_of(b"z").map(Kind::name), Some("string"));
1547 assert!(
1548 k.memory_bytes() < held,
1549 "the sorted set's body was not freed"
1550 );
1551 }
1552
1553 fn all(k: &mut Keyspace, key: &[u8]) -> Vec<(String, f64)> {
1555 let q = Query::rank(0, -1);
1556 let w = k.zwindow(key, &q).unwrap();
1557 let mut out = Vec::new();
1558 let mut digits = [0u8; DIGITS_MAX];
1559 k.zwalk(key, w, |m, s| {
1560 out.push((
1561 String::from_utf8(member_bytes(m, &mut digits).to_vec()).unwrap(),
1562 s,
1563 ));
1564 })
1565 .unwrap();
1566 out
1567 }
1568
1569 fn got(
1571 k: &mut Keyspace,
1572 op: Op,
1573 keys: &[&[u8]],
1574 weights: &[f64],
1575 agg: Aggregate,
1576 ) -> Vec<(String, f64)> {
1577 let mut out = Vec::new();
1578 let mut digits = [0u8; DIGITS_MAX];
1579 let n = k
1580 .zsetop(op, keys.iter().copied(), weights, agg, |m, s| {
1581 out.push((
1582 String::from_utf8(member_bytes(m, &mut digits).to_vec()).unwrap(),
1583 s,
1584 ));
1585 })
1586 .unwrap();
1587 assert_eq!(out.len(), n, "the count and the walk disagree");
1588 out
1589 }
1590
1591 #[test]
1592 fn a_union_adds_the_scores_of_a_member_that_is_in_both() {
1593 let mut k = ks();
1594 add(&mut k, b"a", &[(1.0, b"x"), (2.0, b"y")]);
1595 add(&mut k, b"b", &[(10.0, b"y"), (3.0, b"z")]);
1596 assert_eq!(
1597 got(&mut k, Op::Union, &[b"a", b"b"], &[], Aggregate::Sum),
1598 [("x".into(), 1.0), ("z".into(), 3.0), ("y".into(), 12.0)]
1599 );
1600 }
1601
1602 #[test]
1603 fn an_intersection_keeps_only_what_every_input_has() {
1604 let mut k = ks();
1605 add(&mut k, b"a", &[(1.0, b"x"), (2.0, b"y"), (3.0, b"z")]);
1606 add(&mut k, b"b", &[(5.0, b"y"), (5.0, b"z")]);
1607 add(&mut k, b"c", &[(7.0, b"z")]);
1608 assert_eq!(
1609 got(&mut k, Op::Inter, &[b"a", b"b", b"c"], &[], Aggregate::Sum),
1610 [("z".into(), 15.0)]
1611 );
1612 assert_eq!(
1613 got(&mut k, Op::Inter, &[b"a", b"b", b"c"], &[], Aggregate::Min),
1614 [("z".into(), 3.0)]
1615 );
1616 assert_eq!(
1617 got(&mut k, Op::Inter, &[b"a", b"b", b"c"], &[], Aggregate::Max),
1618 [("z".into(), 7.0)]
1619 );
1620 }
1621
1622 #[test]
1623 fn a_difference_takes_the_first_input_and_removes_the_rest() {
1624 let mut k = ks();
1625 add(&mut k, b"a", &[(1.0, b"x"), (2.0, b"y"), (3.0, b"z")]);
1626 add(&mut k, b"b", &[(99.0, b"y")]);
1627 assert_eq!(
1628 got(&mut k, Op::Diff, &[b"a", b"b"], &[], Aggregate::Sum),
1629 [("x".into(), 1.0), ("z".into(), 3.0)]
1630 );
1631 }
1632
1633 #[test]
1634 fn a_missing_key_keeps_its_place_so_the_weights_stay_lined_up() {
1635 let mut k = ks();
1636 add(&mut k, b"a", &[(1.0, b"x")]);
1637 add(&mut k, b"c", &[(1.0, b"x")]);
1638 let out = got(
1641 &mut k,
1642 Op::Union,
1643 &[b"a", b"gone", b"c"],
1644 &[2.0, 10.0, 3.0],
1645 Aggregate::Sum,
1646 );
1647 assert_eq!(out, [("x".into(), 5.0)]);
1648 }
1649
1650 #[test]
1651 fn a_plain_set_counts_as_every_score_being_one() {
1652 let mut k = ks();
1653 add(&mut k, b"z", &[(5.0, b"x")]);
1654 k.sadd(b"s", [b"x".as_slice(), b"y".as_slice()].into_iter())
1655 .unwrap();
1656 assert_eq!(
1657 got(&mut k, Op::Union, &[b"z", b"s"], &[], Aggregate::Sum),
1658 [("y".into(), 1.0), ("x".into(), 6.0)]
1659 );
1660 assert_eq!(
1661 got(&mut k, Op::Inter, &[b"z", b"s"], &[], Aggregate::Min),
1662 [("x".into(), 1.0)]
1663 );
1664 }
1665
1666 #[test]
1667 fn a_store_writes_the_result_and_answers_its_size() {
1668 let mut k = ks();
1669 add(&mut k, b"a", &[(1.0, b"x"), (2.0, b"y")]);
1670 add(&mut k, b"b", &[(10.0, b"y")]);
1671 assert_eq!(
1672 k.zsetop_store(
1673 Op::Union,
1674 b"d",
1675 [b"a".as_slice(), b"b".as_slice()].into_iter(),
1676 &[],
1677 Aggregate::Sum
1678 )
1679 .unwrap(),
1680 2
1681 );
1682 assert_eq!(all(&mut k, b"d"), [("x".into(), 1.0), ("y".into(), 12.0)]);
1683 assert_eq!(k.zscore(b"d", b"y").unwrap(), Some(12.0));
1684 assert_eq!(k.zrank(b"d", b"y", false).unwrap(), Some((1, 12.0)));
1685 }
1686
1687 #[test]
1688 fn a_store_onto_one_of_its_own_sources_still_reads_the_old_body() {
1689 let mut k = ks();
1690 add(&mut k, b"a", &[(1.0, b"x"), (2.0, b"y")]);
1691 add(&mut k, b"b", &[(10.0, b"y")]);
1692 assert_eq!(
1693 k.zsetop_store(
1694 Op::Union,
1695 b"a",
1696 [b"a".as_slice(), b"b".as_slice()].into_iter(),
1697 &[],
1698 Aggregate::Sum
1699 )
1700 .unwrap(),
1701 2
1702 );
1703 assert_eq!(all(&mut k, b"a"), [("x".into(), 1.0), ("y".into(), 12.0)]);
1704 }
1705
1706 #[test]
1707 fn a_store_with_nothing_in_it_deletes_the_destination() {
1708 let mut k = ks();
1709 add(&mut k, b"a", &[(1.0, b"x")]);
1710 add(&mut k, b"b", &[(1.0, b"y")]);
1711 add(&mut k, b"d", &[(1.0, b"old")]);
1712 assert_eq!(
1713 k.zsetop_store(
1714 Op::Inter,
1715 b"d",
1716 [b"a".as_slice(), b"b".as_slice()].into_iter(),
1717 &[],
1718 Aggregate::Sum
1719 )
1720 .unwrap(),
1721 0
1722 );
1723 assert!(!k.exists(b"d"));
1724 }
1725
1726 #[test]
1727 fn a_store_clears_the_deadline_the_destination_was_carrying() {
1728 let mut k = ks();
1729 add(&mut k, b"a", &[(1.0, b"x")]);
1730 add(&mut k, b"d", &[(1.0, b"old")]);
1731 assert!(k.set_expiry(b"d", Some(u64::MAX / 2)));
1732 k.zsetop_store(
1733 Op::Union,
1734 b"d",
1735 [b"a".as_slice()].into_iter(),
1736 &[],
1737 Aggregate::Sum,
1738 )
1739 .unwrap();
1740 assert_eq!(all(&mut k, b"d"), [("x".into(), 1.0)]);
1741 assert_eq!(k.expire_at(b"d"), None);
1742 }
1743
1744 #[test]
1745 fn the_algebra_refuses_a_key_holding_something_that_is_neither() {
1746 let mut k = ks();
1747 add(&mut k, b"a", &[(1.0, b"x")]);
1748 k.set(b"s", b"hello", strings::SetOptions::default())
1749 .unwrap();
1750 assert_eq!(
1751 k.zsetop(
1752 Op::Union,
1753 [b"a".as_slice(), b"s".as_slice()].into_iter(),
1754 &[],
1755 Aggregate::Sum,
1756 |_, _| {}
1757 )
1758 .unwrap_err()
1759 .code(),
1760 Code::WrongType
1761 );
1762 assert!(!k.exists(b"d"));
1765 assert_eq!(
1766 k.zsetop_store(
1767 Op::Union,
1768 b"d",
1769 [b"a".as_slice(), b"s".as_slice()].into_iter(),
1770 &[],
1771 Aggregate::Sum
1772 )
1773 .unwrap_err()
1774 .code(),
1775 Code::WrongType
1776 );
1777 assert!(!k.exists(b"d"));
1778 }
1779
1780 #[test]
1781 fn intercard_counts_without_building_anything_and_stops_at_the_limit() {
1782 let mut k = ks();
1783 add(
1784 &mut k,
1785 b"a",
1786 &[(1.0, b"w"), (2.0, b"x"), (3.0, b"y"), (4.0, b"z")],
1787 );
1788 add(&mut k, b"b", &[(1.0, b"x"), (1.0, b"y"), (1.0, b"z")]);
1789 assert_eq!(
1790 k.zintercard([b"a".as_slice(), b"b".as_slice()].into_iter(), 0)
1791 .unwrap(),
1792 3
1793 );
1794 assert_eq!(
1795 k.zintercard([b"a".as_slice(), b"b".as_slice()].into_iter(), 2)
1796 .unwrap(),
1797 2
1798 );
1799 assert_eq!(
1800 k.zintercard([b"a".as_slice(), b"gone".as_slice()].into_iter(), 0)
1801 .unwrap(),
1802 0
1803 );
1804 }
1805
1806 #[test]
1807 fn a_range_store_copies_a_window_and_leaves_the_source_alone() {
1808 let mut k = ks();
1809 add(
1810 &mut k,
1811 b"z",
1812 &[(1.0, b"a"), (2.0, b"b"), (3.0, b"c"), (4.0, b"d")],
1813 );
1814 assert_eq!(k.zrangestore(b"d", b"z", &Query::rank(1, 2)).unwrap(), 2);
1815 assert_eq!(all(&mut k, b"d"), [("b".into(), 2.0), ("c".into(), 3.0)]);
1816 assert_eq!(k.zcard(b"z").unwrap(), 4);
1817 }
1818
1819 #[test]
1820 fn a_reverse_range_store_picks_the_same_members_and_orders_them_the_same() {
1821 let mut k = ks();
1822 add(
1823 &mut k,
1824 b"z",
1825 &[(1.0, b"a"), (2.0, b"b"), (3.0, b"c"), (4.0, b"d")],
1826 );
1827 assert_eq!(
1830 k.zrangestore(b"d", b"z", &Query::rank(0, 1).rev(true))
1831 .unwrap(),
1832 2
1833 );
1834 assert_eq!(all(&mut k, b"d"), [("c".into(), 3.0), ("d".into(), 4.0)]);
1835 }
1836
1837 #[test]
1838 fn a_range_store_by_score_takes_the_bounds_the_range_would_have() {
1839 let mut k = ks();
1840 add(
1841 &mut k,
1842 b"z",
1843 &[(1.0, b"a"), (2.0, b"b"), (3.0, b"c"), (4.0, b"d")],
1844 );
1845 let q = Query::score(Bound::closed(2.0), Bound::open(4.0));
1846 assert_eq!(k.zrangestore(b"d", b"z", &q).unwrap(), 2);
1847 assert_eq!(all(&mut k, b"d"), [("b".into(), 2.0), ("c".into(), 3.0)]);
1848 }
1849
1850 #[test]
1851 fn a_range_store_of_an_empty_window_deletes_the_destination() {
1852 let mut k = ks();
1853 add(&mut k, b"z", &[(1.0, b"a")]);
1854 add(&mut k, b"d", &[(1.0, b"old")]);
1855 assert_eq!(k.zrangestore(b"d", b"z", &Query::rank(5, 9)).unwrap(), 0);
1856 assert!(!k.exists(b"d"));
1857 assert_eq!(
1858 k.zrangestore(b"d", b"gone", &Query::rank(0, -1)).unwrap(),
1859 0
1860 );
1861 assert!(!k.exists(b"d"));
1862 }
1863
1864 #[test]
1865 fn a_range_store_onto_its_own_source_keeps_the_window() {
1866 let mut k = ks();
1867 add(
1868 &mut k,
1869 b"z",
1870 &[(1.0, b"a"), (2.0, b"b"), (3.0, b"c"), (4.0, b"d")],
1871 );
1872 assert_eq!(k.zrangestore(b"z", b"z", &Query::rank(1, 2)).unwrap(), 2);
1873 assert_eq!(all(&mut k, b"z"), [("b".into(), 2.0), ("c".into(), 3.0)]);
1874 }
1875
1876 #[test]
1877 fn a_big_result_comes_out_on_the_table_band_in_the_right_order() {
1878 let mut k = ks();
1879 let names: Vec<String> = (0..3000).map(|i| format!("member-{i:05}")).collect();
1880 for (i, name) in names.iter().enumerate() {
1881 add(&mut k, b"a", &[((i % 17) as f64, name.as_bytes())]);
1882 }
1883 for name in names.iter().step_by(3) {
1884 add(&mut k, b"b", &[(100.0, name.as_bytes())]);
1885 }
1886 let n = k
1887 .zsetop_store(
1888 Op::Union,
1889 b"d",
1890 [b"a".as_slice(), b"b".as_slice()].into_iter(),
1891 &[],
1892 Aggregate::Sum,
1893 )
1894 .unwrap();
1895 assert_eq!(n, 3000);
1896 assert_eq!(
1897 k.zset_encoding(b"d").map(crate::zset::Encoding::name),
1898 Some("skiplist")
1899 );
1900 let out = all(&mut k, b"d");
1901 assert_eq!(out.len(), 3000);
1902 let mut want = out.clone();
1903 want.sort_by(|x, y| x.1.partial_cmp(&y.1).unwrap().then_with(|| x.0.cmp(&y.0)));
1904 assert_eq!(out, want, "the result came out in the wrong order");
1905 for (i, name) in names.iter().enumerate() {
1906 let base = (i % 17) as f64;
1907 let want = if i % 3 == 0 { base + 100.0 } else { base };
1908 assert_eq!(k.zscore(b"d", name.as_bytes()).unwrap(), Some(want));
1909 }
1910 }
1911}