Permalink
Browse files

NCBC-47: Add support for spatial view queries

Change-Id: I339bc3ea0c4a1ff4bf7c782db729a2009a5ca61f
Reviewed-on: http://review.couchbase.org/22420
Reviewed-by: Matt Ingenthron <matt@couchbase.com>
Reviewed-by: Volker Mische <volker.mische@gmail.com>
Tested-by: John C. Zablocki <john@couchbase.com>
  • Loading branch information...
johnzablocki authored and John C. Zablocki committed Nov 8, 2012
1 parent ffaba6e commit 48cc56fb05dd50d01134da057091710ff02f3410
@@ -51,6 +51,8 @@
</ItemGroup>
<ItemGroup>
<Compile Include="ConfigHelperTests.cs" />
+ <Compile Include="CouchbaseClientSpatialViewTests.cs" />
+ <Compile Include="HelperTests\DocHelperTests.cs" />
<Compile Include="HttpClientConfigTests.cs" />
<Compile Include="CouchbaseAuthenticatedViewTests.cs" />
<Compile Include="CouchbaseClientGenericViewTests.cs" />
@@ -0,0 +1,99 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using NUnit.Framework;
+using Couchbase.Extensions;
+
+namespace Couchbase.Tests
+{
+ [TestFixture]
+ public class CouchbaseClientSpatialViewTests : CouchbaseClientViewTestsBase
+ {
+ [Test]
+ public void When_Querying_Spatial_View_Results_Are_Returned()
+ {
+ var view = _Client.GetSpatialView("cities", "by_location");
+ foreach (var item in view)
+ {
+ Assert.That(item.Id, Is.Not.Null, "Item Id was null");
+ Assert.That(item.BoundingBox, Is.Not.Null, "Bounding box was null");
+ Assert.That(item.BoundingBox.Length, Is.GreaterThan(0), "Bounding length box was empty");
+ Assert.That(item.Geometry.Type, Is.StringMatching("Point"), "Type was not place");
+ Assert.That(item.Geometry.Coordinates, Is.InstanceOf<float[]>(), "Coordinates were missing");
+ }
+
+ Assert.That(view.Count(), Is.GreaterThan(0), "View count was 0");
+ }
+
+ [Test]
+ public void When_Querying_Spatial_View_With_Generics_And_Should_Lookup_Doc_By_Id_Is_True_Results_Are_Returned()
+ {
+ var view = _Client.GetSpatialView<City>("cities", "by_location", true);
+ foreach (var item in view)
+ {
+ Assert.That(item.Id, Is.Not.Null, "Id was null");
+ Assert.That(item.Name, Is.Not.Null, "Name was null");
+ Assert.That(item.State, Is.Not.Null, "State was null");
+ Assert.That(item.Type, Is.StringMatching("city"), "Type was not city");
+ }
+
+ Assert.That(view.Count(), Is.GreaterThan(0), "View count was 0");
+ }
+
+ [Test]
+ public void When_Querying_Spatial_View_With_Generics_And_Should_Lookup_Doc_By_Id_Is_False_Results_Are_Returned()
+ {
+ var view = _Client.GetSpatialView<CityProjection>("cities", "by_location_with_city_name", false);
+ foreach (var item in view)
+ {
+ Assert.That(item.CityState, Is.Not.Null);
+ }
+
+ Assert.That(view.Count(), Is.GreaterThan(0), "View count was 0");
+ }
+
+ [Test]
+ public void When_Querying_Spatial_View_With_Limit_Rows_Are_Limited()
+ {
+ var view = _Client.GetSpatialView("cities", "by_location").Limit(2);
+ Assert.That(view.Count(), Is.EqualTo(2), "View count was not 2");
+ }
+
+ [Test]
+ public void When_Querying_Spatial_View_With_Bounding_Box_Rows_Are_Limited()
+ {
+ var hasAtLeastOneRecord = false;
+ var view = _Client.GetSpatialView("cities", "by_location").BoundingBox(-73.789673f, 41.093704f, -71.592407f, 42.079742f); //bbox around Connecticut
+ foreach (var item in view)
+ {
+ hasAtLeastOneRecord = true;
+ var doc = _Client.GetJson<City>(item.Id);
+ Assert.That(doc.State, Is.StringMatching("CT"), "State was " + doc.State + " not CT");
+ }
+
+ Assert.That(hasAtLeastOneRecord, Is.True, "No records found");
+ }
+ }
+}
+
+#region [ License information ]
+/* ************************************************************
+ *
+ * @author Couchbase <info@couchbase.com>
+ * @copyright 2012 Couchbase, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * ************************************************************/
+#endregion
@@ -1,22 +1,22 @@
-{ "name" : "Hartford", "state" : "CT", "type" : "city" }
-{ "name" : "Bridgeport", "state" : "CT", "type" : "city" }
-{ "name" : "Stamford", "state" : "CT", "type" : "city" }
-{ "name" : "New Haven", "state" : "CT", "type" : "city" }
-{ "name" : "New London", "state" : "CT", "type" : "city" }
-{ "name" : "Norwalk", "state" : "CT", "type" : "city" }
-{ "name" : "Boston", "state" : "MA", "type" : "city" }
-{ "name" : "Cambridge", "state" : "MA", "type" : "city" }
-{ "name" : "Somerville", "state" : "MA", "type" : "city" }
-{ "name" : "Springfield", "state" : "MA", "type" : "city" }
-{ "name" : "Worcester", "state" : "MA", "type" : "city" }
-{ "name" : "Portsmouth", "state" : "NH", "type" : "city" }
-{ "name" : "Concord", "state" : "NH", "type" : "city" }
-{ "name" : "Manchester", "state" : "NH", "type" : "city" }
-{ "name" : "Burlington", "state" : "VT", "type" : "city" }
-{ "name" : "Montpelier", "state" : "VT", "type" : "city" }
-{ "name" : "Newport", "state" : "VT", "type" : "city" }
-{ "name" : "Providence", "state" : "RI", "type" : "city" }
-{ "name" : "Warwick", "state" : "RI", "type" : "city" }
-{ "name" : "Newport", "state" : "RI", "type" : "city" }
-{ "name" : "Bangor", "state" : "ME", "type" : "city" }
-{ "name" : "Portland", "state" : "ME", "type" : "city" }
+{ "name" : "Hartford", "state" : "CT", "type" : "city", "loc" : [-72.67408, 41.763309] }
+{ "name" : "Bridgeport", "state" : "CT", "type" : "city", "loc" : [-73.191269, 41.181881] }
+{ "name" : "Stamford", "state" : "CT", "type" : "city", "loc" : [-73.542229, 41.051819] }
+{ "name" : "New Haven", "state" : "CT", "type" : "city", "loc" : [-72.92498, 41.307129] }
+{ "name" : "New London", "state" : "CT", "type" : "city", "loc" : [-72.096474, 41.356441] }
+{ "name" : "Norwalk", "state" : "CT", "type" : "city", "loc" : [-73.407654, 41.113659] }
+{ "name" : "Boston", "state" : "MA", "type" : "city", "loc" : [-71.056702, 42.358631] }
+{ "name" : "Cambridge", "state" : "MA", "type" : "city", "loc" : [-71.10601, 42.366791] }
+{ "name" : "Somerville", "state" : "MA", "type" : "city", "loc" : [-71.098259, 42.386681] }
+{ "name" : "Springfield", "state" : "MA", "type" : "city", "loc" : [-72.589287, 42.10125] }
+{ "name" : "Worcester", "state" : "MA", "type" : "city", "loc" : [-71.802193, 42.263409] }
+{ "name" : "Portsmouth", "state" : "NH", "type" : "city", "loc" : [-70.772118, 43.070621] }
+{ "name" : "Concord", "state" : "NH", "type" : "city", "loc" : [-71.536598, 43.207249] }
+{ "name" : "Manchester", "state" : "NH", "type" : "city", "loc" : [-71.463089, 42.991169] }
+{ "name" : "Burlington", "state" : "VT", "type" : "city", "loc" : [-73.213226, 44.475922] }
+{ "name" : "Montpelier", "state" : "VT", "type" : "city", "loc" : [-72.576263, 44.260288] }
+{ "name" : "Newport", "state" : "VT", "type" : "city", "loc" : [-72.210617, 44.935341] }
+{ "name" : "Providence", "state" : "RI", "type" : "city", "loc" : [-71.411987, 41.823872] }
+{ "name" : "Warwick", "state" : "RI", "type" : "city", "loc" : [-71.461678, 41.698589] }
+{ "name" : "Newport", "state" : "RI", "type" : "city", "loc" : [-71.311333, 41.492161] }
+{ "name" : "Bangor", "state" : "ME", "type" : "city", "loc" : [-68.770767, 44.801708] }
+{ "name" : "Portland", "state" : "ME", "type" : "city", "loc" : [-70.256653, 43.659142] }
@@ -13,5 +13,9 @@
"map": "function (doc) { if (doc.type == \"city\") { emit(doc.state, doc.name); } }",
"reduce": "_count"
}
- }
+ },
+ "spatial" : {
+ "by_location" : "function (doc, meta) { if (doc.type == \"city\") { emit({ \"type\": \"Point\", \"coordinates\": doc.loc}, null); } }",
+ "by_location_with_city_name" : "function (doc, meta) { if (doc.type == \"city\") { emit({ \"type\": \"Point\", \"coordinates\": doc.loc}, { \"cityState\" : doc.name + \",\" + doc.state }); } }"
+ }
}
@@ -0,0 +1,45 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using NUnit.Framework;
+using Couchbase.Helpers;
+using Newtonsoft.Json;
+
+namespace Couchbase.Tests.HelperTests
+{
+ [TestFixture]
+ public class DocHelperTests
+ {
+ [Test]
+ public void When_Inserting_Id_Into_Doc_Json_String_Is_Valid_And_Contains_Id()
+ {
+ var json = "{ \"message\" : \"Test\" }";
+ var jsonWithId = DocHelper.InsertId(json, "8675309");
+
+ Assert.That(jsonWithId, Is.StringContaining("\"_id\":\"8675309\""));
+ Assert.That(JsonConvert.DeserializeObject(jsonWithId), Is.Not.Null);
+ }
+ }
+}
+
+#region [ License information ]
+/* ************************************************************
+ *
+ * @author Couchbase <info@couchbase.com>
+ * @copyright 2012 Couchbase, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * ************************************************************/
+#endregion
@@ -51,6 +51,7 @@
<HintPath>..\packages\Newtonsoft.Json.4.5.1\lib\net40\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
+ <Reference Include="System.Configuration" />
<Reference Include="System.configuration" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
@@ -71,8 +72,15 @@
<ItemGroup>
<Compile Include="Configuration\HttpClientElement.cs" />
<Compile Include="Configuration\IHttpClientConfiguration.cs" />
+ <Compile Include="CouchbaseSpatialView`1.cs" />
+ <Compile Include="CouchbaseSpatialView.cs" />
+ <Compile Include="CouchbaseSpatialViewBase.cs" />
+ <Compile Include="CouchbaseViewHandler.cs" />
<Compile Include="Extensions\CouchbaseClientExtensions.cs" />
+ <Compile Include="Helpers\DocHelper.cs" />
<Compile Include="Helpers\JsonHelper.cs" />
+ <Compile Include="ISpatialView`1.cs" />
+ <Compile Include="ISpatialViewRow.cs" />
<Compile Include="Management\Bucket.cs" />
<Compile Include="BucketConfigListener.cs" />
<Compile Include="BucketConfigSettings.cs" />
@@ -150,7 +158,10 @@
<Compile Include="Results\IObserveOperationResult.cs" />
<Compile Include="Results\ObserveOperationResult.cs" />
<Compile Include="Settings\ObserveSettings.cs" />
+ <Compile Include="SpatialViewGeometry.cs" />
+ <Compile Include="SpatialViewRow.cs" />
<Compile Include="VBucketAwareOperationFactory.cs" />
+ <Compile Include="ViewParamsBuilder.cs" />
<Compile Include="WebClientWithTimeout.cs">
<SubType>Component</SubType>
</Compile>
@@ -168,6 +179,9 @@
<Name>Enyim.Caching</Name>
</ProjectReference>
</ItemGroup>
+ <ItemGroup>
+ <Folder Include="Geo\" />
+ </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<GitTagMatch>mb*</GitTagMatch>
@@ -715,6 +715,18 @@ public IView<T> GetView<T>(string designName, string viewName, bool shouldLookup
return new CouchbaseView<T>(this, this, designName, viewName, shouldLookupDocById);
}
+ public ISpatialView<ISpatialViewRow> GetSpatialView(string designName, string viewName)
+ {
+ getViewSetup(ref designName, ref viewName);
+ return new CouchbaseSpatialView(this, this, designName, viewName);
+ }
+
+ public ISpatialView<T> GetSpatialView<T>(string designName, string viewName, bool shouldLookupDocById = false)
+ {
+ getViewSetup(ref designName, ref viewName);
+ return new CouchbaseSpatialView<T>(this, this, designName, viewName, shouldLookupDocById);
+ }
+
public IDictionary<string, object> Get(IView view)
{
var keys = view.Select(row => row.ItemId);
@@ -0,0 +1,41 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Newtonsoft.Json;
+
+namespace Couchbase
+{
+ internal class CouchbaseSpatialView : CouchbaseSpatialViewBase<ISpatialViewRow>
+ {
+ internal CouchbaseSpatialView(ICouchbaseClient client, IHttpClientLocator clientLocator, string designDocument, string indexName)
+ :base(client, clientLocator, designDocument, indexName) {}
+
+ public override IEnumerator<ISpatialViewRow> GetEnumerator()
+ {
+ return ViewHandler.TransformResults<ISpatialViewRow>(
+ jr => JsonConvert.DeserializeObject<SpatialViewRow>(Json.ParseRaw(jr)), BuildParams());
+ }
+ }
+}
+
+#region [ License information ]
+/* ************************************************************
+ *
+ * @author Couchbase <info@couchbase.com>
+ * @copyright 2012 Couchbase, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * ************************************************************/
+#endregion
Oops, something went wrong.

0 comments on commit 48cc56f

Please sign in to comment.