1 /**
2 	MongoDatabase class representing common database for group of collections.
3 
4 	Technically it is very special collection with common query functions
5 	disabled and some service commands provided.
6 
7 	Copyright: © 2012-2014 Sönke Ludwig
8 	License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file.
9 	Authors: Sönke Ludwig
10 */
11 module vibe.db.mongo.database;
12 
13 import vibe.db.mongo.client;
14 import vibe.db.mongo.collection;
15 import vibe.data.bson;
16 
17 
18 /** Represents a single database accessible through a given MongoClient.
19 */
20 struct MongoDatabase
21 {
22 @safe:
23 
24 	private {
25 		string m_name;
26 		string m_commandCollection;
27 		MongoClient m_client;
28 	}
29 
30 	//@disable this();
31 
32 	this(MongoClient client, string name)
33 	{
34 		import std.algorithm;
35 
36 		assert(client !is null);
37 		m_client = client;
38 
39 		assert(
40 				!canFind(name, '.'),
41 				"Compound collection path provided to MongoDatabase constructor instead of single database name"
42 		  );
43 		m_name = name;
44 		m_commandCollection = m_name ~ ".$cmd";
45 	}
46 
47 	/// The name of this database
48 	@property string name()
49 	{
50 		return m_name;
51 	}
52 
53 	/// The client which represents the connection to the database server
54 	@property MongoClient client()
55 	{
56 		return m_client;
57 	}
58 
59 	/** Accesses the collections of this database.
60 
61 		Returns: The collection with the given name
62 	*/
63 	MongoCollection opIndex(string name)
64 	{
65 		return MongoCollection(this, name);
66 	}
67 
68 	/** Retrieves the last error code (if any) from the database server.
69 
70 		Exact object format is not documented. MongoErrorDescription signature will be
71 		updated upon any issues. Note that this method will execute a query to service
72 		collection and thus is far from being "free".
73 
74 		Returns: struct storing data from MongoDB db.getLastErrorObj() object
75  	*/
76 	MongoErrorDescription getLastError()
77 	{
78 		return m_client.lockConnection().getLastError(m_name);
79 	}
80 
81 	/** Returns recent log messages for this database from the database server.
82 
83 		See $(LINK http://www.mongodb.org/display/DOCS/getLog+Command).
84 
85 	 	Params:
86 	 		mask = "global" or "rs" or "startupWarnings". Refer to official MongoDB docs.
87 
88 	 	Returns: Bson document with recent log messages from MongoDB service.
89  	 */
90 	Bson getLog(string mask)
91 	{
92 		static struct CMD {
93 			string getLog;
94 		}
95 		CMD cmd;
96 		cmd.getLog = mask;
97 		return runCommand(cmd);
98 	}
99 
100 	/** Performs a filesystem/disk sync of the database on the server.
101 
102 		See $(LINK http://www.mongodb.org/display/DOCS/fsync+Command)
103 
104 		Returns: check documentation
105  	 */
106 	Bson fsync(bool async = false)
107 	{
108 		static struct CMD {
109 			int fsync = 1;
110 			bool async;
111 		}
112 		CMD cmd;
113 		cmd.async = async;
114 		return runCommand(cmd);
115 	}
116 
117 
118 	/** Generic means to run commands on the database.
119 
120 		See $(LINK http://www.mongodb.org/display/DOCS/Commands) for a list
121 		of possible values for command_and_options.
122 
123 		Note that some commands return a cursor instead of a single document.
124 		In this case, use `runListCommand` instead of `runCommand` to be able
125 		to properly iterate over the results.
126 
127 		Params:
128 			command_and_options = Bson object containing the command to be executed
129 				as well as the command parameters as fields
130 
131 		Returns: The raw response of the MongoDB server
132 	*/
133 	Bson runCommand(T)(T command_and_options)
134 	{
135 		return m_client.getCollection(m_commandCollection).findOne(command_and_options);
136 	}
137 	/// ditto
138 	MongoCursor!R runListCommand(R = Bson, T)(T command_and_options)
139 	{
140 		auto cur = runCommand(command_and_options);
141 		if (cur["ok"].get!double != 1.0)
142 			throw new MongoException("MongoDB list command failed: " ~ cur["errmsg"].get!string);
143 
144 		auto cursorid = cur["cursor"]["id"].get!long;
145 		static if (is(R == Bson))
146 			auto existing = cur["cursor"]["firstBatch"].get!(Bson[]);
147 		else auto existing = cur["cursor"]["firstBatch"].deserializeBson!(R[]);
148 		return MongoCursor!R(m_client, m_commandCollection, cursorid, existing);
149 	}
150 }