neo4apis 0.0.1

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 30ba847cad3af0957ed3e603dd236b5037c80f20
4
+ data.tar.gz: eb86312649a77abe55ae3c668b178709cb5ac803
5
+ SHA512:
6
+ metadata.gz: 1ac9fcb8bbe6b8f1f934df3f81ad6dbeb267fcc502bff457fe3b7a6698963d0de9dff9f51874f1f0125585c1ee62af9975384b3ad3231832ae882d4c5fbfdf7c
7
+ data.tar.gz: bd4597cad7cf2adf0a6c4dab7e2235e6ce3b7c86b45b30f1e07fa564179fbc0930eda0c6134b67ed30553c64bebce29fd9edc3c9b2d8eee78d1fb8a7b5aa6758
data/Gemfile ADDED
@@ -0,0 +1,16 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ gem 'neo4j-core', '~> 3.0.0', path: '/Users/brian/github/neo4jrb/neo4j-core'
6
+
7
+ gem 'twitter'
8
+
9
+ group :development do
10
+ gem 'pry'
11
+ end
12
+
13
+ group :test do
14
+ gem 'rspec'
15
+ end
16
+
data/README.md ADDED
@@ -0,0 +1,73 @@
1
+
2
+ neo4apis is a ruby gem for building gems which import data into neo4j. Takes care of batching of queries for better import performance
3
+
4
+ In the below example we assume that a variable `awesome_client` is passed in which allows us to make requests to the API. This may be, for example, provided by another gem.
5
+
6
+ ```ruby
7
+ require 'neo4apis'
8
+
9
+ module Neo4Apis
10
+ class AwesomeSite < Base
11
+ PREFIX = 'awesome_site'
12
+
13
+ def initialize(neo4j_client, options = {})
14
+ @client = options[:awesome_client]
15
+
16
+ options[:uuids] = (options[:uuids] || {}).merge({
17
+ User: :id,
18
+ Widget: :uuid
19
+ })
20
+
21
+ super(neo4j_client, options)
22
+ end
23
+
24
+ def import_widget_search(*args)
25
+ @client.widget_search(*args).each do |widget|
26
+ add_widget(widget)
27
+ end
28
+ end
29
+
30
+ private
31
+
32
+ def add_widget(widget)
33
+ user_node = add_user(widget.owner)
34
+
35
+ # add_node comes from From Neo4Apis::Base
36
+ node = add_node :Widget, {
37
+ uuid: widget.uuid,
38
+ text: widget.text,
39
+ }
40
+
41
+ # add_relationship comes from Neo4Apis::Base
42
+ add_relationship(:owns, user_node, node)
43
+
44
+ node
45
+ end
46
+
47
+ def add_user(user)
48
+ add_node :User, {
49
+ id: user.id,
50
+ username: user.username,
51
+ name: user.name,
52
+ }
53
+ end
54
+
55
+ end
56
+ end
57
+ ```
58
+
59
+ Then somebody else could use your gem in the following manner:
60
+
61
+ ```ruby
62
+
63
+ neo4j_session = Neo4j::Session.open # From the neo4j-core gem
64
+ awesome_client = Awesome.open # From a theoretical API wrapping gem
65
+
66
+ neo4apis_awesome = Neo4Apis::AwesomeSite.new(neo4j_session, awesome_client: awesome_client)
67
+
68
+ neo4apis_awesome.batch do
69
+ neo4apis_awesome.import_widget_search('cool') # Does a search for 'cool' via the Awesome gem and imports to the neo4j database
70
+ end
71
+
72
+ ```
73
+
@@ -0,0 +1,82 @@
1
+ module Neo4Apis
2
+ class Base
3
+ DEFAULT_FLUSH_SIZE = 500
4
+
5
+ NODE_PROXIES = {}
6
+
7
+ def initialize(neo4j_session, options = {})
8
+ @buffer = QueryBuffer.new(neo4j_session)
9
+ @flush_size = DEFAULT_FLUSH_SIZE
10
+ (options[:uuids] || {}).each do |label, uuid_field|
11
+ NODE_PROXIES[label] = Struct.new(:label, :props) do
12
+ const_set(:UUID_FIELD, uuid_field)
13
+
14
+ def uuid_value
15
+ raise ArgumentError, "props does not have UUID field `#{uuid_field}` for #{self.inspect}" if not props.has_key?(uuid_field)
16
+
17
+ props[uuid_field]
18
+ end
19
+
20
+ def uuid_field
21
+ self.class::UUID_FIELD
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ def add_node(label, props = {})
28
+ require_batch
29
+
30
+ node_proxy = NODE_PROXIES[label]
31
+ raise ArgumentError, "No UUID specified for label `#{label}`" if not node_proxy
32
+
33
+ node_proxy.new(label, props).tap do |node_proxy|
34
+ @buffer << create_node_query(node_proxy)
35
+ end
36
+ end
37
+
38
+ def add_relationship(type, source, target, props = {})
39
+ raise ArgumentError, "No source specified" if not source
40
+ raise ArgumentError, "No target specified" if not target
41
+
42
+ require_batch
43
+
44
+ @buffer << create_relationship_query(type, source, target, props)
45
+ end
46
+
47
+ def batch
48
+ @in_batch = true
49
+
50
+ yield
51
+
52
+ @buffer.flush
53
+ ensure
54
+ @in_batch = false
55
+ end
56
+
57
+ private
58
+
59
+ def create_node_query(node_proxy)
60
+ Neo4j::Core::Query.new.
61
+ merge(node: {node_proxy.label => {node_proxy.uuid_field => node_proxy.uuid_value}}).
62
+ on_create_set(node: node_proxy.props)
63
+ end
64
+
65
+ def create_relationship_query(type, source, target, props)
66
+ Neo4j::Core::Query.new.
67
+ match(source: {source.label => {source.uuid_field => source.uuid_value}}).
68
+ match(target: {target.label => {target.uuid_field => target.uuid_value}}).
69
+ merge("source-[:#{type}]->target")
70
+ end
71
+
72
+ def add_to_buffer(*args)
73
+ flush_buffer if buffer.size >= FLUSH_SIZE
74
+
75
+ @buffer << args
76
+ end
77
+
78
+ def require_batch
79
+ raise "Must be in a batch" if not @in_batch
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,51 @@
1
+ module Neo4Apis
2
+ class QueryBuffer < Array
3
+
4
+ def initialize(neo4j_session)
5
+ @neo4j_session = neo4j_session
6
+
7
+ uri = URI.parse(@neo4j_session.resource_url)
8
+
9
+ @faraday_connection = Faraday.new(:url => "#{uri.scheme}://#{uri.host}:#{uri.port}") do |faraday|
10
+ faraday.request :url_encoded # form-encode POST params
11
+ faraday.response :logger # log requests to STDOUT
12
+ faraday.adapter Faraday.default_adapter # make requests with Net::HTTP
13
+ end
14
+
15
+ super()
16
+ end
17
+
18
+ def flush
19
+ execute
20
+
21
+ clear
22
+ end
23
+
24
+
25
+ private
26
+
27
+ def execute
28
+ puts "request_body_data", request_body_data.inspect
29
+ @faraday_connection.post do |req|
30
+ req.url '/db/data/transaction/commit'
31
+ req.headers['Accept'] = 'application/json; charset=UTF-8'
32
+ req.headers['Content-Type'] = 'application/json'
33
+ req.headers['X-Stream'] = 'true'
34
+ req.body = request_body_data.to_json
35
+ end
36
+ end
37
+
38
+ def request_body_data
39
+ {
40
+ statements: self.map do |query|
41
+ {
42
+ statement: query.to_cypher,
43
+ parameters: query.send(:merge_params)
44
+ }
45
+ end
46
+ }
47
+ end
48
+
49
+ end
50
+ end
51
+
@@ -0,0 +1,3 @@
1
+ module Neo4Apis
2
+ VERSION = '0.0.1'
3
+ end
data/lib/neo4apis.rb ADDED
@@ -0,0 +1,6 @@
1
+ require 'neo4j-core'
2
+
3
+ require 'neo4apis/version'
4
+
5
+ require 'neo4apis/query_buffer'
6
+ require 'neo4apis/base'
data/neo4apis.gemspec ADDED
@@ -0,0 +1,26 @@
1
+ lib = File.expand_path('../lib/', __FILE__)
2
+ $:.unshift lib unless $:.include?(lib)
3
+
4
+ require 'neo4apis/version'
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "neo4apis"
8
+ s.version = Neo4Apis::VERSION
9
+ s.required_ruby_version = ">= 1.9.1"
10
+
11
+ s.authors = "Brian Underwood"
12
+ s.email = 'public@brian-underwood.codes'
13
+ s.homepage = "https://github.com/neo4jrb/neo4apis/"
14
+ s.summary = "An API to import web API data to neo4j"
15
+ s.license = 'MIT'
16
+ s.description = <<-EOF
17
+ A core library for importing data from APIs into neo4j. Designed to be used with an adapter
18
+ EOF
19
+
20
+ s.require_path = 'lib'
21
+ s.files = Dir.glob("{bin,lib,config}/**/*") + %w(README.md Gemfile neo4apis.gemspec)
22
+
23
+ s.add_dependency('faraday', "~> 0.9.0")
24
+ s.add_dependency("neo4j-core", "~> 3.0.3")
25
+
26
+ end
metadata ADDED
@@ -0,0 +1,79 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: neo4apis
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Brian Underwood
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-10-29 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: faraday
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.9.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.9.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: neo4j-core
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 3.0.3
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 3.0.3
41
+ description: |
42
+ A core library for importing data from APIs into neo4j. Designed to be used with an adapter
43
+ email: public@brian-underwood.codes
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - Gemfile
49
+ - README.md
50
+ - lib/neo4apis.rb
51
+ - lib/neo4apis/base.rb
52
+ - lib/neo4apis/query_buffer.rb
53
+ - lib/neo4apis/version.rb
54
+ - neo4apis.gemspec
55
+ homepage: https://github.com/neo4jrb/neo4apis/
56
+ licenses:
57
+ - MIT
58
+ metadata: {}
59
+ post_install_message:
60
+ rdoc_options: []
61
+ require_paths:
62
+ - lib
63
+ required_ruby_version: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: 1.9.1
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: '0'
73
+ requirements: []
74
+ rubyforge_project:
75
+ rubygems_version: 2.2.2
76
+ signing_key:
77
+ specification_version: 4
78
+ summary: An API to import web API data to neo4j
79
+ test_files: []