1 module mongostore;
2 
3 import vibe.http.session;
4 import vibe.db.mongo.mongo;
5 import vibe.db.mongo.database;
6 import vibe.db.mongo.client;
7 import vibe.db.mongo.connection;
8 import vibe.data.bson;
9 import std.variant;
10 
11 /// Session class for `HTTPServerSettings.sessionStore`
12 final class MongoSessionStore : SessionStore
13 {
14 public:
15 	///
16 	this(string host, string database, string collection = "sessions_")
17 	{
18 		_collection = connectMongoDB(host).getDatabase(database)[collection];
19 	}
20 
21 	///
22 	this(MongoClient client, string database, string collection = "sessions_")
23 	{
24 		_collection = client.getDatabase(database)[collection];
25 	}
26 
27 	///
28 	this(MongoDatabase database, string collection = "sessions_")
29 	{
30 		_collection = database[collection];
31 	}
32 
33 	///
34 	this(MongoCollection collection)
35 	{
36 		_collection = collection;
37 	}
38 
39 	@property SessionStorageType storageType() const
40 	{
41 		return SessionStorageType.bson;
42 	}
43 
44 	Session create()
45 	{
46 		auto s = createSessionInstance();
47 		_collection.update(["id" : s.id], Bson(["session" : Bson(null)]), UpdateFlags.Upsert);
48 		return s;
49 	}
50 
51 	Session open(string id)
52 	{
53 		return _collection.findOne(["id" : id]).isNull ? Session.init : createSessionInstance(id);
54 	}
55 
56 	void set(string id, string key, Variant value) @trusted
57 	{
58 		_collection.update(["id" : id], Bson(["$set"
59 				: Bson(["session." ~ key.makeKey : value.get!Bson])]), UpdateFlags.Upsert);
60 	}
61 
62 	Variant get(string id, string key, lazy Variant defaultVal) @trusted
63 	{
64 		auto v = _collection.findOne(["id" : id])["session"].tryIndex(key.makeKey);
65 		return v.isNull ? defaultVal : Variant(v.get);
66 	}
67 
68 	bool isKeySet(string id, string key)
69 	{
70 		return !_collection.findOne(Bson(["id" : Bson(id),
71 				"session." ~ key.makeKey : Bson(["$exists" : Bson(true)])])).isNull;
72 	}
73 
74 	void remove(string id, string key)
75 	{
76 		_collection.update(["id" : id], Bson(["$unset" : Bson("session." ~ key.makeKey)]));
77 	}
78 
79 	int delegate(int delegate(ref string key, ref Variant value)) iterateSession(string id) @safe
80 	{
81 		assert(false, "Not available for MongoSessionStore");
82 	}
83 
84 	void destroy(string id)
85 	{
86 		_collection.remove(["id" : id]);
87 	}
88 
89 	int iterateSession(string id, scope int delegate(string key) @safe del) @trusted
90 	{
91 		auto v = _collection.findOne(["id" : id]);
92 		foreach (string key, _; v["session"])
93 			if (auto ret = del(key))
94 				return ret;
95 		return 0;
96 	}
97 
98 	int iterateSession(string id, scope int delegate(string key) del) @trusted
99 	{
100 		auto v = _collection.findOne(["id" : id]);
101 		foreach (string key, _; v["session"])
102 			if (auto ret = del(key))
103 				return ret;
104 		return 0;
105 	}
106 
107 private:
108 	MongoCollection _collection;
109 }
110 
111 private string makeKey(string key) @safe
112 {
113 	if (key.length == 0)
114 		return "_";
115 	if (key[0] == '$')
116 		return "_" ~ key;
117 	return key;
118 }