From eea4c94b1ada0ad56390970f757a962c04f477a7 Mon Sep 17 00:00:00 2001 From: Frank Celler Date: Sun, 29 Apr 2012 14:14:52 +0200 Subject: [PATCH] added constraint flag --- .../Examples.Durham/ensure-geo-index-array | 2 +- Doxygen/Examples.Durham/ensure-geo-index-list | 2 +- Doxygen/Examples.Durham/fluent17 | 2 +- Doxygen/Examples.Durham/fluent18 | 4 +- Makefile.in | 3 +- Makefile.unittests | 5 +- RestServer/index-geo.dox | 8 + V8/v8-vocbase.cpp | 215 +++++++++--------- VocBase/index.c | 102 +++++---- VocBase/index.h | 16 +- VocBase/query-join-execute.c | 4 +- VocBase/simple-collection.c | 143 +++++++----- VocBase/simple-collection.h | 26 ++- js/common/tests/shell-index-geo.js | 114 ++++++++-- js/server/modules/simple-query.js | 8 +- 15 files changed, 404 insertions(+), 250 deletions(-) diff --git a/Doxygen/Examples.Durham/ensure-geo-index-array b/Doxygen/Examples.Durham/ensure-geo-index-array index 2989bb9c7b..d9b4a75803 100644 --- a/Doxygen/Examples.Durham/ensure-geo-index-array +++ b/Doxygen/Examples.Durham/ensure-geo-index-array @@ -1,5 +1,5 @@ avocado> db.geo2.ensureGeoIndex("location.latitude", "location.longitude"); -{ "id" : "87612/1070652", "type" : "geo", "fields" : ["location.latitude", "location.longitude"], "isNewlyCreated" : true } +{ "id" : "87612/1070652", "type" : "geo2", "fields" : ["location.latitude", "location.longitude"], "isNewlyCreated" : true } avocado> for (i = -90; i <= 90; i += 10) { .......> for (j = -180; j <= 180; j += 10) { diff --git a/Doxygen/Examples.Durham/ensure-geo-index-list b/Doxygen/Examples.Durham/ensure-geo-index-list index f2ae399e4d..01009169b7 100644 --- a/Doxygen/Examples.Durham/ensure-geo-index-list +++ b/Doxygen/Examples.Durham/ensure-geo-index-list @@ -1,5 +1,5 @@ avocado> db.geo.ensureGeoIndex("loc"); -{ "id" : "127629/47772301", "type" : "geo", "geoJson" : false, "fields" : ["loc"], "isNewlyCreated" : true } +{ "id" : "127629/47772301", "type" : "geo1", "geoJson" : false, "fields" : ["loc"], "isNewlyCreated" : true } avocado> for (i = -90; i <= 90; i += 10) { .......> for (j = -180; j <= 180; j += 10) { diff --git a/Doxygen/Examples.Durham/fluent17 b/Doxygen/Examples.Durham/fluent17 index 5c9b66a78c..8282f85623 100644 --- a/Doxygen/Examples.Durham/fluent17 +++ b/Doxygen/Examples.Durham/fluent17 @@ -2,7 +2,7 @@ avocado> db.examples.ensureGeoIndex("location"); 4545321 avocado> db.examples.getIndexes(); -[ { "iid" : 4545321, "type" : "geo", "location" : "location" } ] +[ { "iid" : 4545321, "type" : "geo1", "location" : "location" } ] avocado> db.examples.dropIndex(4545321); true diff --git a/Doxygen/Examples.Durham/fluent18 b/Doxygen/Examples.Durham/fluent18 index 378c233123..63320e3c45 100644 --- a/Doxygen/Examples.Durham/fluent18 +++ b/Doxygen/Examples.Durham/fluent18 @@ -1,5 +1,5 @@ avocado> db.examples.getIndexes(); [ - { "iid" : 4701883, "type" : "geo", "location" : "work" }, - { "iid" : 4545321, "type" : "geo", "location" : "home" } + { "iid" : 4701883, "type" : "geo1", "location" : "work" }, + { "iid" : 4545321, "type" : "geo1", "location" : "home" } ] diff --git a/Makefile.in b/Makefile.in index 22227a6e70..a4cbd1d27b 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1021,7 +1021,8 @@ CLIENT_OPT := --startup.directory ./js --startup.modules-path ./js/client/module ################################################################################ SHELL_SERVER = @srcdir@/js/common/tests/shell-document.js \ @srcdir@/js/common/tests/shell-edge.js \ - @srcdir@/js/common/tests/shell-collection.js + @srcdir@/js/common/tests/shell-collection.js \ + @srcdir@/js/common/tests/shell-index-geo.js UNITTESTS_SERVER = $(addprefix --unit-tests ,$(SHELL_SERVER)) diff --git a/Makefile.unittests b/Makefile.unittests index 86abf8dfeb..054cb18632 100644 --- a/Makefile.unittests +++ b/Makefile.unittests @@ -128,7 +128,8 @@ endif SHELL_SERVER = @srcdir@/js/common/tests/shell-document.js \ @srcdir@/js/common/tests/shell-edge.js \ - @srcdir@/js/common/tests/shell-collection.js + @srcdir@/js/common/tests/shell-collection.js \ + @srcdir@/js/common/tests/shell-index-geo.js .PHONY: unittests-shell-server @@ -159,7 +160,7 @@ SHELL_SERVER_AHUACATL = @srcdir@/js/server/tests/ahuacatl-operators.js \ @srcdir@/js/server/tests/ahuacatl-functions.js \ @srcdir@/js/server/tests/ahuacatl-queries-collection.js \ @srcdir@/js/server/tests/ahuacatl-queries-noncollection.js - + .PHONY: unittests-shell-server-ahuacatl diff --git a/RestServer/index-geo.dox b/RestServer/index-geo.dox index b98f9f8d62..c5d80f65f1 100644 --- a/RestServer/index-geo.dox +++ b/RestServer/index-geo.dox @@ -55,6 +55,14 @@ /// blog /// for details. /// +/// A geo-spatial index assumes that the latitude is between -90 and +/// 90 degree and the longitude is between -180 and 180 degree. A geo +/// index will ignore all documents which do not fulfill these +/// requirements. +/// +/// A geo-spatial constraint makes the same assumptions, but documents +/// not fulfill the requirements are rejected. +/// /// @section IndexGeoShell Accessing Geo Indexes from the Shell /////////////////////////////////////////////////////////////// /// diff --git a/V8/v8-vocbase.cpp b/V8/v8-vocbase.cpp index fe5ffce0ac..7e564d54bf 100644 --- a/V8/v8-vocbase.cpp +++ b/V8/v8-vocbase.cpp @@ -1183,6 +1183,114 @@ static v8::Handle CollectionVocBase (v8::Arguments const& argv, bool return scope.Close(edge ? TRI_WrapEdgesCollection(collection) : TRI_WrapCollection(collection)); } +//////////////////////////////////////////////////////////////////////////////// +/// @brief ensures that a geo index or constraint exists +//////////////////////////////////////////////////////////////////////////////// + +static v8::Handle EnsureGeoIndexVocbaseCol (v8::Arguments const& argv, bool constraint) { + v8::HandleScope scope; + + v8::Handle err; + TRI_vocbase_col_t const* collection = UseCollection(argv.Holder(), &err); + + if (collection == 0) { + return scope.Close(v8::ThrowException(err)); + } + + TRI_doc_collection_t* doc = collection->_collection; + + if (doc->base._type != TRI_COL_TYPE_SIMPLE_DOCUMENT) { + ReleaseCollection(collection); + return scope.Close(v8::ThrowException(CreateErrorObject(TRI_ERROR_INTERNAL, "unknown collection type"))); + } + + TRI_sim_collection_t* sim = (TRI_sim_collection_t*) doc; + TRI_index_t* idx = 0; + bool created; + + // ............................................................................. + // case: + // ............................................................................. + + if (argv.Length() == 1) { + v8::String::Utf8Value loc(argv[0]); + + if (*loc == 0) { + ReleaseCollection(collection); + return scope.Close(v8::ThrowException(CreateErrorObject(TRI_ERROR_ILLEGAL_OPTION, " must be an attribute path"))); + } + + idx = TRI_EnsureGeoIndex1SimCollection(sim, *loc, false, constraint, &created); + } + + // ............................................................................. + // case: , + // ............................................................................. + + else if (argv.Length() == 2 && (argv[1]->IsBoolean() || argv[1]->IsBooleanObject())) { + v8::String::Utf8Value loc(argv[0]); + + if (*loc == 0) { + ReleaseCollection(collection); + return scope.Close(v8::ThrowException(CreateErrorObject(TRI_ERROR_ILLEGAL_OPTION, " must be an attribute path"))); + } + + idx = TRI_EnsureGeoIndex1SimCollection(sim, *loc, TRI_ObjectToBoolean(argv[1]), constraint, &created); + } + + // ............................................................................. + // case: , + // ............................................................................. + + else if (argv.Length() == 2) { + v8::String::Utf8Value lat(argv[0]); + v8::String::Utf8Value lon(argv[1]); + + if (*lat == 0) { + ReleaseCollection(collection); + return scope.Close(v8::ThrowException(CreateErrorObject(TRI_ERROR_ILLEGAL_OPTION, " must be an attribute path"))); + } + + if (*lon == 0) { + ReleaseCollection(collection); + return scope.Close(v8::ThrowException(CreateErrorObject(TRI_ERROR_ILLEGAL_OPTION, " must be an attribute path"))); + } + + idx = TRI_EnsureGeoIndex2SimCollection(sim, *lat, *lon, constraint, &created); + } + + // ............................................................................. + // error case + // ............................................................................. + + else { + ReleaseCollection(collection); + return scope.Close(v8::ThrowException(CreateErrorObject(TRI_ERROR_ILLEGAL_OPTION, + "usage: ensureGeoIndex(, ) or ensureGeoIndex(, [])"))); + } + + if (idx == 0) { + ReleaseCollection(collection); + return scope.Close(v8::ThrowException(CreateErrorObject(TRI_errno(), "index could not be created"))); + } + + TRI_json_t* json = idx->json(idx, collection->_collection); + + if (!json) { + return scope.Close(v8::ThrowException(v8::String::New("out of memory"))); + } + + v8::Handle index = IndexRep(&collection->_collection->base, json); + TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json); + + if (index->IsObject()) { + index->ToObject()->Set(v8::String::New("isNewlyCreated"), created ? v8::True() : v8::False()); + } + + ReleaseCollection(collection); + return scope.Close(index); +} + //////////////////////////////////////////////////////////////////////////////// /// @} //////////////////////////////////////////////////////////////////////////////// @@ -1918,7 +2026,7 @@ static v8::Handle JS_NearQuery (v8::Arguments const& argv) { return scope.Close(v8::ThrowException(err)); } - if (idx->_type != TRI_IDX_TYPE_GEO_INDEX) { + if (idx->_type != TRI_IDX_TYPE_GEO_INDEX1 && idx->_type != TRI_IDX_TYPE_GEO_INDEX2) { ReleaseCollection(collection); return scope.Close(v8::ThrowException(CreateErrorObject(TRI_ERROR_BAD_PARAMETER, "index must be a geo-index"))); } @@ -2024,7 +2132,7 @@ static v8::Handle JS_WithinQuery (v8::Arguments const& argv) { return scope.Close(v8::ThrowException(err)); } - if (idx->_type != TRI_IDX_TYPE_GEO_INDEX) { + if (idx->_type != TRI_IDX_TYPE_GEO_INDEX1 && idx->_type != TRI_IDX_TYPE_GEO_INDEX2) { ReleaseCollection(collection); return scope.Close(v8::ThrowException(CreateErrorObject(TRI_ERROR_BAD_PARAMETER, "index must be a geo-index"))); } @@ -4245,107 +4353,7 @@ static v8::Handle JS_DropIndexVocbaseCol (v8::Arguments const& argv) //////////////////////////////////////////////////////////////////////////////// static v8::Handle JS_EnsureGeoIndexVocbaseCol (v8::Arguments const& argv) { - v8::HandleScope scope; - - v8::Handle err; - TRI_vocbase_col_t const* collection = UseCollection(argv.Holder(), &err); - - if (collection == 0) { - return scope.Close(v8::ThrowException(err)); - } - - TRI_doc_collection_t* doc = collection->_collection; - - if (doc->base._type != TRI_COL_TYPE_SIMPLE_DOCUMENT) { - ReleaseCollection(collection); - return scope.Close(v8::ThrowException(CreateErrorObject(TRI_ERROR_INTERNAL, "unknown collection type"))); - } - - TRI_sim_collection_t* sim = (TRI_sim_collection_t*) doc; - TRI_index_t* idx = 0; - bool created; - - // ............................................................................. - // case: - // ............................................................................. - - if (argv.Length() == 1) { - v8::String::Utf8Value loc(argv[0]); - - if (*loc == 0) { - ReleaseCollection(collection); - return scope.Close(v8::ThrowException(CreateErrorObject(TRI_ERROR_ILLEGAL_OPTION, " must be an attribute path"))); - } - - idx = TRI_EnsureGeoIndexSimCollection(sim, *loc, false, &created); - } - - // ............................................................................. - // case: , - // ............................................................................. - - else if (argv.Length() == 2 && (argv[1]->IsBoolean() || argv[1]->IsBooleanObject())) { - v8::String::Utf8Value loc(argv[0]); - - if (*loc == 0) { - ReleaseCollection(collection); - return scope.Close(v8::ThrowException(CreateErrorObject(TRI_ERROR_ILLEGAL_OPTION, " must be an attribute path"))); - } - - idx = TRI_EnsureGeoIndexSimCollection(sim, *loc, TRI_ObjectToBoolean(argv[1]), &created); - } - - // ............................................................................. - // case: , - // ............................................................................. - - else if (argv.Length() == 2) { - v8::String::Utf8Value lat(argv[0]); - v8::String::Utf8Value lon(argv[1]); - - if (*lat == 0) { - ReleaseCollection(collection); - return scope.Close(v8::ThrowException(CreateErrorObject(TRI_ERROR_ILLEGAL_OPTION, " must be an attribute path"))); - } - - if (*lon == 0) { - ReleaseCollection(collection); - return scope.Close(v8::ThrowException(CreateErrorObject(TRI_ERROR_ILLEGAL_OPTION, " must be an attribute path"))); - } - - idx = TRI_EnsureGeoIndex2SimCollection(sim, *lat, *lon, &created); - } - - // ............................................................................. - // error case - // ............................................................................. - - else { - ReleaseCollection(collection); - return scope.Close(v8::ThrowException(CreateErrorObject(TRI_ERROR_ILLEGAL_OPTION, - "usage: ensureGeoIndex(, ) or ensureGeoIndex(, [])"))); - } - - if (idx == 0) { - ReleaseCollection(collection); - return scope.Close(v8::ThrowException(CreateErrorObject(TRI_errno(), "index could not be created"))); - } - - TRI_json_t* json = idx->json(idx, collection->_collection); - - if (!json) { - return scope.Close(v8::ThrowException(v8::String::New("out of memory"))); - } - - v8::Handle index = IndexRep(&collection->_collection->base, json); - TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json); - - if (index->IsObject()) { - index->ToObject()->Set(v8::String::New("isNewlyCreated"), created ? v8::True() : v8::False()); - } - - ReleaseCollection(collection); - return scope.Close(index); + return EnsureGeoIndexVocbaseCol(argv, false); } //////////////////////////////////////////////////////////////////////////////// @@ -4389,7 +4397,6 @@ static v8::Handle JS_EnsureUniqueConstraintVocbaseCol (v8::Arguments static v8::Handle JS_EnsureHashIndexVocbaseCol (v8::Arguments const& argv) { return EnsureHashSkipListIndex("ensureHashIndex", argv, false, 0); } - //////////////////////////////////////////////////////////////////////////////// /// @brief ensures that a priority queue index exists diff --git a/VocBase/index.c b/VocBase/index.c index 0319e69a15..a7b2bfd887 100644 --- a/VocBase/index.c +++ b/VocBase/index.c @@ -61,7 +61,8 @@ void TRI_FreeIndex (TRI_index_t* const idx) { LOG_TRACE("freeing index"); switch (idx->_type) { - case TRI_IDX_TYPE_GEO_INDEX: + case TRI_IDX_TYPE_GEO_INDEX1: + case TRI_IDX_TYPE_GEO_INDEX2: TRI_FreeGeoIndex(idx); break; @@ -221,8 +222,11 @@ char const* TRI_TypeNameIndex (const TRI_index_t* const idx) { case TRI_IDX_TYPE_SKIPLIST_INDEX: return "skiplist"; - case TRI_IDX_TYPE_GEO_INDEX: - return "geo"; + case TRI_IDX_TYPE_GEO_INDEX1: + return "geo1"; + + case TRI_IDX_TYPE_GEO_INDEX2: + return "geo2"; case TRI_IDX_TYPE_PRIMARY_INDEX: return "primary"; @@ -479,7 +483,7 @@ static bool ExtractDoubleList (TRI_shaper_t* shaper, } //////////////////////////////////////////////////////////////////////////////// -/// @brief inserts a new document, location is a list +/// @brief inserts a new document //////////////////////////////////////////////////////////////////////////////// static int InsertGeoIndex (TRI_index_t* idx, TRI_doc_mptr_t const* doc) { @@ -510,7 +514,12 @@ static int InsertGeoIndex (TRI_index_t* idx, TRI_doc_mptr_t const* doc) { } if (! ok) { - return false; + if (geo->_constraint) { + return TRI_set_errno(TRI_ERROR_AVOCADO_GEO_INDEX_VIOLATED); + } + else { + return TRI_ERROR_NO_ERROR; + } } // and insert into index @@ -530,8 +539,13 @@ static int InsertGeoIndex (TRI_index_t* idx, TRI_doc_mptr_t const* doc) { return TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY); } else if (res == -3) { - LOG_DEBUG("illegal geo-coordinates, ignoring entry"); - return TRI_set_errno(TRI_ERROR_AVOCADO_GEO_INDEX_VIOLATED); + if (geo->_constraint) { + LOG_DEBUG("illegal geo-coordinates, ignoring entry"); + return TRI_set_errno(TRI_ERROR_AVOCADO_GEO_INDEX_VIOLATED); + } + else { + return TRI_ERROR_NO_ERROR; + } } else if (res < 0) { return TRI_set_errno(TRI_ERROR_INTERNAL); @@ -541,7 +555,7 @@ static int InsertGeoIndex (TRI_index_t* idx, TRI_doc_mptr_t const* doc) { } //////////////////////////////////////////////////////////////////////////////// -/// @brief updates a document, location is a list +/// @brief updates a document //////////////////////////////////////////////////////////////////////////////// static int UpdateGeoIndex (TRI_index_t* idx, TRI_doc_mptr_t const* doc, TRI_shaped_json_t const* old) { @@ -577,7 +591,7 @@ static int UpdateGeoIndex (TRI_index_t* idx, TRI_doc_mptr_t const* doc, TRI_sha res = GeoIndex_remove(geo->_geoIndex, &gc); if (res != 0) { - LOG_WARNING("cannot remove old index entry: %d", res); + LOG_DEBUG("cannot remove old index entry: %d", res); } } @@ -591,7 +605,12 @@ static int UpdateGeoIndex (TRI_index_t* idx, TRI_doc_mptr_t const* doc, TRI_sha } if (! ok) { - return false; + if (geo->_constraint) { + return TRI_set_errno(TRI_ERROR_AVOCADO_GEO_INDEX_VIOLATED); + } + else { + return TRI_ERROR_NO_ERROR; + } } gc.latitude = latitude; @@ -611,8 +630,13 @@ static int UpdateGeoIndex (TRI_index_t* idx, TRI_doc_mptr_t const* doc, TRI_sha return TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY); } else if (res == -3) { - LOG_DEBUG("illegal geo-coordinates, ignoring entry"); - return TRI_set_errno(TRI_ERROR_AVOCADO_GEO_INDEX_VIOLATED); + if (geo->_constraint) { + LOG_DEBUG("illegal geo-coordinates, ignoring entry"); + return TRI_set_errno(TRI_ERROR_AVOCADO_GEO_INDEX_VIOLATED); + } + else { + return TRI_ERROR_NO_ERROR; + } } else if (res < 0) { return TRI_set_errno(TRI_ERROR_INTERNAL); @@ -622,7 +646,7 @@ static int UpdateGeoIndex (TRI_index_t* idx, TRI_doc_mptr_t const* doc, TRI_sha } //////////////////////////////////////////////////////////////////////////////// -/// @brief erases a document, location is a list +/// @brief erases a document //////////////////////////////////////////////////////////////////////////////// static int RemoveGeoIndex (TRI_index_t* idx, TRI_doc_mptr_t const* doc) { @@ -658,7 +682,7 @@ static int RemoveGeoIndex (TRI_index_t* idx, TRI_doc_mptr_t const* doc) { res = GeoIndex_remove(geo->_geoIndex, &gc); if (res != 0) { - LOG_WARNING("cannot remove old index entry: %d", res); + LOG_DEBUG("cannot remove old index entry: %d", res); return TRI_set_errno(TRI_ERROR_INTERNAL); } } @@ -670,7 +694,7 @@ static int RemoveGeoIndex (TRI_index_t* idx, TRI_doc_mptr_t const* doc) { /// @brief JSON description of a geo index, location is a list //////////////////////////////////////////////////////////////////////////////// -static TRI_json_t* JsonGeoIndex (TRI_index_t* idx, TRI_doc_collection_t const* collection) { +static TRI_json_t* JsonGeoIndex1 (TRI_index_t* idx, TRI_doc_collection_t const* collection) { TRI_json_t* json; TRI_json_t* fields; TRI_shape_path_t const* path; @@ -700,8 +724,9 @@ static TRI_json_t* JsonGeoIndex (TRI_index_t* idx, TRI_doc_collection_t const* c TRI_PushBack3ListJson(TRI_UNKNOWN_MEM_ZONE, fields, TRI_CreateStringCopyJson(TRI_UNKNOWN_MEM_ZONE, location)); TRI_Insert3ArrayJson(TRI_UNKNOWN_MEM_ZONE, json, "id", TRI_CreateNumberJson(TRI_UNKNOWN_MEM_ZONE, idx->_iid)); - TRI_Insert3ArrayJson(TRI_UNKNOWN_MEM_ZONE, json, "type", TRI_CreateStringCopyJson(TRI_UNKNOWN_MEM_ZONE, "geo")); + TRI_Insert3ArrayJson(TRI_UNKNOWN_MEM_ZONE, json, "type", TRI_CreateStringCopyJson(TRI_UNKNOWN_MEM_ZONE, "geo1")); TRI_Insert3ArrayJson(TRI_UNKNOWN_MEM_ZONE, json, "geoJson", TRI_CreateBooleanJson(TRI_UNKNOWN_MEM_ZONE, geo->_geoJson)); + TRI_Insert3ArrayJson(TRI_UNKNOWN_MEM_ZONE, json, "constraint", TRI_CreateBooleanJson(TRI_UNKNOWN_MEM_ZONE, geo->_constraint)); TRI_Insert3ArrayJson(TRI_UNKNOWN_MEM_ZONE, json, "fields", fields); return json; @@ -752,7 +777,8 @@ static TRI_json_t* JsonGeoIndex2 (TRI_index_t* idx, TRI_doc_collection_t const* TRI_PushBack3ListJson(TRI_UNKNOWN_MEM_ZONE, fields, TRI_CreateStringCopyJson(TRI_UNKNOWN_MEM_ZONE, longitude)); TRI_Insert3ArrayJson(TRI_UNKNOWN_MEM_ZONE, json, "id", TRI_CreateNumberJson(TRI_UNKNOWN_MEM_ZONE, idx->_iid)); - TRI_Insert3ArrayJson(TRI_UNKNOWN_MEM_ZONE, json, "type", TRI_CreateStringCopyJson(TRI_UNKNOWN_MEM_ZONE, "geo")); + TRI_Insert3ArrayJson(TRI_UNKNOWN_MEM_ZONE, json, "type", TRI_CreateStringCopyJson(TRI_UNKNOWN_MEM_ZONE, "geo2")); + TRI_Insert3ArrayJson(TRI_UNKNOWN_MEM_ZONE, json, "constraint", TRI_CreateBooleanJson(TRI_UNKNOWN_MEM_ZONE, geo->_constraint)); TRI_Insert3ArrayJson(TRI_UNKNOWN_MEM_ZONE, json, "fields", fields); return json; @@ -775,40 +801,38 @@ static TRI_json_t* JsonGeoIndex2 (TRI_index_t* idx, TRI_doc_collection_t const* /// @brief creates a geo-index for lists //////////////////////////////////////////////////////////////////////////////// -TRI_index_t* TRI_CreateGeoIndex (struct TRI_doc_collection_s* collection, - char const* locationName, - TRI_shape_pid_t location, - bool geoJson) { +TRI_index_t* TRI_CreateGeoIndex1 (struct TRI_doc_collection_s* collection, + char const* locationName, + TRI_shape_pid_t location, + bool geoJson, + bool constraint) { TRI_geo_index_t* geo; char* ln; geo = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_geo_index_t), false); + if (geo == NULL) { TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY); return NULL; } ln = TRI_DuplicateString(locationName); - if (ln == NULL) { - TRI_Free(TRI_UNKNOWN_MEM_ZONE, geo); - TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY); - return NULL; - } TRI_InitVectorString(&geo->base._fields, TRI_UNKNOWN_MEM_ZONE); geo->base._iid = TRI_NewTickVocBase(); - geo->base._type = TRI_IDX_TYPE_GEO_INDEX; + geo->base._type = TRI_IDX_TYPE_GEO_INDEX1; geo->base._collection = collection; geo->base._unique = false; geo->base.insert = InsertGeoIndex; geo->base.remove = RemoveGeoIndex; geo->base.update = UpdateGeoIndex; - geo->base.json = JsonGeoIndex; + geo->base.json = JsonGeoIndex1; TRI_PushBackVectorString(&geo->base._fields, ln); + geo->_constraint = constraint; geo->_geoIndex = GeoIndex_new(); geo->_variant = geoJson ? INDEX_GEO_COMBINED_LAT_LON : INDEX_GEO_COMBINED_LON_LAT; @@ -828,36 +852,26 @@ TRI_index_t* TRI_CreateGeoIndex2 (struct TRI_doc_collection_s* collection, char const* latitudeName, TRI_shape_pid_t latitude, char const* longitudeName, - TRI_shape_pid_t longitude) { + TRI_shape_pid_t longitude, + bool constraint) { TRI_geo_index_t* geo; char* lat; char* lon; geo = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_geo_index_t), false); + if (geo == NULL) { TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY); return NULL; } lat = TRI_DuplicateString(latitudeName); - if (lat == NULL) { - TRI_Free(TRI_UNKNOWN_MEM_ZONE, geo); - TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY); - return NULL; - } - lon = TRI_DuplicateString(longitudeName); - if (lon == NULL) { - TRI_Free(TRI_UNKNOWN_MEM_ZONE, geo); - TRI_Free(TRI_UNKNOWN_MEM_ZONE, lat); - TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY); - return NULL; - } TRI_InitVectorString(&geo->base._fields, TRI_UNKNOWN_MEM_ZONE); geo->base._iid = TRI_NewTickVocBase(); - geo->base._type = TRI_IDX_TYPE_GEO_INDEX; + geo->base._type = TRI_IDX_TYPE_GEO_INDEX2; geo->base._collection = collection; geo->base._unique = false; @@ -869,6 +883,7 @@ TRI_index_t* TRI_CreateGeoIndex2 (struct TRI_doc_collection_s* collection, TRI_PushBackVectorString(&geo->base._fields, lat); TRI_PushBackVectorString(&geo->base._fields, lon); + geo->_constraint = constraint; geo->_geoIndex = GeoIndex_new(); geo->_variant = INDEX_GEO_INDIVIDUAL_LAT_LON; @@ -1656,7 +1671,7 @@ HashIndexElements* TRI_LookupHashIndex(TRI_index_t* idx, TRI_json_t* parameterLi // ----------------------------------------------------------------------------- -// --SECTION-- PRIVATE FUNCTIONS +// --SECTION-- private functions // ----------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// @@ -2152,7 +2167,6 @@ static int UpdatePriorityQueueIndex (TRI_index_t* idx, else if (res != TRI_ERROR_NO_ERROR) { - return res; } diff --git a/VocBase/index.h b/VocBase/index.h index 99d1482c24..641a009ed6 100644 --- a/VocBase/index.h +++ b/VocBase/index.h @@ -72,7 +72,8 @@ typedef TRI_voc_tick_t TRI_idx_iid_t; typedef enum { TRI_IDX_TYPE_PRIMARY_INDEX, - TRI_IDX_TYPE_GEO_INDEX, + TRI_IDX_TYPE_GEO_INDEX1, + TRI_IDX_TYPE_GEO_INDEX2, TRI_IDX_TYPE_HASH_INDEX, TRI_IDX_TYPE_PRIORITY_QUEUE_INDEX, TRI_IDX_TYPE_SKIPLIST_INDEX @@ -125,6 +126,7 @@ typedef struct TRI_geo_index_s { TRI_shape_pid_t _longitude; bool _geoJson; + bool _constraint; } TRI_geo_index_t; @@ -262,10 +264,11 @@ void TRI_FreePrimaryIndex (TRI_index_t*); /// first and latitude second. //////////////////////////////////////////////////////////////////////////////// -TRI_index_t* TRI_CreateGeoIndex (struct TRI_doc_collection_s*, - char const* locationName, - TRI_shape_pid_t, - bool geoJson); +TRI_index_t* TRI_CreateGeoIndex1 (struct TRI_doc_collection_s*, + char const* locationName, + TRI_shape_pid_t, + bool geoJson, + bool constraint); //////////////////////////////////////////////////////////////////////////////// /// @brief creates a geo-index for arrays @@ -275,7 +278,8 @@ TRI_index_t* TRI_CreateGeoIndex2 (struct TRI_doc_collection_s*, char const* latitudeName, TRI_shape_pid_t, char const* longitudeName, - TRI_shape_pid_t); + TRI_shape_pid_t, + bool constraint); //////////////////////////////////////////////////////////////////////////////// /// @brief frees the memory allocated, but does not free the pointer diff --git a/VocBase/query-join-execute.c b/VocBase/query-join-execute.c index 3fe686d82d..4e4f71fef3 100644 --- a/VocBase/query-join-execute.c +++ b/VocBase/query-join-execute.c @@ -174,7 +174,7 @@ static TRI_data_feeder_t* DetermineGeoIndexUsage (TRI_query_instance_t* const in idx = (TRI_index_t*) indexes->_buffer[i]; - if (idx->_type != TRI_IDX_TYPE_GEO_INDEX) { + if (idx->_type != TRI_IDX_TYPE_GEO_INDEX1 && idx->_type != TRI_IDX_TYPE_GEO_INDEX2) { // ignore all indexes except geo indexes here continue; } @@ -250,7 +250,7 @@ static TRI_data_feeder_t* DetermineIndexUsage (TRI_query_instance_t* const insta QL_optimize_range_compare_type_e lastCompareType = COMPARE_TYPE_UNKNOWN; size_t j; - if (idx->_type == TRI_IDX_TYPE_GEO_INDEX) { + if (idx->_type == TRI_IDX_TYPE_GEO_INDEX1 || idx->_type == TRI_IDX_TYPE_GEO_INDEX2) { // ignore all geo indexes here continue; } diff --git a/VocBase/simple-collection.c b/VocBase/simple-collection.c index 273eea4802..b88f7ebb50 100644 --- a/VocBase/simple-collection.c +++ b/VocBase/simple-collection.c @@ -83,6 +83,7 @@ static TRI_index_t* CreateGeoIndexSimCollection (TRI_sim_collection_t* collectio char const* latitude, char const* longitude, bool geoJson, + bool constraint, TRI_idx_iid_t iid, bool* created); @@ -384,8 +385,9 @@ static TRI_doc_mptr_t CreateDocument (TRI_sim_collection_t* sim, if (resRollback != TRI_ERROR_NO_ERROR) { LOG_ERROR("encountered error '%s' during rollback of create", TRI_last_error()); - TRI_set_errno(res); } + + TRI_set_errno(res); } // ............................................................................. @@ -639,8 +641,9 @@ static TRI_doc_mptr_t UpdateDocument (TRI_sim_collection_t* collection, if (resUpd._did == 0) { LOG_ERROR("encountered error '%s' during rollback of update", TRI_last_error()); - TRI_set_errno(res); } + + TRI_set_errno(res); } // ............................................................................. @@ -1414,7 +1417,7 @@ static bool OpenIndexIterator (char const* filename, void* data) { TRI_index_t* idx; TRI_json_t* fieldStr; TRI_json_t* fld; - TRI_json_t* gjs; + TRI_json_t* bv; TRI_json_t* iis; TRI_json_t* json; TRI_json_t* type; @@ -1494,47 +1497,72 @@ static bool OpenIndexIterator (char const* filename, void* data) { } // ........................................................................... - // GEO INDEX + // GEO INDEX (list or attribute) // ........................................................................... - if (TRI_EqualString(typeStr, "geo")) { - bool geoJson; + if (TRI_EqualString(typeStr, "geo1") || TRI_EqualString(typeStr, "geo2")) { + bool constraint; - gjs = TRI_LookupArrayJson(json, "geoJson"); - geoJson = false; + bv = TRI_LookupArrayJson(json, "contraint"); + constraint = false; - if (gjs != NULL && gjs->_type == TRI_JSON_BOOLEAN) { - geoJson = gjs->_value._boolean; + if (bv != NULL && bv->_type == TRI_JSON_BOOLEAN) { + constraint = bv->_value._boolean; } - if (fieldCount == 1) { - TRI_json_t* loc; + if (TRI_EqualString(typeStr, "geo1")) { + bool geoJson; - loc = TRI_AtVector(&fld->_value._objects, 0); + bv = TRI_LookupArrayJson(json, "geoJson"); + geoJson = false; + + if (bv != NULL && bv->_type == TRI_JSON_BOOLEAN) { + geoJson = bv->_value._boolean; + } - CreateGeoIndexSimCollection(doc, loc->_value._string.data, NULL, NULL, geoJson, iid, NULL); + if (fieldCount == 1) { + TRI_json_t* loc; - TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json); - return true; + loc = TRI_AtVector(&fld->_value._objects, 0); + + CreateGeoIndexSimCollection(doc, loc->_value._string.data, NULL, NULL, geoJson, constraint, iid, NULL); + + TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json); + return true; + } + else { + LOG_ERROR("ignoring %s-index %lu, 'fields' must be a list with 1 entries", + typeStr, (unsigned long) iid); + + TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json); + return false; + } } - else if (fieldCount == 2) { - TRI_json_t* lat; - TRI_json_t* lon; - lat = TRI_AtVector(&fld->_value._objects, 0); - lon = TRI_AtVector(&fld->_value._objects, 1); + else if (TRI_EqualString(typeStr, "geo2")) { + if (fieldCount == 2) { + TRI_json_t* lat; + TRI_json_t* lon; - CreateGeoIndexSimCollection(doc, NULL, lat->_value._string.data, lon->_value._string.data, false, iid, NULL); + lat = TRI_AtVector(&fld->_value._objects, 0); + lon = TRI_AtVector(&fld->_value._objects, 1); - TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json); - return true; + CreateGeoIndexSimCollection(doc, NULL, lat->_value._string.data, lon->_value._string.data, false, constraint, iid, NULL); + + TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json); + return true; + } + else { + LOG_ERROR("ignoring %s-index %lu, 'fields' must be a list with 2 entries", + typeStr, (unsigned long) iid); + + TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json); + return false; + } } + else { - LOG_ERROR("ignoring %s-index %lu, 'fields' must be a list with 1 or 2 entries", - typeStr, (unsigned long) iid); - - TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json); - return false; + assert(false); } } @@ -1542,16 +1570,16 @@ static bool OpenIndexIterator (char const* filename, void* data) { // HASH INDEX OR SKIPLIST INDEX // ........................................................................... - else if (TRI_EqualString(typeStr, "hash") || TRI_EqualString(typeStr, "skiplist") || - TRI_EqualString(typeStr, "priorityqueue") - ) { + else if ( TRI_EqualString(typeStr, "hash") + || TRI_EqualString(typeStr, "skiplist") + || TRI_EqualString(typeStr, "priorityqueue")) { // Determine if the hash index is unique or non-unique - gjs = TRI_LookupArrayJson(json, "unique"); + bv = TRI_LookupArrayJson(json, "unique"); uniqueIndex = false; - if (gjs != NULL && gjs->_type == TRI_JSON_BOOLEAN) { - uniqueIndex = gjs->_value._boolean; + if (bv != NULL && bv->_type == TRI_JSON_BOOLEAN) { + uniqueIndex = bv->_value._boolean; } else { LOG_ERROR("ignoring %s-index %lu, could not determine if unique or non-unique", @@ -2130,7 +2158,11 @@ static int CreateImmediateIndexes (TRI_sim_collection_t* sim, return TRI_set_errno(TRI_ERROR_AVOCADO_UNIQUE_CONSTRAINT_VIOLATED); } - return result; + if (result != TRI_ERROR_NO_ERROR) { + return TRI_set_errno(result); + } + + return TRI_ERROR_NO_ERROR; } //////////////////////////////////////////////////////////////////////////////// @@ -2672,6 +2704,7 @@ static TRI_index_t* CreateGeoIndexSimCollection (TRI_sim_collection_t* sim, char const* latitude, char const* longitude, bool geoJson, + bool constraint, TRI_idx_iid_t iid, bool* created) { TRI_index_t* idx; @@ -2717,10 +2750,10 @@ static TRI_index_t* CreateGeoIndexSimCollection (TRI_sim_collection_t* sim, // check, if we know the index if (location != NULL) { - idx = TRI_LookupGeoIndexSimCollection(sim, loc, geoJson); + idx = TRI_LookupGeoIndex1SimCollection(sim, loc, geoJson, constraint); } else if (longitude != NULL && latitude != NULL) { - idx = TRI_LookupGeoIndex2SimCollection(sim, lat, lon); + idx = TRI_LookupGeoIndex2SimCollection(sim, lat, lon, constraint); } else { TRI_set_errno(TRI_ERROR_INTERNAL); @@ -2740,14 +2773,14 @@ static TRI_index_t* CreateGeoIndexSimCollection (TRI_sim_collection_t* sim, // create a new index if (location != NULL) { - idx = TRI_CreateGeoIndex(&sim->base, location, loc, geoJson); + idx = TRI_CreateGeoIndex1(&sim->base, location, loc, geoJson, constraint); LOG_TRACE("created geo-index for location '%s': %d", location, (unsigned long) loc); } else if (longitude != NULL && latitude != NULL) { - idx = TRI_CreateGeoIndex2(&sim->base, latitude, lat, longitude, lon); + idx = TRI_CreateGeoIndex2(&sim->base, latitude, lat, longitude, lon, constraint); LOG_TRACE("created geo-index for location '%s': %d, %d", location, @@ -3255,9 +3288,10 @@ TRI_vector_t TRI_SelectByExample (TRI_sim_collection_t* sim, /// @brief finds a geo index //////////////////////////////////////////////////////////////////////////////// -TRI_index_t* TRI_LookupGeoIndexSimCollection (TRI_sim_collection_t* collection, +TRI_index_t* TRI_LookupGeoIndex1SimCollection (TRI_sim_collection_t* collection, TRI_shape_pid_t location, - bool geoJson) { + bool geoJson, + bool constraint) { size_t n; size_t i; @@ -3268,10 +3302,10 @@ TRI_index_t* TRI_LookupGeoIndexSimCollection (TRI_sim_collection_t* collection, idx = collection->_indexes._buffer[i]; - if (idx->_type == TRI_IDX_TYPE_GEO_INDEX) { + if (idx->_type == TRI_IDX_TYPE_GEO_INDEX1) { TRI_geo_index_t* geo = (TRI_geo_index_t*) idx; - if (geo->_location != 0 && geo->_location == location && geo->_geoJson == geoJson) { + if (geo->_location != 0 && geo->_location == location && geo->_geoJson == geoJson && geo->_constraint == constraint) { return idx; } } @@ -3286,7 +3320,8 @@ TRI_index_t* TRI_LookupGeoIndexSimCollection (TRI_sim_collection_t* collection, TRI_index_t* TRI_LookupGeoIndex2SimCollection (TRI_sim_collection_t* collection, TRI_shape_pid_t latitude, - TRI_shape_pid_t longitude) { + TRI_shape_pid_t longitude, + bool constraint) { size_t n; size_t i; @@ -3297,10 +3332,10 @@ TRI_index_t* TRI_LookupGeoIndex2SimCollection (TRI_sim_collection_t* collection, idx = collection->_indexes._buffer[i]; - if (idx->_type == TRI_IDX_TYPE_GEO_INDEX) { + if (idx->_type == TRI_IDX_TYPE_GEO_INDEX2) { TRI_geo_index_t* geo = (TRI_geo_index_t*) idx; - if (geo->_latitude != 0 && geo->_longitude != 0 && geo->_latitude == latitude && geo->_longitude == longitude) { + if (geo->_latitude != 0 && geo->_longitude != 0 && geo->_latitude == latitude && geo->_longitude == longitude && geo->_constraint == constraint) { return idx; } } @@ -3515,10 +3550,11 @@ TRI_index_t* TRI_LookupSkiplistIndexSimCollection (TRI_sim_collection_t* collect /// @brief ensures that a geo index exists //////////////////////////////////////////////////////////////////////////////// -TRI_index_t* TRI_EnsureGeoIndexSimCollection (TRI_sim_collection_t* sim, - char const* location, - bool geoJson, - bool* created) { +TRI_index_t* TRI_EnsureGeoIndex1SimCollection (TRI_sim_collection_t* sim, + char const* location, + bool geoJson, + bool constraint, + bool* created) { TRI_index_t* idx; int res; @@ -3528,7 +3564,7 @@ TRI_index_t* TRI_EnsureGeoIndexSimCollection (TRI_sim_collection_t* sim, TRI_WRITE_LOCK_DOCUMENTS_INDEXES_SIM_COLLECTION(sim); - idx = CreateGeoIndexSimCollection(sim, location, NULL, NULL, geoJson, 0, created); + idx = CreateGeoIndexSimCollection(sim, location, NULL, NULL, geoJson, constraint, 0, created); if (idx == NULL) { TRI_WRITE_UNLOCK_DOCUMENTS_INDEXES_SIM_COLLECTION(sim); @@ -3553,6 +3589,7 @@ TRI_index_t* TRI_EnsureGeoIndexSimCollection (TRI_sim_collection_t* sim, TRI_index_t* TRI_EnsureGeoIndex2SimCollection (TRI_sim_collection_t* sim, char const* latitude, char const* longitude, + bool constraint, bool* created) { TRI_index_t* idx; int res; @@ -3563,7 +3600,7 @@ TRI_index_t* TRI_EnsureGeoIndex2SimCollection (TRI_sim_collection_t* sim, TRI_WRITE_LOCK_DOCUMENTS_INDEXES_SIM_COLLECTION(sim); - idx = CreateGeoIndexSimCollection(sim, NULL, latitude, longitude, false, 0, created); + idx = CreateGeoIndexSimCollection(sim, NULL, latitude, longitude, false, constraint, 0, created); if (idx == NULL) { TRI_WRITE_UNLOCK_DOCUMENTS_INDEXES_SIM_COLLECTION(sim); diff --git a/VocBase/simple-collection.h b/VocBase/simple-collection.h index 282df64171..2711a18d09 100644 --- a/VocBase/simple-collection.h +++ b/VocBase/simple-collection.h @@ -408,9 +408,10 @@ TRI_vector_pointer_t TRI_LookupEdgesSimCollection (TRI_sim_collection_t* edges, /// Note that the caller must hold at least a read-lock. //////////////////////////////////////////////////////////////////////////////// -struct TRI_index_s* TRI_LookupGeoIndexSimCollection (TRI_sim_collection_t* collection, - TRI_shape_pid_t location, - bool geoJson); +struct TRI_index_s* TRI_LookupGeoIndex1SimCollection (TRI_sim_collection_t* collection, + TRI_shape_pid_t location, + bool geoJson, + bool constraint); //////////////////////////////////////////////////////////////////////////////// /// @brief finds a geo index @@ -420,7 +421,8 @@ struct TRI_index_s* TRI_LookupGeoIndexSimCollection (TRI_sim_collection_t* colle struct TRI_index_s* TRI_LookupGeoIndex2SimCollection (TRI_sim_collection_t* collection, TRI_shape_pid_t latitude, - TRI_shape_pid_t longitude); + TRI_shape_pid_t longitude, + bool constraint); //////////////////////////////////////////////////////////////////////////////// /// @brief finds a hash index @@ -455,19 +457,21 @@ struct TRI_index_s* TRI_LookupSkiplistIndexSimCollection (TRI_sim_collection_t*, /// @brief ensures that a geo index exists //////////////////////////////////////////////////////////////////////////////// -struct TRI_index_s* TRI_EnsureGeoIndexSimCollection (TRI_sim_collection_t* collection, - char const* location, - bool geoJson, - bool* created); +struct TRI_index_s* TRI_EnsureGeoIndex1SimCollection (TRI_sim_collection_t* collection, + char const* location, + bool geoJson, + bool constraint, + bool* created); //////////////////////////////////////////////////////////////////////////////// /// @brief adds a geo index to a collection //////////////////////////////////////////////////////////////////////////////// struct TRI_index_s* TRI_EnsureGeoIndex2SimCollection (TRI_sim_collection_t* collection, - char const* latitude, - char const* longitude, - bool* created); + char const* latitude, + char const* longitude, + bool constraint, + bool* created); //////////////////////////////////////////////////////////////////////////////// /// @brief adds or returns an existing hash index to a collection diff --git a/js/common/tests/shell-index-geo.js b/js/common/tests/shell-index-geo.js index dc2a1fd35e..fb83b33d18 100644 --- a/js/common/tests/shell-index-geo.js +++ b/js/common/tests/shell-index-geo.js @@ -78,7 +78,7 @@ function geoIndexCreationSuite() { var id = idx.id; assertNotEqual(0, id); - assertEqual("geo", idx.type); + assertEqual("geo1", idx.type); assertEqual(false, idx.geoJson); assertEqual(["loc"], idx.fields); assertEqual(true, idx.isNewlyCreated); @@ -86,7 +86,7 @@ function geoIndexCreationSuite() { idx = collection.ensureGeoIndex("loc"); assertEqual(id, idx.id); - assertEqual("geo", idx.type); + assertEqual("geo1", idx.type); assertEqual(false, idx.geoJson); assertEqual(["loc"], idx.fields); assertEqual(false, idx.isNewlyCreated); @@ -94,10 +94,20 @@ function geoIndexCreationSuite() { idx = collection.ensureGeoIndex("loc", true); assertNotEqual(id, idx.id); - assertEqual("geo", idx.type); + assertEqual("geo1", idx.type); assertEqual(true, idx.geoJson); assertEqual(["loc"], idx.fields); assertEqual(true, idx.isNewlyCreated); + + collection.unload(); + + idx = collection.ensureGeoIndex("loc", true); + + assertNotEqual(id, idx.id); + assertEqual("geo1", idx.type); + assertEqual(true, idx.geoJson); + assertEqual(["loc"], idx.fields); + assertEqual(false, idx.isNewlyCreated); }, //////////////////////////////////////////////////////////////////////////////// @@ -109,7 +119,7 @@ function geoIndexCreationSuite() { var id = idx.id; assertNotEqual(0, id); - assertEqual("geo", idx.type); + assertEqual("geo1", idx.type); assertEqual(true, idx.geoJson); assertEqual(["loc"], idx.fields); assertEqual(true, idx.isNewlyCreated); @@ -117,7 +127,7 @@ function geoIndexCreationSuite() { idx = collection.ensureGeoIndex("loc", true); assertEqual(id, idx.id); - assertEqual("geo", idx.type); + assertEqual("geo1", idx.type); assertEqual(true, idx.geoJson); assertEqual(["loc"], idx.fields); assertEqual(false, idx.isNewlyCreated); @@ -125,10 +135,20 @@ function geoIndexCreationSuite() { idx = collection.ensureGeoIndex("loc", false); assertNotEqual(id, idx.id); - assertEqual("geo", idx.type); + assertEqual("geo1", idx.type); assertEqual(false, idx.geoJson); assertEqual(["loc"], idx.fields); assertEqual(true, idx.isNewlyCreated); + + collection.unload(); + + idx = collection.ensureGeoIndex("loc", false); + + assertNotEqual(id, idx.id); + assertEqual("geo1", idx.type); + assertEqual(false, idx.geoJson); + assertEqual(["loc"], idx.fields); + assertEqual(false, idx.isNewlyCreated); }, //////////////////////////////////////////////////////////////////////////////// @@ -140,31 +160,88 @@ function geoIndexCreationSuite() { var id = idx.id; assertNotEqual(0, id); - assertEqual("geo", idx.type); + assertEqual("geo2", idx.type); assertEqual(["lat", "lon"], idx.fields); assertEqual(true, idx.isNewlyCreated); idx = collection.ensureGeoIndex("lat", "lon"); assertEqual(id, idx.id); - assertEqual("geo", idx.type); + assertEqual("geo2", idx.type); assertEqual(["lat", "lon"], idx.fields); assertEqual(false, idx.isNewlyCreated); - }, + + collection.unload(); + + idx = collection.ensureGeoIndex("lat", "lon"); + + assertEqual(id, idx.id); + assertEqual("geo2", idx.type); + assertEqual(["lat", "lon"], idx.fields); + assertEqual(false, idx.isNewlyCreated); + } + }; +} + +// ----------------------------------------------------------------------------- +// --SECTION-- basic methods +// ----------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -/// @brief test: error handling +/// @brief test suite: Simple Queries //////////////////////////////////////////////////////////////////////////////// - testCreationLocationError : function () { - collection.save({ loc : [ -100, 0 ] }); +function geoIndexErrorHandlingSuite() { + var cn = "UnitTestsCollectionGeo"; + var collection = null; - try { - collection.ensureGeoIndex("loc"); - fail(); - } - catch (err) { - } + return { + +//////////////////////////////////////////////////////////////////////////////// +/// @brief set up +//////////////////////////////////////////////////////////////////////////////// + + setUp : function () { + db._drop(cn); + collection = db._create(cn, { waitForSync : false }); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief tear down +//////////////////////////////////////////////////////////////////////////////// + + tearDown : function () { + collection.drop(); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test: error handling index +//////////////////////////////////////////////////////////////////////////////// + + testErrorHandlerIndexList : function () { + collection.ensureGeoIndex("loc"); + + var d1 = collection.save({ a : 1 }); + var d2 = collection.save({ loc : null }); + var d3 = collection.save({ loc : [0] }); + var d4 = collection.save({ loc : [ -100, -200 ] }); + var d5 = collection.save({ loc : [ -10, -20 ]}); + + assertEqual(1, collection.near(0,0).toArray().length); + + d1 = collection.replace(d1, { loc : [ 0, 0 ] }); + d2 = collection.replace(d2, { loc : [ 0, 0 ] }); + d3 = collection.replace(d3, { loc : [ 0, 0 ] }); + d4 = collection.replace(d4, { loc : [ 0, 0 ] }); + + assertEqual(5, collection.near(0,0).toArray().length); + + collection.replace(d1, { a : 2 }); + collection.replace(d2, { loc : null }); + collection.replace(d3, { loc : [ 0 ] }); + collection.replace(d4, { loc : [ -100, -200 ] }); + + assertEqual(1, collection.near(0,0).toArray().length); } }; } @@ -458,6 +535,7 @@ function geoIndexSimpleQueriesSuite() { //////////////////////////////////////////////////////////////////////////////// jsunity.run(geoIndexCreationSuite); +jsunity.run(geoIndexErrorHandlingSuite); jsunity.run(geoIndexSimpleQueriesSuite); return jsunity.done(); diff --git a/js/server/modules/simple-query.js b/js/server/modules/simple-query.js index 4f6a60787b..a90c0a303a 100644 --- a/js/server/modules/simple-query.js +++ b/js/server/modules/simple-query.js @@ -189,7 +189,7 @@ AvocadoCollection.prototype.geo = function(loc, order) { for (var i = 0; i < inds.length; ++i) { var index = inds[i]; - if (index.type == "geo") { + if (index.type == "geo1") { if (index.fields[0] == loc && index.geoJson == order) { return index; } @@ -205,7 +205,7 @@ AvocadoCollection.prototype.geo = function(loc, order) { for (var i = 0; i < inds.length; ++i) { var index = inds[i]; - if (index.type == "geo" && 2 <= index.fields.length) { + if (index.type == "geo2") { if (index.fields[0] == lat && index.fields[1] == lon) { return index; } @@ -1144,7 +1144,7 @@ function SimpleQueryNear (collection, latitude, longitude, iid) { for (var i = 0; i < idx.length; ++i) { var index = idx[i]; - if (index.type == "geo") { + if (index.type == "geo1" || index.type == "geo2") { if (this._index == null) { this._index = index.id; } @@ -1327,7 +1327,7 @@ function SimpleQueryWithin (collection, latitude, longitude, radius, iid) { for (var i = 0; i < idx.length; ++i) { var index = idx[i]; - if (index.type == "geo") { + if (index.type == "geo1" || index.type == "geo2") { if (this._index == null) { this._index = index.id; }