neo4jrb_spatial 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d9a8fabd817cc1db5b5d5f6f7466a1c0850f7359
4
+ data.tar.gz: 39f2e8a65c7a8a3f4baf988423be0916b6a9c282
5
+ SHA512:
6
+ metadata.gz: 3fd46e9a2b1605f8539f97c68fb9fecfd39f9a4949a20a18a811ce0ac697c015e0d181b6882c45d2b1f9bdaf7e5d895e0252a6b7c7ee4b483c07c0c962e10fca
7
+ data.tar.gz: 0d2eedf8a8df07564138fd9e2be26c0fad14b2f424169fbae7fbd7c4f8a8289f563e57af8ae3b2546a7e9e74889f5a1cbdd685d0c7464b266b85410869a68a9f
@@ -0,0 +1,11 @@
1
+ # Change Log
2
+ All notable changes to this project will be documented in this file.
3
+ This file should follow the standards specified on [http://keepachangelog.com/]
4
+ This project adheres to [Semantic Versioning](http://semver.org/).
5
+
6
+ ## [Unreleased][unreleased]
7
+
8
+ ## [1.0.0] - 2015-06-TBD
9
+
10
+ ### Added
11
+ - Everything. It's all new.
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+ # gem 'neo4j', github: 'neo4jrb/neo4j', branch: 'master'
3
+ gem 'neo4j-core', github: 'neo4jrb/neo4j-core', branch: 'master'
4
+
5
+ # Specify your gem's dependencies in neo4jrb_spatial.gemspec
6
+ gemspec
@@ -0,0 +1,107 @@
1
+ # Neo4jrbSpatial
2
+
3
+ Provides support for Neo4j Spatial to Neo4j.rb 5+.
4
+
5
+ It is more or less a Neo4j.rb-flavored implementation of [Max De Marzi](https://github.com/maxdemarzi)'s
6
+ [code](https://github.com/maxdemarzi/neography/blob/46be2bb3c66aea14e707b1e6f82937e65f686ccc/lib/neography/rest/spatial.rb) from
7
+ [Neography](https://github.com/maxdemarzi/neography).
8
+
9
+ For support, open an issue or say hello through [Gitter](https://gitter.im/neo4jrb/neo4j).
10
+
11
+ ## What it provides
12
+
13
+ * Basic index and layer management
14
+ * Basic node-to-index management
15
+ * Hooks for Neo4j::ActiveNode::Query::QueryProxy models if you are using them
16
+
17
+ It is powered by an implementation of [Neography's](https://github.com/maxdemarzi/neography) [spatial module](https://github.com/maxdemarzi/neography/blob/46be2bb3c66aea14e707b1e6f82937e65f686ccc/lib/neography/rest/spatial.rb).
18
+ Clearly, a huge debt is owed to [Max De Marzi](https://github.com/maxdemarzi) for doing all the hard work.
19
+
20
+ ## Requirements
21
+
22
+ * Neo4j-core 5.0.1+
23
+ * Neo4j Server 2.2.2+ (earlier versions will likely work but are not tested)
24
+ * Ruby MRI 2.2.2+
25
+ * Compatible version of [Neo4j Spatial](https://github.com/neo4j-contrib/spatial)
26
+
27
+ Optionally:
28
+
29
+ * v5.0.1+ of the [Neo4j gem](https://github.com/neo4jrb/neo4j)
30
+
31
+ # Usage
32
+
33
+
34
+ ## Require it
35
+
36
+ ```
37
+ # neo4j-core only?
38
+ require 'neo4j/spatial'
39
+
40
+ # neo4j gem/ActiveNode can omit the line above, just include the module in your model
41
+ include Neo4j::ActiveNode::Spatial
42
+ ```
43
+
44
+ ## Basics - Neo4j-core
45
+
46
+ ```ruby
47
+ # Create an index
48
+ Neo4j::Session.current.create_spatial_index('restaurants')
49
+
50
+ # Create a node
51
+ node = Neo4j::Node.create({:name => "Indie Cafe", :lat => 41.990326, :lon => -87.672907 }, :Restaurant)
52
+
53
+ # Add a node to the index
54
+ Neo4j::Session.current.add_node_to_spatial_index('restaurants', node)
55
+
56
+ # Query around the index
57
+ Neo4j::Session.current.query.start('n = node:restaurants({location})').params(location: 'withinDistance:[41.99,-87.67,10.0]').pluck(:n)
58
+ # => CypherNode 90126 (70333884677220)
59
+ ```
60
+
61
+ ## Basics - Neo4j gem
62
+
63
+ Neo4j.rb does not support legacy indexes, so a helper method is provided to add nodes. As with normal properties, your lat and lon
64
+ should be explicitly declared.
65
+
66
+ ### Automatic index addition
67
+
68
+ At the moment, automatic index addition is not implemented.
69
+
70
+ ### Manual index addition
71
+
72
+ All of the Neo4j-core spatial methods accept ActiveNode-including nodes, so you can use them as arguments for all defined methods as you would
73
+ Neo4j::Server::CypherNode instances.
74
+
75
+ Additionally, you can call the `add_to_spatial_index` instance method on any node to add it to its model's defined index.
76
+
77
+ ### Spatial queries
78
+
79
+ No helpers are provided to query against the REST API -- you'll need to use the ones provided for Neo4j-core; however, a class method is provided
80
+ to make Cypher queries easier: `spatial_match`.
81
+
82
+ ```
83
+ # Use the index defined on the model as demonstrated above
84
+ Restaurant.all.spatial_match(:r, params_string)
85
+ # Generates:
86
+ # => "START r = node:restaurants({params_string})"
87
+ ```
88
+
89
+ It then drops you back into a QueryProxy in the context of the class. If you had an `employees` association defined in your model:
90
+
91
+ ```
92
+ # Find all restaurants within the specified distance, then find their employees who are age 30
93
+ Restauarant.all.spatial_match(:r, 'withinDistance:[41.99,-87.67,10.0]').employees.where(age: 30)
94
+ ```
95
+
96
+ Alternatively, if you did no define `spatial_index` on your model, you can feed a third argument: the index to use for the query.
97
+
98
+ ## Additional Resources
99
+
100
+ Check out the specs and the code for help, it's rather straightforward.
101
+
102
+ [Max's blog post](http://maxdemarzi.com/2014/01/31/neo4j-spatial-part-1/) on using Neography with Spatial
103
+ mostly works for an idea of the basics, just replace Neography-specific commands with their Neo4j-core versions.
104
+
105
+ ## Contributions
106
+
107
+ Pull requests and maintanence help would be swell. In addition to being fully tested, please ensure rubocop passes by running `rubocop` from the CLI.
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'neo4jrb_spatial'
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require 'irb'
14
+ IRB.start
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,40 @@
1
+ module Neo4j::ActiveNode
2
+ module Spatial
3
+ def self.included(other)
4
+ other.extend(ClassMethods)
5
+ end
6
+
7
+ def add_to_spatial_index(index_name = nil)
8
+ index = index_name || self.class.spatial_index_name
9
+ fail 'index name not found' unless index
10
+ Neo4j::Session.current.add_node_to_spatial_index(index, self)
11
+ end
12
+
13
+ module ClassMethods
14
+ attr_reader :spatial_index_name
15
+ def spatial_index(index_name = nil)
16
+ return spatial_index_name unless index_name
17
+ # create_index_callback(index_name)
18
+ @spatial_index_name = index_name
19
+ end
20
+
21
+ # This will not work for now. Neo4j Spatial's REST API doesn't seem to work within transactions.
22
+ # def create_index_callback(index_name)
23
+ # after_create(proc { |node| Neo4j::Session.current.add_node_to_spatial_index(index_name, node) })
24
+ # end
25
+
26
+ # private :create_index_callback
27
+ end
28
+
29
+ class Query::QueryProxy
30
+ def spatial_match(var, params_string, spatial_index = nil)
31
+ index = model.spatial_index_name || spatial_index
32
+ fail 'Cannot query without index. Set index in model or as third argument.' unless index
33
+ Neo4j::Session.current.query
34
+ .start("#{var} = node:#{index}({spatial_params})")
35
+ .proxy_as(model, var)
36
+ .params(spatial_params: params_string)
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,130 @@
1
+ module Neo4j::Server
2
+ module Spatial
3
+ def spatial?
4
+ Neo4j::Session.current.connection.get('/db/data/ext/SpatialPlugin').status == 200
5
+ end
6
+
7
+ def spatial_plugin
8
+ Neo4j::Session.current.connection.get('/db/data/ext/SpatialPlugin').body
9
+ end
10
+
11
+ def add_point_layer(layer, lat = nil, lon = nil)
12
+ options = {
13
+ layer: layer,
14
+ lat: lat || 'lat',
15
+ lon: lon || 'lon'
16
+ }
17
+
18
+ spatial_post('/ext/SpatialPlugin/graphdb/addSimplePointLayer', options)
19
+ end
20
+
21
+ def add_editable_layer(layer, format = 'WKT', node_property_name = 'wkt')
22
+ options = {
23
+ layer: layer,
24
+ format: format,
25
+ nodePropertyName: node_property_name
26
+ }
27
+
28
+ spatial_post('/ext/SpatialPlugin/graphdb/addEditableLayer', options)
29
+ end
30
+
31
+ def get_layer(layer)
32
+ options = {
33
+ layer: layer
34
+ }
35
+ spatial_post('/ext/SpatialPlugin/graphdb/getLayer', options)
36
+ end
37
+
38
+ def add_geometry_to_layer(layer, geometry)
39
+ options = {
40
+ layer: layer,
41
+ geometry: geometry
42
+ }
43
+ spatial_post('/ext/SpatialPlugin/graphdb/addGeometryWKTToLayer', options)
44
+ end
45
+
46
+ def edit_geometry_from_layer(layer, geometry, node)
47
+ options = {
48
+ layer: layer,
49
+ geometry: geometry,
50
+ geometryNodeId: get_id(node)
51
+ }
52
+ spatial_post('/ext/SpatialPlugin/graphdb/updateGeometryFromWKT', options)
53
+ end
54
+
55
+ def add_node_to_layer(layer, node)
56
+ options = {
57
+ layer: layer,
58
+ node: "#{resource_url}node/#{node.neo_id}"
59
+ }
60
+ spatial_post('/ext/SpatialPlugin/graphdb/addNodeToLayer', options)
61
+ end
62
+
63
+ def find_geometries_in_bbox(layer, minx, maxx, miny, maxy)
64
+ options = {
65
+ layer: layer,
66
+ minx: minx,
67
+ maxx: maxx,
68
+ miny: miny,
69
+ maxy: maxy
70
+ }
71
+ spatial_post('/ext/SpatialPlugin/graphdb/findGeometriesInBBox', options)
72
+ end
73
+
74
+ def find_geometries_within_distance(layer, pointx, pointy, distance)
75
+ options = {
76
+ layer: layer,
77
+ pointX: pointx,
78
+ pointY: pointy,
79
+ distanceInKm: distance
80
+ }
81
+ spatial_post('/ext/SpatialPlugin/graphdb/findGeometriesWithinDistance', options)
82
+ end
83
+
84
+ def create_spatial_index(name, type = nil, lat = nil, lon = nil)
85
+ options = {
86
+ name: name,
87
+ config: {
88
+ provider: 'spatial',
89
+ geometry_type: type || 'point',
90
+ lat: lat || 'lat',
91
+ lon: lon || 'lon'
92
+ }
93
+ }
94
+ spatial_post('/index/node', options)
95
+ end
96
+
97
+ def add_node_to_spatial_index(index, node)
98
+ options = {
99
+ uri: "/#{get_id(node)}",
100
+ key: 'k',
101
+ value: 'v'
102
+ }
103
+ spatial_post("/index/node/#{index}", options)
104
+ end
105
+
106
+ private
107
+
108
+ def spatial_post(path, options)
109
+ Neo4j::Session.current.connection.post("/db/data/#{path}", options).body
110
+ end
111
+
112
+ def get_id(id)
113
+ return id.neo_id if id.respond_to?(:neo_id)
114
+ case id
115
+ when Array
116
+ get_id(id.first)
117
+ when Hash
118
+ id[:self].split('/').last
119
+ when String
120
+ id.split('/').last
121
+ else
122
+ id
123
+ end
124
+ end
125
+ end
126
+
127
+ class CypherSession
128
+ include Spatial
129
+ end
130
+ end
@@ -0,0 +1,3 @@
1
+ require 'neo4jrb_spatial/version'
2
+ require 'neo4j/spatial'
3
+ require 'neo4j/active_node/spatial'
@@ -0,0 +1,3 @@
1
+ module Neo4jrbSpatial
2
+ VERSION = '1.0.0'
3
+ end
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'neo4jrb_spatial/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'neo4jrb_spatial'
8
+ spec.version = Neo4jrbSpatial::VERSION
9
+ spec.authors = ['Chris Grigg']
10
+ spec.email = ['chris@subvertallmedia.com']
11
+
12
+ spec.summary = 'Provides basic support for Neo4j Spatial with Neo4j.rb.'
13
+ spec.homepage = 'https://github.com/neo4jrb/neo4jrb_spatial'
14
+
15
+ spec.files = Dir.glob('{bin,lib,config}/**/*') + %w(README.md CHANGELOG.md Gemfile neo4jrb_spatial.gemspec)
16
+ spec.bindir = 'exe'
17
+ spec.require_paths = ['lib']
18
+
19
+ spec.add_development_dependency 'bundler', '~> 1.9'
20
+ spec.add_development_dependency 'rake', '~> 10.0'
21
+ spec.add_development_dependency('rubocop', '~> 0.29.1')
22
+ spec.add_development_dependency 'rspec'
23
+ spec.add_development_dependency 'pry'
24
+
25
+ spec.add_dependency 'neo4j', '~> 5.0.1'
26
+ spec.add_dependency 'neo4j-core', '~> 5.0.1'
27
+ end
metadata ADDED
@@ -0,0 +1,151 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: neo4jrb_spatial
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Chris Grigg
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2015-06-29 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.9'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.9'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rubocop
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 0.29.1
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 0.29.1
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: pry
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: neo4j
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 5.0.1
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 5.0.1
97
+ - !ruby/object:Gem::Dependency
98
+ name: neo4j-core
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 5.0.1
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 5.0.1
111
+ description:
112
+ email:
113
+ - chris@subvertallmedia.com
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - CHANGELOG.md
119
+ - Gemfile
120
+ - README.md
121
+ - bin/console
122
+ - bin/setup
123
+ - lib/neo4j/active_node/spatial.rb
124
+ - lib/neo4j/spatial.rb
125
+ - lib/neo4jrb_spatial.rb
126
+ - lib/neo4jrb_spatial/version.rb
127
+ - neo4jrb_spatial.gemspec
128
+ homepage: https://github.com/neo4jrb/neo4jrb_spatial
129
+ licenses: []
130
+ metadata: {}
131
+ post_install_message:
132
+ rdoc_options: []
133
+ require_paths:
134
+ - lib
135
+ required_ruby_version: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ version: '0'
140
+ required_rubygems_version: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - ">="
143
+ - !ruby/object:Gem::Version
144
+ version: '0'
145
+ requirements: []
146
+ rubyforge_project:
147
+ rubygems_version: 2.4.6
148
+ signing_key:
149
+ specification_version: 4
150
+ summary: Provides basic support for Neo4j Spatial with Neo4j.rb.
151
+ test_files: []