neo4jrb_spatial 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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: []