** Represents a MongoDB index.
const class Index {
private const Namespace colNs
private const Namespace idxNs
private const ConnectionManager conMgr
** Use in 'key' arguments to denote field sort order.
static const Int ASC := 1
** Use in 'key' arguments to denote field sort order.
static const Int DESC := -1
** Use in 'key' arguments to denote a text index on the field.
static const Str TEXT := "text"
** The name of this index.
const Str name
** Creates an 'Index' with the given details.
new make(ConnectionManager conMgr, Str collectionQname, Str indexName, |This|? f := null) {
f?.call(this)
this.conMgr = conMgr
this.colNs = Namespace(collectionQname)
this.idxNs = colNs.withCollection("system.indexes")
this.name = indexName
}
internal new makeWithNs(ConnectionManager conMgr, Namespace namespace, Str indexName, |This|? f := null) {
f?.call(this)
this.conMgr = conMgr
this.colNs = namespace
this.idxNs = colNs.withCollection("system.indexes")
this.name = indexName
}
** Returns index info.
**
** Returns 'null' if index does not exist.
**
** @see `http://docs.mongodb.org/manual/reference/method/db.collection.getIndexes/`
[Str:Obj?]? info() {
res := cmd.add("listIndexes", colNs.collectionName).run
nfo := ([Str:Obj?][]) res["cursor"]->get("firstBatch")
return nfo.find { it["name"] == name }
}
** Returns 'true' if this index exists.
Bool exists() {
info != null
}
** Creates this index.
**
** 'key' is a map of fields to index type.
** Values may either be the standard Mongo '1' and '-1' for ascending / descending, the
** strings 'ASC' / 'DESC', or the string 'TEXT'.
**
** syntax: fantom
** index.create(["dateAdded" : Index.ASC])
**
** Note that should 'key' contain more than 1 entry, it must be ordered.
**
** The 'options' parameter is merged with the Mongo command.
** Options are numerous (see the MongoDB documentation for details) but common options are:
**
** table:
** Name Type Desc
** ---- ---- ----
** background Bool Builds the index in the background so it does not block other database activities. Defaults to 'false'.
** sparse Bool Only reference documents with the specified field. Uses less space but behave differently in sorts. Defaults to 'false'.
** expireAfterSeconds Int Specifies a Time To Live (TTL) in seconds that controls how long documents are retained.
** weights Map Specifies the relative weights of fields to use in text searching. See [Control Search Results with Weights]`https://docs.mongodb.com/manual/tutorial/control-results-of-text-search/`.
** default_language Str The language used to create text indexes. See [Supported Text Search Languages]`https://docs.mongodb.com/manual/reference/text-search-languages/#text-search-languages`. Defaults to 'english'.
**
** @see `http://docs.mongodb.org/manual/reference/command/createIndexes/`
This create(Str:Obj key, Bool? unique := false, Str:Obj options := [:]) {
if (key.size > 1 && key.ordered == false)
throw ArgErr(ErrMsgs.cursor_mapNotOrdered(key))
// there's no createIndexMulti 'cos I figure no novice will need to create multiple indexes at once!
if (unique == true) options.set("unique", unique)
cmd .add("createIndexes", colNs.collectionName)
.add("indexes", [cmd
.add("key", Utils.convertAscDesc(key))
.add("name", name)
.addAll(options)
.query
])
.run
// [createdCollectionAutomatically:false, numIndexesBefore:1, numIndexesAfter:2, ok:1.0]
return this
}
** Ensures this index exists.
** If the index does not exist, it is created.
** If it exists but with a different key / options, it is dropped and re-created.
**
** Returns 'true' if the index was (re)-created, 'false' if nothing changed.
**
** syntax: fantom
**
** index.ensure(["dateAdded" : Index.ASC])
**
** Note that should 'key' contain more than 1 entry, it must be ordered.
**
** The 'options' parameter is merged with the Mongo command.
** Options are numerous (see the MongoDB documentation for details) but common options are:
**
** table:
** Name Type Desc
** ---- ---- ----
** background Bool Builds the index in the background so it does not block other database activities.
** sparse Bool Only reference documents with the specified field. Uses less space but behave differently in sorts.
** expireAfterSeconds Int Specifies a Time To Live (TTL) in seconds that controls how long documents are retained.
** weights Map Specifies the relative weights of fields to use in text searching. See [Control Search Results with Weights]`https://docs.mongodb.com/manual/tutorial/control-results-of-text-search/`.
** default_language Str The language used to create text indexes. See [Text Search Languages]`https://docs.mongodb.com/manual/reference/text-search-languages/#text-search-languages` for a list of valid options. Defaults to 'english'.
**
** @see `http://docs.mongodb.org/manual/reference/command/createIndexes/`
Bool ensure(Str:Obj key, Bool? unique := false, Str:Obj options := [:]) {
if (key.size > 1 && key.ordered == false)
throw ArgErr(ErrMsgs.cursor_mapNotOrdered(key))
if (!exists) {
create(key, unique, options)
return true
}
// if null or false, unique does not appear in the index info map
if (unique == true) options.set("unique", unique)
info := info
oldKeyMap := (Str:Obj?) info["key"]
newKeyMap := Map.make(oldKeyMap.typeof).addAll(Utils.convertAscDesc(key))
if (info.size == options.size + 4 && oldKeyMap == newKeyMap && options.all |v, k| { info[k] == v })
return false
drop
create(key, unique, options)
return true
}
** Drops this index, but only if it exists.
**
** If 'force' is 'true' then the index is dropped regardless.
** Note this may result in an error if the index doesn't exist.
**
** @see `http://docs.mongodb.org/manual/reference/command/dropIndexes/`
This drop(Bool force := false) {
if (force || exists) cmd.add("dropIndexes", colNs.collectionName).add("index", name).run
// [nIndexesWas:2, ok:1.0]
return this
}
// ---- Private Methods -----------------------------------------------------------------------
private Cmd cmd(Str? action := null) {
Cmd(conMgr, colNs, action)
}
// ---- Obj Overrides -------------------------------------------------------------------------
@NoDoc
override Str toStr() {
"${idxNs.databaseName}::${name}"
}
}