cypher_builder 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Guardfile +1 -1
- data/README.md +2 -0
- data/lib/cypher_builder.rb +11 -5
- data/lib/cypher_builder/alias.rb +1 -1
- data/lib/cypher_builder/{context.rb → infra/context.rb} +0 -0
- data/lib/cypher_builder/{payload.rb → infra/payload.rb} +0 -0
- data/lib/cypher_builder/{resolver.rb → infra/resolver.rb} +2 -0
- data/lib/cypher_builder/{runner.rb → infra/runner.rb} +0 -0
- data/lib/cypher_builder/limit.rb +16 -0
- data/lib/cypher_builder/match.rb +1 -1
- data/lib/cypher_builder/node.rb +2 -2
- data/lib/cypher_builder/order_by.rb +32 -0
- data/lib/cypher_builder/rel.rb +37 -0
- data/lib/cypher_builder/version.rb +1 -1
- data/spec/cypher_builder/cypher_spec.rb +16 -3
- data/spec/cypher_builder/node_spec.rb +3 -3
- data/spec/cypher_builder/order_by_spec.rb +24 -0
- data/spec/cypher_builder/rel_spec.rb +37 -0
- metadata +13 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 875bb9cde808a0014d2d16a22bbba9f9fa050f32
|
4
|
+
data.tar.gz: a8dc8091e8b7862273da2c20d81b9c1a956c5e0d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1f67659909ed0a09587c0779e491980e4cd7745f9a83e6a14065c6b0f45cee962106b32863267b219ccd8450bdadfd849a41191854f3a674115823bd0207d6f8
|
7
|
+
data.tar.gz: 270f94f3052508ff0ac7ad7d74a63fb68a2b335eb4eb860fb033eea4eb0dfb6e1d330274e849624fb36a3c2a0dfed5a83e643ef6b745a599f81f492a550350e9
|
data/Guardfile
CHANGED
@@ -32,7 +32,7 @@ clearing :on
|
|
32
32
|
# * zeus: 'zeus rspec' (requires the server to be started separately)
|
33
33
|
# * 'just' rspec: 'rspec'
|
34
34
|
|
35
|
-
guard :rspec, cmd: 'bundle exec rspec' do
|
35
|
+
guard :rspec, cmd: 'bundle exec rspec', all_on_start: true, keep: true, all_after_pass: true, run_all: { cmd: 'bundle exec rspec -f progress' } do
|
36
36
|
require 'guard/rspec/dsl'
|
37
37
|
dsl = Guard::RSpec::Dsl.new(self)
|
38
38
|
|
data/README.md
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# CypherBuilder
|
2
2
|
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/cypher_builder.svg)](http://badge.fury.io/rb/cypher_builder)
|
4
|
+
|
3
5
|
Build Cypher query classes (Neo4j).
|
4
6
|
|
5
7
|
It creates Command classes that executes Cypher queries using Neography. The goal is make class creation easier.
|
data/lib/cypher_builder.rb
CHANGED
@@ -11,16 +11,20 @@ if defined?(::Neography)
|
|
11
11
|
CypherBuilder::Adapter::DEFAULT = CypherBuilder::Adapter::Neography.new
|
12
12
|
end
|
13
13
|
|
14
|
-
require 'cypher_builder/payload'
|
15
|
-
require 'cypher_builder/context'
|
16
|
-
require 'cypher_builder/resolver'
|
17
|
-
require 'cypher_builder/runner'
|
18
|
-
require 'cypher_builder/cypher'
|
14
|
+
require 'cypher_builder/infra/payload'
|
15
|
+
require 'cypher_builder/infra/context'
|
16
|
+
require 'cypher_builder/infra/resolver'
|
17
|
+
require 'cypher_builder/infra/runner'
|
19
18
|
|
19
|
+
# Not in Cypher
|
20
|
+
require 'cypher_builder/cypher'
|
20
21
|
require 'cypher_builder/as_is'
|
21
22
|
require 'cypher_builder/opt'
|
23
|
+
|
24
|
+
# Cypher
|
22
25
|
require 'cypher_builder/field'
|
23
26
|
require 'cypher_builder/node'
|
27
|
+
require 'cypher_builder/rel'
|
24
28
|
require 'cypher_builder/param'
|
25
29
|
require 'cypher_builder/literal'
|
26
30
|
require 'cypher_builder/match'
|
@@ -30,3 +34,5 @@ require 'cypher_builder/eql'
|
|
30
34
|
require 'cypher_builder/like'
|
31
35
|
require 'cypher_builder/return'
|
32
36
|
require 'cypher_builder/alias'
|
37
|
+
require 'cypher_builder/order_by'
|
38
|
+
require 'cypher_builder/limit'
|
data/lib/cypher_builder/alias.rb
CHANGED
File without changes
|
File without changes
|
File without changes
|
data/lib/cypher_builder/match.rb
CHANGED
@@ -11,7 +11,7 @@ module CypherBuilder
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def as_cypher(payload:, context: )
|
14
|
-
resolve(@parts, format: 'MATCH
|
14
|
+
resolve(@parts, format: 'MATCH %s', separator: ', ', payload: payload, context: context.add(self))
|
15
15
|
end
|
16
16
|
end
|
17
17
|
end
|
data/lib/cypher_builder/node.rb
CHANGED
@@ -9,7 +9,7 @@ module CypherBuilder
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def as_cypher(_ = nil)
|
12
|
-
[@prefix, *@labels].compact.join(':')
|
12
|
+
::Kernel.sprintf('(%s)', [@prefix, *@labels].compact.join(':'))
|
13
13
|
end
|
14
14
|
|
15
15
|
def respond_to_missing?(name, include_private = false)
|
@@ -17,7 +17,7 @@ module CypherBuilder
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def method_missing(name, *_)
|
20
|
-
|
20
|
+
Field.new(@prefix, name)
|
21
21
|
end
|
22
22
|
end
|
23
23
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module CypherBuilder
|
2
|
+
class MicroResolver < Struct.new(:payload, :context)
|
3
|
+
include Resolver
|
4
|
+
def execute(value)
|
5
|
+
resolve(value, payload: payload, context: context)
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
def OrderBy(first, *rest)
|
10
|
+
OrderBy.new(first, *rest)
|
11
|
+
end
|
12
|
+
|
13
|
+
class OrderBy
|
14
|
+
include Resolver
|
15
|
+
def initialize(first, *rest)
|
16
|
+
@parts = wrap(*([first] + rest))
|
17
|
+
end
|
18
|
+
|
19
|
+
def as_cypher(payload:, context:)
|
20
|
+
rsv = MicroResolver.new(payload, context.add(self))
|
21
|
+
|
22
|
+
ps = @parts.reduce([]) do |r, v|
|
23
|
+
if r.last && AsIs === v
|
24
|
+
r[0..-2] + [[r.last, rsv.execute(v)].join(' ')]
|
25
|
+
else
|
26
|
+
r + [rsv.execute(v)]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
sprintf('ORDER BY %s', ps.join(', '))
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module CypherBuilder
|
2
|
+
def Rel(prefix, labels: [])
|
3
|
+
Rel.new(prefix, labels: labels)
|
4
|
+
end
|
5
|
+
|
6
|
+
class Rel < BasicObject
|
7
|
+
def initialize(prefix, labels: [], from: nil, to: nil)
|
8
|
+
@prefix, @labels = prefix, ::Kernel.Array(labels)
|
9
|
+
@from, @to = from, to
|
10
|
+
end
|
11
|
+
|
12
|
+
def as_cypher(payload:, context:)
|
13
|
+
::Kernel.sprintf('%s-[%s]->%s',
|
14
|
+
(@from ? @from.as_cypher(payload: payload, context: context.add(self)) : '()'),
|
15
|
+
[@prefix, *@labels].compact.join(':'),
|
16
|
+
(@to ? @to.as_cypher(payload: payload, context: context.add(self)) : '()'))
|
17
|
+
end
|
18
|
+
|
19
|
+
def from(node = nil)
|
20
|
+
return Field.new(@prefix, 'from') if node == nil
|
21
|
+
Rel.new(@prefix, labels: @labels, from: node, to: @to)
|
22
|
+
end
|
23
|
+
|
24
|
+
def to(node = nil)
|
25
|
+
return Field.new(@prefix, 'to') if node == nil
|
26
|
+
Rel.new(@prefix, labels: @labels, from: @from, to: node)
|
27
|
+
end
|
28
|
+
|
29
|
+
def respond_to_missing?(name, include_private = false)
|
30
|
+
true
|
31
|
+
end
|
32
|
+
|
33
|
+
def method_missing(name, *_)
|
34
|
+
Field.new(@prefix, name)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -24,14 +24,27 @@ describe Cypher do
|
|
24
24
|
cypher_class.new(adapter).execute
|
25
25
|
expect(adapter).to have_received(:execute).with('MATCH (c) RETURN c.name AS name', {})
|
26
26
|
end
|
27
|
+
it 'executes a query with relationships' do
|
28
|
+
c = Node('c')
|
29
|
+
n = Node('n')
|
30
|
+
r = Rel('r', labels: 'TEST')
|
31
|
+
cypher_class = Cypher(Match(r.from(c).to(n)),
|
32
|
+
Return(c.name))
|
33
|
+
cypher_class.new(adapter).execute
|
34
|
+
expect(adapter).to have_received(:execute).with('MATCH (c)-[r:TEST]->(n) RETURN c.name AS name', {})
|
35
|
+
end
|
27
36
|
it 'executes the most complex query possible (exercises everything currently implemented)' do
|
28
37
|
c = Node('c', labels: 'what')
|
29
|
-
|
38
|
+
n = Node('n')
|
39
|
+
r = Rel('r')
|
40
|
+
cypher_class = Cypher(Match(r.from(c).to(n)),
|
30
41
|
Where(And(Eql(c.stuff, Param('thing')),
|
31
42
|
Like(c.staff, 'test%'))),
|
32
|
-
Return(c.name, Alias(c.stuff, 'something'))
|
43
|
+
Return(c.name, Alias(c.stuff, 'something')),
|
44
|
+
OrderBy(c.name, :desc, c.stuff),
|
45
|
+
Limit(10))
|
33
46
|
cypher_class.new(adapter).execute(thing: 'of course')
|
34
|
-
expect(adapter).to have_received(:execute).with('MATCH (c:what) WHERE c.stuff = {thing} AND c.staff LIKE "test%" RETURN c.name AS name, c.stuff AS something', {thing: 'of course'})
|
47
|
+
expect(adapter).to have_received(:execute).with('MATCH (c:what)-[r]->(n) WHERE c.stuff = {thing} AND c.staff LIKE "test%" RETURN c.name AS name, c.stuff AS something ORDER BY c.name desc, c.stuff LIMIT 10', {thing: 'of course'})
|
35
48
|
end
|
36
49
|
context 'with Opt' do
|
37
50
|
before do
|
@@ -8,9 +8,9 @@ describe Node do
|
|
8
8
|
let(:node_multiple_labels) { Node('x', labels: ['uga', 'buga']) }
|
9
9
|
|
10
10
|
it 'converts to be used in "match"' do
|
11
|
-
expect(node.as_cypher).to eq 'x:uga'
|
12
|
-
expect(node_prefix_only.as_cypher).to eq 'x'
|
13
|
-
expect(node_multiple_labels.as_cypher).to eq 'x:uga:buga'
|
11
|
+
expect(node.as_cypher).to eq '(x:uga)'
|
12
|
+
expect(node_prefix_only.as_cypher).to eq '(x)'
|
13
|
+
expect(node_multiple_labels.as_cypher).to eq '(x:uga:buga)'
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe OrderBy do
|
4
|
+
describe '#as_cypher' do
|
5
|
+
let(:payload) { instance_spy(Payload) }
|
6
|
+
let(:context) { instance_spy(Context) }
|
7
|
+
let(:c) { Node('c') }
|
8
|
+
|
9
|
+
it 'formats simple case' do
|
10
|
+
ob = OrderBy(c.something)
|
11
|
+
expect(ob.as_cypher(payload: payload, context: context)).to eq 'ORDER BY c.something'
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'formats multiple elements' do
|
15
|
+
ob = OrderBy(c.something, c.other)
|
16
|
+
expect(ob.as_cypher(payload: payload, context: context)).to eq 'ORDER BY c.something, c.other'
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'formats using :asc/:desc' do
|
20
|
+
ob = OrderBy(c.something, :desc, c.other)
|
21
|
+
expect(ob.as_cypher(payload: payload, context: context)).to eq 'ORDER BY c.something desc, c.other'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Rel do
|
4
|
+
let(:rel) { Rel('x', labels: 'uga') }
|
5
|
+
|
6
|
+
describe '#as_cypher' do
|
7
|
+
let(:payload) { spy(Payload) }
|
8
|
+
let(:context) { spy(Context) }
|
9
|
+
|
10
|
+
it 'converts to be used in "match"' do
|
11
|
+
expect(rel.as_cypher(payload: payload, context: context)).to eq '()-[x:uga]->()'
|
12
|
+
|
13
|
+
c = Node('c')
|
14
|
+
nr = rel.from(c)
|
15
|
+
expect(nr.as_cypher(payload: payload, context: context)).to eq '(c)-[x:uga]->()'
|
16
|
+
|
17
|
+
x = Node('x', labels: 'test')
|
18
|
+
nr = rel.from(c).to(x)
|
19
|
+
expect(nr.as_cypher(payload: payload, context: context)).to eq '(c)-[x:uga]->(x:test)'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe '#respond_to?' do
|
24
|
+
it 'is true for #as_cypher' do
|
25
|
+
expect(rel.respond_to?(:as_cypher)).to be_truthy
|
26
|
+
end
|
27
|
+
it 'is true for any method' do
|
28
|
+
expect(rel.respond_to?(:anything)).to be_truthy
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe 'any method' do
|
33
|
+
it 'responds with a Field' do
|
34
|
+
expect(rel.some_field).to be_instance_of Field
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cypher_builder
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ronie Uliana
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-01-
|
11
|
+
date: 2015-01-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -87,25 +87,30 @@ files:
|
|
87
87
|
- lib/cypher_builder/alias.rb
|
88
88
|
- lib/cypher_builder/and.rb
|
89
89
|
- lib/cypher_builder/as_is.rb
|
90
|
-
- lib/cypher_builder/context.rb
|
91
90
|
- lib/cypher_builder/cypher.rb
|
92
91
|
- lib/cypher_builder/eql.rb
|
93
92
|
- lib/cypher_builder/field.rb
|
93
|
+
- lib/cypher_builder/infra/context.rb
|
94
|
+
- lib/cypher_builder/infra/payload.rb
|
95
|
+
- lib/cypher_builder/infra/resolver.rb
|
96
|
+
- lib/cypher_builder/infra/runner.rb
|
94
97
|
- lib/cypher_builder/like.rb
|
98
|
+
- lib/cypher_builder/limit.rb
|
95
99
|
- lib/cypher_builder/literal.rb
|
96
100
|
- lib/cypher_builder/match.rb
|
97
101
|
- lib/cypher_builder/node.rb
|
98
102
|
- lib/cypher_builder/opt.rb
|
103
|
+
- lib/cypher_builder/order_by.rb
|
99
104
|
- lib/cypher_builder/param.rb
|
100
|
-
- lib/cypher_builder/
|
101
|
-
- lib/cypher_builder/resolver.rb
|
105
|
+
- lib/cypher_builder/rel.rb
|
102
106
|
- lib/cypher_builder/return.rb
|
103
|
-
- lib/cypher_builder/runner.rb
|
104
107
|
- lib/cypher_builder/version.rb
|
105
108
|
- lib/cypher_builder/where.rb
|
106
109
|
- spec/cypher_builder/adapter/neography_spec.rb
|
107
110
|
- spec/cypher_builder/cypher_spec.rb
|
108
111
|
- spec/cypher_builder/node_spec.rb
|
112
|
+
- spec/cypher_builder/order_by_spec.rb
|
113
|
+
- spec/cypher_builder/rel_spec.rb
|
109
114
|
- spec/spec_helper.rb
|
110
115
|
homepage: https://github.com/ruliana/cypher_builder
|
111
116
|
licenses:
|
@@ -135,4 +140,6 @@ test_files:
|
|
135
140
|
- spec/cypher_builder/adapter/neography_spec.rb
|
136
141
|
- spec/cypher_builder/cypher_spec.rb
|
137
142
|
- spec/cypher_builder/node_spec.rb
|
143
|
+
- spec/cypher_builder/order_by_spec.rb
|
144
|
+
- spec/cypher_builder/rel_spec.rb
|
138
145
|
- spec/spec_helper.rb
|