Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update for Neo4J 3.x, neo4jrb 8.x, and neojrb-core 7.0.x #18

Merged
merged 12 commits into from
Jun 24, 2017
10 changes: 10 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,13 @@
.idea
bin/
/db

# shapfile stuff
*.CPG
*.dbf
*.prj
*.sbn
*.sbx
*.shp
*.shp.xml
*.shx
5 changes: 3 additions & 2 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ Style/SpaceInsideHashLiteralBraces:
Style/FileName:
Enabled: false

Metrics/AbcSize:
Max: 20

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I always really, really try to avoid allowing the code to get more complex on a global level. Rarely I'll make a rubocop:disable comment around the method itself if I absolutely need to, but most of the time I can find a way to refactor and most of the time my code is better for it (not always ;) )

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, I'd suggest running rubocop -aD. That will fix any issues that it can, and then you can resolve the rest. The D will output the cop's name so that you can look it up in case you don't know what it's talking about ;)

#---------------------------
# Don't intend to fix these:
#---------------------------
Expand Down Expand Up @@ -68,5 +71,3 @@ Style/Lambda:
# Reason: I'm proud to be part of the double negative Ruby tradition
Style/DoubleNegation:
Enabled: false


12 changes: 2 additions & 10 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,21 @@ install:
- "bundle exec rake neo4j_spatial:install"
- "bundle exec rake neo4j:start --trace"
- "sleep 20"
- "bundle exec rake neo4j:generate_schema_migration[constraint,Restaurant,uuid]"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can certainly do this, but the specs won't work on other peoples' machines unless they know to run this line. I generally try to do something like this inside the specs themselves:

Neo4j::ActiveBase.label_object(: Restaurant).create_constraint(:uuid, type: :unique)

You might also rescue from Neo4j::Core::CypherSession::SchemaErrors::IndexAlreadyExistsError so that if it already exists it doesn't just fail

sudo: false
cache: bundler
script:
- "travis_retry bundle exec rake default --trace"
language: ruby
jdk: oraclejdk8
rvm:
- 2.0.0
- 2.2.4
- 2.3.1
- jruby-9.0.5.0
env:
global:
- JRUBY_OPTS="-J-Xmx1280m -Xcompile.invokedynamic=false -J-XX:+TieredCompilation -J-XX:TieredStopAtLevel=1 -J-noverify -Xcompile.mode=OFF"
- NEO4J_VERSION=3.0.1
- NEO4J_VERSION=3.1.0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3.2 just came out, BTW ;)

matrix:
- NEO4J_URL="http://localhost:7474"
matrix:
Expand All @@ -32,11 +32,3 @@ matrix:
install:
script: "bundle exec rubocop"
env: "RUBOCOP=true"

# Older versions of Neo4j with latest version of Ruby
- rvm: 2.3.1
env: NEO4J_VERSION=2.3.3
- rvm: 2.3.1
env: NEO4J_VERSION=2.2.2
- rvm: 2.3.1
env: NEO4J_VERSION=2.1.8
32 changes: 32 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,12 @@ It then drops you back into a QueryProxy in the context of the class. If you had

If you did no define `spatial_index` on your model or what to query against something other than the model's default, you can feed a third argument: the index to use for the query.

## Rake tasks:
#### `neo4j_spatial:install`

usage: `NEO4J_VERSION='3.0.4' rake neo4j_spatial:install[<env>]`
If no `env` argument is provided, this defaults to 'development'

## Additional Resources

Check out the specs and the code for help, it's rather straightforward.
Expand All @@ -136,3 +142,29 @@ mostly works for an idea of the basics, just replace Neography-specific commands
## Contributions

Pull requests and maintanence help would be swell. In addition to being fully tested, please ensure rubocop passes by running `rubocop` from the CLI.

### Running Tests:

Upon first running `bundle exec rake spec` or `bundle exec rspec spec`, you may run into an issue like this:

```
Failure/Error: Restaurant.delete_all

Neo4j::DeprecatedSchemaDefinitionError:
Some schema elements were defined by the model (which is no longer supported), but they do not exist in the database. Run the following to create them:

rake neo4j:generate_schema_migration[constraint,Restaurant,uuid]


And then run `rake neo4j:migrate`
...
```

To resolve, simply run the commands as it says (but maybe prefix `bundle exec` depending on your setup):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I see that you have this in the docs (which is great!). It would be nicer, though, if people didn't need to think about it


```
bundle exec rake neo4j:generate_schema_migration[constraint,Restaurant,uuid]
bundle exec rake neo4j:migrate
```

NOTE that if your NEO4J_URL is not the default, you will have to prefix while running migrate: `NEO4J_URL='http://localhost:7123' be rake neo4j:migrate`
40 changes: 3 additions & 37 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -1,45 +1,11 @@
require 'bundler/gem_tasks'
require 'neo4j'
require 'neo4j/rake_tasks'
require 'net/http'

def system_or_fail(command)
system(command) || exit(1)
end
require 'neo4jrb_spatial/rake_tasks'
load 'neo4j/tasks/migration.rake'

task 'spec' do
system_or_fail('rspec spec')
end

namespace :neo4j_spatial do
def match_version?(version, max_version)
min_version = max_version.split('.')[0..-1].join('.')
Gem::Version.new(version) <= Gem::Version.new(max_version) &&
Gem::Version.new(version) >= Gem::Version.new(min_version)
end

def matching_version(version)
uri = 'https://raw.githubusercontent.com/neo4j-contrib/m2/master/releases/org/neo4j/neo4j-spatial/maven-metadata.xml'
versions = Net::HTTP.get_response(URI.parse(uri)).body
versions = versions.scan(/<version>([a-z\-0-9\.]+)<\/version>/)
versions.map! { |e| e.first.split('-neo4j-') }
versions.select { |e| match_version?(version, e.last) }.last
end

task 'install' do
url = 'https://github.com/neo4j-contrib/m2/blob/master/releases/org/neo4j/neo4j-spatial'
input_version = ENV['NEO4J_VERSION']
fail ArgumentError, 'Missing NEO4J_VERSION' unless input_version
spatial_version, neo4j_version = *matching_version(input_version)
if neo4j_version[0].to_i < 3
file_name = "neo4j-spatial-#{spatial_version}-neo4j-#{neo4j_version}-server-plugin.zip"
system_or_fail("wget -O #{file_name} #{url}/#{spatial_version}-neo4j-#{neo4j_version}/#{file_name}?raw=true")
system_or_fail("unzip #{file_name} -d ./db/neo4j/development/plugins")
else
file_name = "neo4j-spatial-#{spatial_version}-neo4j-#{neo4j_version}-server-plugin.jar"
system_or_fail("wget -O #{file_name} #{url}/#{spatial_version}-neo4j-#{neo4j_version}/#{file_name}?raw=true")
system_or_fail("mv #{file_name} ./db/neo4j/development/plugins")
end
end
end

task default: ['spec']
79 changes: 58 additions & 21 deletions lib/neo4j/active_node/spatial.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,38 +5,75 @@ def self.included(other)
other.extend(ClassMethods)
end

def add_to_spatial_index(index_name = nil)
index = index_name || self.class.spatial_index_name
fail 'index name not found' unless index
Neo4j::Session.current.add_node_to_spatial_index(index, self)
def add_to_spatial_layer(layer_name = nil)
layer = layer_name || self.class.spatial_layer_name
fail 'layer name not found' unless layer
Neo4j::ActiveBase.current_session.add_node_to_layer(layer, self)
end

module ClassMethods
attr_reader :spatial_index_name
def spatial_index(index_name = nil)
return spatial_index_name unless index_name
# create_index_callback(index_name)
@spatial_index_name = index_name
attr_reader :spatial_layer_name
attr_reader :spatial_layer_type
attr_reader :spatial_layer_config

def spatial_layer(layer_name = nil, options = {})
return spatial_layer_name unless layer_name

@spatial_layer_name = layer_name
@spatial_layer_type = options.fetch(:type, 'SimplePoint')
@spatial_layer_config = options.fetch(:config, 'lon:lat')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about having a Struct instead? Something like:

attr_reader :spatial_layer

SpatialLayer = Struct.new(:name, :type, :config)
def spatial_layer(layer_name = nil, options = {})
  return spatial_layer_name unless layer_name

  @spatial_layer = SpatialLayer.new(layer_name, options.fetch(:type, 'SimplePoint'), options.fetch(:config, 'lon:lat'))
end


spatial_layer_name
end

# This will not work for now. Neo4j Spatial's REST API doesn't seem to work within transactions.
# def create_index_callback(index_name)
# after_create(proc { |node| Neo4j::Session.current.add_node_to_spatial_index(index_name, node) })
# end
def create_layer
fail 'layer name not found' unless spatial_layer_name

# private :create_index_callback
lon_name, lat_name = spatial_layer_config.split(':')

Neo4j::ActiveBase.current_session.add_layer(spatial_layer_name, spatial_layer_type, lat_name, lon_name)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might just be part of the original API, but it feels strange to extend the session objects with add_layer / remove_layer / within_distance / etc... I would expect maybe some other object which is given a session on initialization. Depends on if you find that worthwhile and if you want to go to the extent of changing it

end

def remove_layer
fail 'layer name not found' unless spatial_layer_name

Neo4j::ActiveBase.current_session.remove_layer(spatial_layer_name)
end
end
end

module Query
class QueryProxy
def spatial_match(var, params_string, spatial_index = nil)
index = model.spatial_index_name || spatial_index
fail 'Cannot query without index. Set index in model or as third argument.' unless index
Neo4j::Session.current.query
.start("#{var} = node:#{index}({spatial_params})")
.proxy_as(model, var)
.params(spatial_params: params_string)
def within_distance(coordinate, distance, layer_name = nil)
layer = model.spatial_layer_name || layer_name

Neo4j::ActiveBase.current_session
.within_distance(layer, coordinate, distance, execute: false)
.proxy_as(model, :node)
end

def bbox(min, max, layer_name = nil)
layer = model.spatial_layer_name || layer_name

Neo4j::ActiveBase.current_session
.bbox(layer, min, max, execute: false)
.proxy_as(model, :node)
end

def closest(coordinate, distance = 100, layer_name = nil)
layer = model.spatial_layer_name || layer_name

Neo4j::ActiveBase.current_session
.closest(layer, coordinate, distance, execute: false)
.proxy_as(model, :node)
end

def intersects(geometry, layer_name = nil)
layer = model.spatial_layer_name || layer_name

Neo4j::ActiveBase.current_session
.intersects(layer, geometry, execute: false)
.proxy_as(model, :node)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, I'm not familiar with this gem, but using Neo4j::ActiveBase and proxy_as makes the gem dependent on the neo4j gem and thus couldn't be used with the neo4j-core gem by itself. That doesn't seem to be a big deal because proxy_as was used previously, but just thought I'd mention it

end
end
end
Expand Down
Loading