From 0465e8079d6336aed10c7cb5bd0258dad7aff362 Mon Sep 17 00:00:00 2001 From: Max De Marzi Date: Sat, 25 Jan 2014 17:00:43 -0600 Subject: [PATCH] most of the way there, but cypher still failing :( --- lib/neography/rest.rb | 32 ++++++ lib/neography/rest/spatial.rb | 89 ++++++++++++++++- spec/integration/rest_spatial_spec.rb | 135 ++++++++++++++++++++++++++ 3 files changed, 255 insertions(+), 1 deletion(-) diff --git a/lib/neography/rest.rb b/lib/neography/rest.rb index 57fa869..7f64e87 100644 --- a/lib/neography/rest.rb +++ b/lib/neography/rest.rb @@ -465,6 +465,38 @@ def add_point_layer(layer, lat = nil, lon = nil) @spatial.add_point_layer(layer, lat, lon) end + def add_editable_layer(layer, format, node_property_name) + @spatial.add_editable_layer(layer, format, node_property_name) + end + + def get_layer(layer) + @spatial.get_layer(layer) + end + + def add_geometry_to_layer(layer, geometry) + @spatial.add_geometry_to_layer(layer, geometry) + end + + def edit_geometry_from_layer(layer, geometry, node) + @spatial.edit_geometry_from_layer(layer, geometry, node) + end + + def add_node_to_layer(layer, node) + @spatial.add_node_to_layer(layer, node) + end + + def find_geometries_in_bbox(layer, minx, maxx, miny, maxy) + @spatial.find_geometries_in_bbox(layer, minx, maxx, miny, maxy) + end + + def find_geometries_within_distance(layer, pointx, pointy, distance) + @spatial.find_geometries_within_distance(layer, pointx, pointy, distance) + end + + def create_spatial_index(name, type = nil, lat = nil, lon = nil) + @spatial.create_spatial_index(name, type, lat, lon) + end + # clean database # For testing (use a separate neo4j instance) diff --git a/lib/neography/rest/spatial.rb b/lib/neography/rest/spatial.rb index a746e7b..9790da5 100644 --- a/lib/neography/rest/spatial.rb +++ b/lib/neography/rest/spatial.rb @@ -13,6 +13,7 @@ class Spatial add_path :add_node_to_layer, "/ext/SpatialPlugin/graphdb/addNodeToLayer" add_path :find_geometries_in_bbox, "/ext/SpatialPlugin/graphdb/findGeometriesInBBox" add_path :find_geometries_within_distance,"/ext/SpatialPlugin/graphdb/findGeometriesWithinDistance" + add_path :create_index, "/index/node" def initialize(connection) @connection = connection @@ -38,7 +39,7 @@ def add_point_layer(layer, lat, lon) def add_editable_layer(layer, format = "WKT", node_property_name = "wkt") options = { :body => { - :layer => name, + :layer => layer, :format => format, :nodePropertyName => node_property_name }.to_json, @@ -48,6 +49,92 @@ def add_editable_layer(layer, format = "WKT", node_property_name = "wkt") @connection.post(add_editable_layer_path, options) end + def get_layer(layer) + options = { + :body => { + :layer => layer + }.to_json, + :headers => json_content_type.merge({'Accept' => 'application/json;charset=UTF-8'}) + } + @connection.post(get_layer_path, options) + end + + def add_geometry_to_layer(layer, geometry) + options = { + :body => { + :layer => layer, + :geometry => geometry + }.to_json, + :headers => json_content_type.merge({'Accept' => 'application/json;charset=UTF-8'}) + } + @connection.post(add_geometry_to_layer_path, options) + end + + def edit_geometry_from_layer(layer, geometry, node) + options = { + :body => { + :layer => layer, + :geometry => geometry, + :geometryNodeId => get_id(node) + }.to_json, + :headers => json_content_type.merge({'Accept' => 'application/json;charset=UTF-8'}) + } + @connection.post(edit_geometry_from_layer_path, options) + end + + def add_node_to_layer(layer, node) + options = { + :body => { + :layer => layer, + :node => get_id(node) + }.to_json, + :headers => json_content_type.merge({'Accept' => 'application/json;charset=UTF-8'}) + } + @connection.post(add_node_to_layer_path, options) + end + + def find_geometries_in_bbox(layer, minx, maxx, miny, maxy) + options = { + :body => { + :layer => layer, + :minx => minx, + :maxx => maxx, + :miny => miny, + :maxy => maxy + }.to_json, + :headers => json_content_type.merge({'Accept' => 'application/json;charset=UTF-8'}) + } + @connection.post(find_geometries_in_bbox_path, options) + end + + def find_geometries_within_distance(layer, pointx, pointy, distance) + options = { + :body => { + :layer => layer, + :pointX => pointx, + :pointY => pointy, + :distanceInKm => distance + }.to_json, + :headers => json_content_type.merge({'Accept' => 'application/json;charset=UTF-8'}) + } + @connection.post(find_geometries_within_distance_path, options) + end + + def create_spatial_index(name, type, lat, lon) + options = { + :body => { + :name => name, + :config => { + :provider => "spatial", + :geometry_type => type || "point", + :lat => lat || "lat", + :lon => lon || "lon" + } + }.to_json, + :headers => json_content_type.merge({'Accept' => 'application/json;charset=UTF-8'}) + } + @connection.post(create_index_path, options) + end end end diff --git a/spec/integration/rest_spatial_spec.rb b/spec/integration/rest_spatial_spec.rb index e1d37af..a062f1d 100644 --- a/spec/integration/rest_spatial_spec.rb +++ b/spec/integration/rest_spatial_spec.rb @@ -27,7 +27,142 @@ pl.first["data"]["layer"].should == "coffee_shops" pl.first["data"]["geomencoder_config"].should == "longitude:latitude" end + end + + describe "add an editable layer" do + it "can add an editable layer" do + el = @neo.add_editable_layer("zipcodes", "WKT", "wkt") + el.should_not be_nil + el.first["data"]["layer"].should == "zipcodes" + el.first["data"]["geomencoder_config"].should == "wkt" + end + end + + describe "get a spatial layer" do + it "can get a layer" do + sl = @neo.get_layer("restaurants") + sl.should_not be_nil + sl.first["data"]["layer"].should == "restaurants" + end + end + + describe "create a spatial index" do + it "can create a spatial index" do + index = @neo.create_spatial_index("restaurants") + index["provider"].should == "spatial" + index["geometry_type"].should == "point" + index["lat"].should == "lat" + index["lon"].should == "lon" + end + end + + describe "add geometry to spatial layer" do + it "can add a geometry" do + geometry = "LINESTRING (15.2 60.1, 15.3 60.1)" + geo = @neo.add_geometry_to_layer("zipcodes", geometry) + geo.should_not be_nil + geo.first["data"]["wkt"].should == geometry + end + end + + describe "update geometry from spatial layer" do + it "can update a geometry" do + geometry = "LINESTRING (15.2 60.1, 15.3 60.1)" + geo = @neo.add_geometry_to_layer("zipcodes", geometry) + geo.should_not be_nil + geo.first["data"]["wkt"].should == geometry + geometry = "LINESTRING (14.7 60.1, 15.3 60.1)" + existing_geo = @neo.edit_geometry_from_layer("zipcodes", geometry, geo) + existing_geo.first["data"]["wkt"].should == geometry + existing_geo.first["self"].split('/').last.to_i.should == geo.first["self"].split('/').last.to_i + end + end + + describe "add a node to a layer" do + it "can add a node to a simple point layer" do + properties = {:name => "Max's Restaurant", :lat => 41.8819, :lon => 87.6278} + node = @neo.create_node(properties) + node.should_not be_nil + added = @neo.add_node_to_layer("restaurants", node) + added.first["data"]["lat"].should == properties[:lat] + added.first["data"]["lon"].should == properties[:lon] + + added = @neo.add_node_to_index("restaurants", "dummy", "dummy", node) + added["data"]["lat"].should == properties[:lat] + added["data"]["lon"].should == properties[:lon] + end + end + + describe "find geometries in a bounding box" do + it "can find a geometry in a bounding box" do + properties = {:name => "Max's Restaurant", :lat => 41.8819, :lon => 87.6278} + node = @neo.find_geometries_in_bbox("restaurants", 87.5, 87.7, 41.7, 41.9) + node.should_not be_empty + node.first["data"]["lat"].should == properties[:lat] + node.first["data"]["lon"].should == properties[:lon] + node.first["data"]["name"].should == "Max's Restaurant" + end + it "can find a geometry in a bounding box using cypher" do + node = @neo.execute_query("start n = node:restaurants({bbox}) return n", {:bbox => "bbox:[87.5,87.7,41.7,41.9]"}) + #node = @neo.execute_query("start n = node:restaurants({bbox}) return n", {:bbox => "bbox:[87.6278,41.8819,87.6278,41.8819]"}) + node.should_not be_empty + puts node.inspect + node.first["data"]["lat"].should == properties[:lat] + node.first["data"]["lon"].should == properties[:lon] + node.first["data"]["name"].should == "Max's Restaurant" + end + end + + describe "find geometries within distance" do + it "can find a geometry within distance" do + properties = {:name => "Max's Restaurant", :lat => 41.8819, :lon => 87.6278} + node = @neo.find_geometries_within_distance("restaurants", 87.627, 41.881, 10) + node.should_not be_empty + node.first["data"]["lat"].should == properties[:lat] + node.first["data"]["lon"].should == properties[:lon] + node.first["data"]["name"].should == "Max's Restaurant" + end + + it "can find a geometry within distance using cypher" do + properties = {:name => "Max's Restaurant", :lat => 41.8819, :lon => 87.6278} + node = @neo.execute_query("start n = node:restaurants({bbox}) return n", {:bbox => "withinDistance:[87.6278,41.8819,10.0]"}) + node.should_not be_empty + puts node.inspect + node.first["data"]["lat"].should == properties[:lat] + node.first["data"]["lon"].should == properties[:lon] + node.first["data"]["name"].should == "Max's Restaurant" + end end + + describe "complete example" do + it "can do what the manual does" do + @neo.add_point_layer("geom", "lat", "lon") + node = @neo.create_node({:lat => 60.1, :lon => 15.2}) + @neo.create_spatial_index("geom", "point", "lat", "lon") + @neo.add_node_to_layer("geom", node) + + existing_node = @neo.find_geometries_in_bbox("geom", 15.0,15.3,60.0,60.3) + existing_node.first["data"]["lat"].should == 60.1 + existing_node.first["data"]["lon"].should == 15.2 + + existing_node = @neo.find_geometries_within_distance("geom", 15.0, 60.0, 100.0) + existing_node.first["data"]["lat"].should == 60.1 + existing_node.first["data"]["lon"].should == 15.2 + + added = @neo.add_node_to_index("geom", "dummy", "dummy", node) + existing_node = @neo.execute_query("start node = node:geom(\'bbox:[15.0,15.3,60.0,60.2]\') return node") + puts existing_node.inspect + existing_node.first["data"]["lat"].should == 60.1 + existing_node.first["data"]["lon"].should == 15.2 + + existing_node = @neo.execute_query("start node = node:geom(\'withinDistance:[60.0,15.0, 100.0]\') return node") + puts existing_node.inspect + existing_node.first["data"]["lat"].should == 60.1 + existing_node.first["data"]["lon"].should == 15.2 + end + end + + end \ No newline at end of file