1 module tinyredis.collections.set;
2 
3 import tinyredis : Redis, Response;
4 
5 /**
6 	Set 
7 	A class that represents a SET structure in redis. 
8 	Allows you to query and manipulate the set using methods.  
9 	Implements OutputRange.
10 
11 	NOTE: Operations are done on the server side as much as possible, to reflect the true state of
12 	the collection.
13 */
14 class Set
15 {
16 	private {
17 		Redis conn;
18 		string name;
19 	}
20 
21 	this(Redis conn, string name)
22 	{
23 		this.conn = conn;
24 		this.name = name;
25 	}
26 	
27 	auto smembers()
28 	{
29 		return conn.send("SMEMBERS", name);
30 	}
31 	
32 	@property int scard()
33 	{
34 		return conn.send!int("SCARD", name);
35 	}
36 	alias count = scard;
37 	
38 	
39 	int srem(const(char[])[] values...)
40 	{
41 		return conn.send!int("SREM", name, values);
42 	}
43 	
44 	int del()
45 	{
46 		return conn.send!int("DEL", name);
47 	}
48 	
49 	// OutputRange
50 	int put(in char[] value)
51 	{
52 		return conn.send!int("SADD", name, value);
53 	}
54 	
55 	int put(const(char[])[] values)
56 	{
57 		int count;
58 		foreach(value; values)
59 			count += put(value);
60 		return count;
61 	}
62 	
63 	void opAssign(const(char[]) value)
64 	{
65 		del();
66 		put(value);
67 	}
68 	
69 	void opAssign(const(char[])[] values)
70 	{
71 		del();
72 		put(values);
73 	}
74 
75 	void opOpAssign(string op : "~")(in char[] value) {
76 		put(value);
77 	}
78 
79 	void opOpAssign(string op : "-")(in char[] value) {
80 		srem(value);
81 	}
82 	
83 	void opOpAssign(string op : "~")(const(char[])[] values) {
84 		foreach(value; values)
85 			put(value);
86 	}
87 
88 	void opOpAssign(string op : "-")(const(char[])[] values) {
89 		foreach(value; values)
90 			srem(value);
91 	}
92 }
93 
94 unittest {
95 	import std.range : isOutputRange;
96 
97 	static assert(isOutputRange!(Set, string));
98 	
99 	// Start a redis server on 127.0.0.1:6379
100 	auto conn = new Redis("localhost", 6379);
101 	auto set  = new Set(conn, "tinyRedisUnitTestSet");
102 	
103 	set = ["banana", "apple", "orange"]; // data can be assigned using opAssign
104 	set.put("grapes"); //the put() function appends a value
105 	 
106 	assert(set.scard == 4); // runs the SCARD command, presents a proper count of the set on the server
107 	assert(set.count == 4); // count is an alias for SCARD command
108 	
109 	//opAssign resets the data
110 	set = ["guava", "pear"];
111 	assert(set.scard == 2);
112 	
113 	set ~= "banana"; // implements opOpAssign so ~= appends data
114 	set ~= "apple";
115 	set ~= ["orange", "mango"];
116 	set ~= "apple"; //DUPLICATE!
117 	assert(set.count == 6);
118 	
119 	set -= "mango"; //Not mango season!
120 	assert(set.count == 5);
121 	
122 	import std.algorithm : canFind;
123 	foreach(fruit; set.smembers())
124 		assert(["guava", "pear", "banana", "apple", "orange"].canFind(fruit.toString));
125 }