1 /**
2 	MongoDB index API definitions.
3 
4 	Copyright: © 2020-2022 Jan Jurzitza
5 	License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file.
6 	Authors: Jan Jurzitza
7 */
8 module vibe.db.mongo.impl.index;
9 
10 @safe:
11 
12 import core.time;
13 
14 import std.array;
15 import std.typecons;
16 
17 import vibe.db.mongo.collection;
18 import vibe.data.bson;
19 
20 deprecated("Use CreateIndexOptions instead")
21 enum IndexFlags {
22 	none = 0,
23 	unique = 1<<0,
24 	dropDuplicates = 1<<2,
25 	background = 1<<3,
26 	sparse = 1<<4,
27 	expireAfterSeconds = 1<<5,
28 
29 	None = none, /// Deprecated compatibility alias, use `none` instead.
30 	Unique = unique, /// Deprecated compatibility alias, use `unique` instead.
31 	DropDuplicates = dropDuplicates, /// Deprecated compatibility alias, use `dropDuplicates` instead.
32 	Background = background, /// Deprecated compatibility alias, use `background` instead.
33 	Sparse = sparse, /// Deprecated compatibility alias, use `sparse` instead.
34 	ExpireAfterSeconds = expireAfterSeconds, /// Deprecated compatibility alias, use `expireAfterSeconds` instead.
35 }
36 
37 struct IndexModel
38 {
39 	Bson keys = Bson.emptyObject;
40 	IndexOptions options;
41 
42 	/**
43 		Adds a single field or multikey index with a direction.
44 
45 		Call this method multiple times with different fields to create a
46 		compound index.
47 
48 		Params:
49 		  field = the name of the field to index
50 		  direction = `1` for ascending or `-1` for descending
51 
52 		Returns: this IndexModel instance (caller)
53 	*/
54 	ref IndexModel add(string field, int direction) return
55 	@safe {
56 		// bson objects keep order
57 		keys[field] = Bson(direction);
58 		return this;
59 	}
60 
61 	/**
62 		Adds an index with a given index type. Use `IndexType` for a type-safe
63 		setting of the string.
64 
65 		Params:
66 		  field = the name of the field to index
67 		  type = the index type to use
68 
69 		Returns: this IndexModel instance (caller)
70 	*/
71 	ref IndexModel add(string field, string type) return
72 	@safe {
73 		// bson objects keep order
74 		keys[field] = Bson(type);
75 		return this;
76 	}
77 
78 	/**
79 		Sets the options member of this IndexModel.
80 
81 		Returns: this IndexModel instance (caller)
82 	*/
83 	ref IndexModel withOptions(IndexOptions options) return
84 	@safe {
85 		this.options = options;
86 		return this;
87 	}
88 
89 	string name() const
90 	@property @safe {
91 		if (options.name.length)
92 		{
93 			return options.name;
94 		}
95 		else
96 		{
97 			auto indexname = appender!string();
98 			bool first = true;
99 			foreach (string key, value; keys.byKeyValue) {
100 				if (!first) indexname.put('_');
101 				else first = false;
102 				indexname.put(key);
103 				indexname.put('_');
104 
105 				if (value.type == Bson.Type..string)
106 					indexname.put(value.get!string);
107 				else
108 					indexname.put(value.toString());
109 			}
110 			return indexname.data;
111 		}
112 	}
113 }
114 
115 /**
116 	Specifies the different index types which are available for index creation.
117 
118 	See_Also: $(LINK https://docs.mongodb.com/manual/indexes/#index-types)
119 */
120 enum IndexType : string
121 {
122 	/**
123 		Legacy 2D plane index used in MongoDB 2.2 and earlier. Doesn't support
124 		GeoJSON objects. Uses planar geometry to return results.
125 
126 		See_Also: $(LINK https://docs.mongodb.com/manual/core/2d/)
127 	*/
128 	legacy2D = "2d",
129 
130 	/**
131 		2D sphere index that calculates geometries on an earth-like sphere.
132 		Supports storing as GeoJSON objects.
133 
134 		See_Also: $(LINK https://docs.mongodb.com/manual/core/2dsphere/)
135 	*/
136 	sphere2D = "2dsphere",
137 
138 	/**
139 		A geoHaystack index is a special index that is optimized to return
140 		results over small areas. geoHaystack indexes improve performance on
141 		queries that use flat geometry.
142 
143 		See_Also: $(LINK https://docs.mongodb.com/manual/core/geohaystack/)
144 	*/
145 	geoHaystack = "geoHaystack",
146 
147 	/**
148 		Creates a text index which supports searching for string content in a
149 		collection. These text indexes do not store language-specific stop words
150 		and stem the words in a collection to only store root words.
151 
152 		See_Also: $(LINK https://docs.mongodb.com/manual/core/index-text/)
153 	*/
154 	text = "text",
155 
156 	/**
157 		To support hash based sharding, MongoDB provides a hashed index type,
158 		which indexes the hash of the value of a field. These indexes have a
159 		more random distribution of values along their range, but only support
160 		equality matches and cannot support range-based queries.
161 
162 		See_Also: $(LINK https://docs.mongodb.com/manual/core/index-hashed/)
163 	*/
164 	hashed = "hashed",
165 }
166 
167 /**
168 	See_Also: $(LINK https://docs.mongodb.com/manual/reference/command/createIndexes/)
169 
170 	Standards: $(LINK https://github.com/mongodb/specifications/blob/0c6e56141c867907aacf386e0cbe56d6562a0614/source/index-management.rst#common-api-components)
171 */
172 struct IndexOptions
173 {
174 	/**
175 		Specifying true directs MongoDB to build the index in the background.
176 		Background builds do not block operations on the collection.
177 		Since MongoDB 4.2 indices are built on the background by default.
178 		In MongoDB 4.0 and before, this defaults to `false`.
179 	*/
180 	@embedNullable @until(WireVersion.v42)
181 	Nullable!bool background;
182 
183 	/**
184 		Specifies the length in time, in seconds, for documents to remain in a
185 		collection.
186 	*/
187 	@embedNullable Nullable!int expireAfterSeconds;
188 
189 	void expireAfter(Duration d)
190 	@safe {
191 		expireAfterSeconds = cast(int)d.total!"seconds";
192 	}
193 
194 	/**
195 		Optionally specify a specific name for the index outside of the default
196 		generated name. If none is provided then the name is generated in the
197 		format "[field]_[direction]"
198 	*/
199 	@ignore string name;
200 
201 	/**
202 		Tells the index to only reference documents with the specified field in
203 		the index.
204 	*/
205 	@embedNullable Nullable!bool sparse;
206 
207 	/**
208 		Allows configuring the storage engine on a per-index basis.
209 	*/
210 	@embedNullable @since(WireVersion.v30)
211 	Nullable!Bson storageEngine;
212 
213 	/**
214 		Forces the index to be unique.
215 	*/
216 	@embedNullable Nullable!bool unique;
217 
218 	/**
219 		Creates a unique index on a field that may have duplicates.
220 	*/
221 	@embedNullable @until(WireVersion.v26)
222 	Nullable!bool dropDups;
223 
224 	/**
225 		Specifies the index version number, either 0 or 1.
226 	*/
227 	@embedNullable @(.name("v")) @until(WireVersion.v26)
228 	Nullable!int version_;
229 
230 	/**
231 		Default language for text indexes. Is "english" if none is provided.
232 	*/
233 	@embedNullable @(.name("default_language"))
234 	Nullable!string defaultLanguage;
235 
236 	/**
237 		Specifies the field in the document to override the language.
238 	*/
239 	@embedNullable @(.name("language_override"))
240 	Nullable!string languageOverride;
241 
242 	/**
243 		Sets the text index version number.
244 
245 		MongoDB 2.4 can only support version 1.
246 
247 		MongoDB 2.6 and higher may support version 1 or 2.
248 	*/
249 	@embedNullable @since(WireVersion.v26)
250 	Nullable!int textIndexVersion;
251 
252 	/**
253 		Specifies fields in the index and their corresponding weight values.
254 	*/
255 	@embedNullable Nullable!Bson weights;
256 
257 	/**
258 		Sets the 2dsphere index version number.
259 
260 		MongoDB 2.4 can only support version 1.
261 
262 		MongoDB 2.6 and higher may support version 1 or 2.
263 
264 		MongoDB 3.2 and higher may support version 2 or 3.
265 	*/
266 	@embedNullable @(.name("2dsphereIndexVersion")) @since(WireVersion.v26)
267 	Nullable!int _2dsphereIndexVersion;
268 
269 	/**
270 		For 2d indexes, the number of precision of the stored geo hash value of
271 		the location data.
272 	*/
273 	@embedNullable Nullable!int bits;
274 
275 	/**
276 		For 2d indexes, the upper inclusive boundary for the longitude and
277 		latitude values.
278 	*/
279 	@embedNullable Nullable!double max;
280 
281 	/**
282 		For 2d indexes, the lower inclusive boundary for the longitude and
283 		latitude values.
284 	*/
285 	@embedNullable Nullable!double min;
286 
287 	/**
288 		For geoHaystack indexes, specify the number of units within which to
289 		group the location values; i.e. group in the same bucket those location
290 		values that are within the specified number of units to each other.
291 
292 		The value must be greater than 0.
293 	*/
294 	@embedNullable Nullable!double bucketSize;
295 
296 	/**
297 		If specified, the index only references documents that match the filter
298 		expression. See
299 		$(LINK2 https://docs.mongodb.com/manual/core/index-partial/, Partial Indexes)
300 		for more information.
301 	*/
302 	@embedNullable @since(WireVersion.v32)
303 	Nullable!Bson partialFilterExpression;
304 
305 	/**
306 		Collation allows users to specify language-specific rules for string
307 		comparison, such as rules for letter-case and accent marks.
308 	*/
309 	@embedNullable @since(WireVersion.v34)
310 	Nullable!Collation collation;
311 
312 	/**
313 		Allows users to include or exclude specific field paths from a wildcard
314 		index using the `{ "$**": 1 }` key pattern.
315 	*/
316 	@embedNullable @since(WireVersion.v42)
317 	Nullable!Bson wildcardProjection;
318 }
319 
320 /// Standards: $(LINK https://github.com/mongodb/specifications/blob/0c6e56141c867907aacf386e0cbe56d6562a0614/source/index-management.rst#common-api-components)
321 struct CreateIndexOptions
322 {
323 	/**
324 		The maximum amount of time to allow the index build to take before
325 		returning an error. (not implemented)
326 	*/
327 	@embedNullable Nullable!long maxTimeMS;
328 }
329 
330 /// Same as $(LREF CreateIndexOptions)
331 alias CreateIndexesOptions = CreateIndexOptions;
332 
333 /// Standards: $(LINK https://github.com/mongodb/specifications/blob/f4020bdb6ec093fcd259984e6ff6f42356b17d0e/source/index-management.rst#standard-api)
334 struct DropIndexOptions
335 {
336 	/**
337 		The maximum amount of time to allow the index drop to take before
338 		returning an error. (not implemented)
339 	*/
340 	@embedNullable Nullable!long maxTimeMS;
341 }
342 
343 /// Same as $(LREF DropIndexOptions)
344 alias DropIndexesOptions = DropIndexOptions;