1 module redis.collections.set;
2 
3 public import redis;
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 		string name;
18 		Redis conn;
19 		
20 	public :
21 	
22 	this(Redis conn, string name)
23 	{
24 		this.conn = conn;
25 		this.name = name;
26 	}
27 	
28 	Response smembers()
29 	{
30 	    return conn.send("SMEMBERS", name);
31 	}
32 	
33 	int scard()
34     {
35         return conn.send!(int)("SCARD", name);
36     }
37     alias count = scard;
38     
39     
40     bool srem(const(char[]) value)
41     {
42         return conn.send!(bool)("SREM", name, value);
43     }
44     
45     void del()
46     {
47         conn.send("DEL", name);
48     }
49 	
50 	// OutputRange
51 	void put(const(char[]) value)
52 	{
53 		conn.send("SADD", name, value);
54 	}
55 	
56 	void put(const(char[])[] values)
57     {
58         foreach(value; values)
59             conn.send("SADD", name, value);
60     }
61     
62     void opAssign(const(char[]) value)
63     {
64         del();
65         put(value);
66     }
67     
68     void opAssign(const(char[])[] values)
69     {
70         del();
71         put(values);
72     }
73 
74     void opOpAssign(string op)(const(char[]) value)
75     {
76         static if (op == "~")
77             put(value);
78         else static if (op == "-")
79             srem(value);
80         else 
81             static assert(0, "Operator "~op~" not implemented");
82     }
83     
84     void opOpAssign(string op)(const(char[])[] values)
85     {
86         static if (op == "~")
87             foreach(value; values)
88                 put(value);
89         else static if (op == "-")
90             foreach(value; values)
91                 srem(value);
92         else 
93             static assert(0, "Operator "~op~" not implemented");
94     }
95 	
96 }
97 
98 unittest {
99     
100     import std.range : isOutputRange;
101     assert(isOutputRange!(Set, string));
102     
103     // Start a redis server on 127.0.0.1:6379
104     auto conn = new Redis("localhost", 6379);
105     auto set  = new Set(conn, "tinyRedisUnitTestSet");
106     
107     set = ["banana", "apple", "orange"]; // data can be assigned using opAssign
108     set.put("grapes"); //the put() function appends a value
109      
110     assert(set.scard() == 4); // runs the SCARD command, presents a proper count of the set on the server
111     assert(set.count() == 4); // count is an alias for SCARD command
112     
113     //opAssign resets the data
114     set = ["guava", "pear"];
115     assert(set.scard() == 2);
116     
117     set ~= "banana"; // implements opOpAssign so ~= appends data
118     set ~= "apple";
119     set ~= ["orange", "mango"];
120     set ~= "apple"; //DUPLICATE!
121     assert(set.count() == 6);
122     
123     set -= "mango"; //Not mango season!
124     assert(set.count() == 5);
125     
126     import std.algorithm : canFind;
127     foreach(fruit; set.smembers())
128         assert(["guava", "pear", "banana", "apple", "orange"].canFind(fruit.toString));
129     
130 }