architect4r 0.3.2 → 0.3.3.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +4 -4
- data/Guardfile +1 -1
- data/README.md +13 -1
- data/ReleaseNotes.md +11 -0
- data/lib/architect4r/core/cypher_methods.rb +18 -0
- data/lib/architect4r/model/properties.rb +9 -4
- data/lib/architect4r/version.rb +1 -1
- data/spec/core/cypher_methods_spec.rb +41 -0
- data/spec/model/properties_spec.rb +35 -0
- data/spec/spec_helper.rb +1 -0
- metadata +4 -3
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
architect4r (0.3.
|
4
|
+
architect4r (0.3.3.1)
|
5
5
|
activemodel (~> 3.0)
|
6
6
|
json (~> 1.5)
|
7
7
|
typhoeus (~> 0.2)
|
@@ -18,15 +18,15 @@ GEM
|
|
18
18
|
builder (3.0.0)
|
19
19
|
diff-lcs (1.1.3)
|
20
20
|
growl (1.0.3)
|
21
|
-
guard (0.8.
|
21
|
+
guard (0.8.8)
|
22
22
|
thor (~> 0.14.6)
|
23
23
|
guard-rspec (0.5.0)
|
24
24
|
guard (>= 0.8.4)
|
25
25
|
i18n (0.6.0)
|
26
26
|
json (1.6.1)
|
27
|
-
mime-types (1.17.
|
27
|
+
mime-types (1.17.2)
|
28
28
|
multi_json (1.0.3)
|
29
|
-
rake (0.9.2)
|
29
|
+
rake (0.9.2.2)
|
30
30
|
rb-fsevent (0.4.3.1)
|
31
31
|
rspec (2.7.0)
|
32
32
|
rspec-core (~> 2.7.0)
|
data/Guardfile
CHANGED
data/README.md
CHANGED
@@ -3,7 +3,18 @@
|
|
3
3
|
Architect4r is intended as an easy ruby wrapper for the neo4j graph db
|
4
4
|
REST API. There are other solutions such as neo4j.rb if you are working
|
5
5
|
in a java environment or neography which provides another working wrapper
|
6
|
-
for the REST API.
|
6
|
+
for the REST API. Both solutions are far more feature complete and allow
|
7
|
+
you to do pretty advanced queries on the graph.
|
8
|
+
|
9
|
+
Architect4r is trying to go another route. Instead of using the native
|
10
|
+
graph traversal engine it requires you to write your queries in recently
|
11
|
+
implemented cypher query language. The language is well documented at the
|
12
|
+
official neo4j documentation (http://docs.neo4j.org/chunked/milestone/).
|
13
|
+
Just that you know what you are dealing with… a little example:
|
14
|
+
|
15
|
+
start s=node(1) match s-[:friends]-d return d order by d.name skip 0 limit 20
|
16
|
+
|
17
|
+
But please read the docs for more info.
|
7
18
|
|
8
19
|
Requirements
|
9
20
|
------------
|
@@ -25,6 +36,7 @@ Quick Start
|
|
25
36
|
# Properties
|
26
37
|
property :name, :cast_to => String, :localize => true
|
27
38
|
property :name, :cast_to => String, :localize => :de
|
39
|
+
timestamps!
|
28
40
|
|
29
41
|
# Validations
|
30
42
|
validates :name, :presence => true
|
data/ReleaseNotes.md
CHANGED
@@ -1,5 +1,16 @@
|
|
1
1
|
# Release Notes
|
2
2
|
|
3
|
+
## v0.3.3
|
4
|
+
|
5
|
+
* Add magic timestamp! property for tracking timestamps
|
6
|
+
|
7
|
+
By putting timestamps! into your model, it tracks the creation date and
|
8
|
+
time in created\_at and updates in updated\_at
|
9
|
+
|
10
|
+
* Allow referencing model_roots in cypher queries.
|
11
|
+
|
12
|
+
If you have a model User the reference key would be :user_root
|
13
|
+
|
3
14
|
## v0.3.2
|
4
15
|
|
5
16
|
* Support for carrierwave file upload mechanism
|
@@ -6,6 +6,9 @@ module Architect4r
|
|
6
6
|
module InstanceMethods
|
7
7
|
|
8
8
|
def execute_cypher(query)
|
9
|
+
|
10
|
+
query = self.interpolate_node_model_root_references(query)
|
11
|
+
|
9
12
|
url = prepend_base_url("/ext/CypherPlugin/graphdb/execute_query")
|
10
13
|
response = Typhoeus::Request.post(url,
|
11
14
|
:headers => { 'Accept' => 'application/json', 'Content-Type' => 'application/json' },
|
@@ -41,6 +44,21 @@ module Architect4r
|
|
41
44
|
end
|
42
45
|
end
|
43
46
|
|
47
|
+
def interpolate_node_model_root_references(query)
|
48
|
+
query.scan(/node\((:[^)]*_root)\)/i).flatten.uniq.each do |str|
|
49
|
+
model_name = str.match(/^:(.*)_root$/)[1].to_s.classify
|
50
|
+
if model_name.length > 0
|
51
|
+
# As const_defined? and const_get to not support namespaces, we have to use eval :(
|
52
|
+
begin
|
53
|
+
query.gsub!(str, eval("#{model_name}.model_root.id.to_s"))
|
54
|
+
rescue NoMethodError => ex
|
55
|
+
nil
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
query
|
60
|
+
end
|
61
|
+
|
44
62
|
end
|
45
63
|
end
|
46
64
|
end
|
@@ -54,6 +54,8 @@ module Architect4r
|
|
54
54
|
value.to_i
|
55
55
|
elsif cast_to == Float
|
56
56
|
value.to_f
|
57
|
+
elsif cast_to == DateTime
|
58
|
+
value.to_datetime
|
57
59
|
elsif cast_to == TrueClass or cast_to == FalseClass
|
58
60
|
if value.kind_of?(Integer)
|
59
61
|
value == 1
|
@@ -90,12 +92,15 @@ module Architect4r
|
|
90
92
|
end
|
91
93
|
|
92
94
|
def timestamps!
|
93
|
-
property(:updated_at, :cast_to =>
|
94
|
-
property(:created_at, :cast_to =>
|
95
|
+
property(:updated_at, :cast_to => DateTime)
|
96
|
+
property(:created_at, :cast_to => DateTime)
|
97
|
+
|
98
|
+
set_callback :create, :before do |object|
|
99
|
+
write_attribute('created_at', DateTime.now)
|
100
|
+
end
|
95
101
|
|
96
102
|
set_callback :save, :before do |object|
|
97
|
-
write_attribute('updated_at',
|
98
|
-
write_attribute('created_at', Time.now) if object.new?
|
103
|
+
write_attribute('updated_at', DateTime.now)
|
99
104
|
end
|
100
105
|
end
|
101
106
|
|
data/lib/architect4r/version.rb
CHANGED
@@ -26,4 +26,45 @@ describe Architect4r::Server do
|
|
26
26
|
|
27
27
|
end
|
28
28
|
|
29
|
+
describe :interpolate_node_model_root_references do
|
30
|
+
|
31
|
+
it "should return the original query if there is nothing to interpolate" do
|
32
|
+
result = subject.interpolate_node_model_root_references("start node(0) match something")
|
33
|
+
result.should == "start node(0) match something"
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should find and replace a single reference" do
|
37
|
+
Person.should_receive(:model_root).and_return(stub(:id => 1))
|
38
|
+
result = subject.interpolate_node_model_root_references("start node(:person_root) match something")
|
39
|
+
result.should == "start node(1) match something"
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should find and replace multiple references" do
|
43
|
+
Person.should_receive(:model_root).and_return(stub(:id => 1))
|
44
|
+
Ship.should_receive(:model_root).and_return(stub(:id => 2))
|
45
|
+
result = subject.interpolate_node_model_root_references("start p=node(:person_root), s=node(:ship_root) match something")
|
46
|
+
result.should == "start p=node(1), s=node(2) match something"
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should find and replace multiple references to the same root" do
|
50
|
+
Person.should_receive(:model_root).and_return(stub(:id => 1))
|
51
|
+
result = subject.interpolate_node_model_root_references("start p=node(:person_root), s=node(:person_root) match something")
|
52
|
+
result.should == "start p=node(1), s=node(1) match something"
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should support namespaced models" do
|
56
|
+
module MyNamespace; class UserNode; end; end
|
57
|
+
MyNamespace::UserNode.should_receive(:model_root).and_return(stub(:id => 11))
|
58
|
+
result = subject.interpolate_node_model_root_references("start s=node(:my_namespace/user_node_root) match something")
|
59
|
+
result.should == "start s=node(11) match something"
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should support camel case models" do
|
63
|
+
SomeDatabaseModelNode.should_receive(:model_root).and_return(stub(:id => 12))
|
64
|
+
result = subject.interpolate_node_model_root_references("start s=node(:some_database_model_node_root) match something")
|
65
|
+
result.should == "start s=node(12) match something"
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
29
70
|
end
|
@@ -162,4 +162,39 @@ describe "Model properties based on test class Person" do
|
|
162
162
|
|
163
163
|
end
|
164
164
|
|
165
|
+
describe "automatic tracking of create and update timestamps" do
|
166
|
+
|
167
|
+
subject { Person.new(:name => 'Person with timestamps', :human => false) }
|
168
|
+
|
169
|
+
it "should allow setting timestamps" do
|
170
|
+
subject.should respond_to(:created_at)
|
171
|
+
subject.should respond_to(:updated_at)
|
172
|
+
end
|
173
|
+
|
174
|
+
it "should create the timestamps only after creation" do
|
175
|
+
subject.created_at.should be_nil
|
176
|
+
subject.updated_at.should be_nil
|
177
|
+
subject.save
|
178
|
+
subject.created_at.should be_a(DateTime)
|
179
|
+
subject.updated_at.should be_a(DateTime)
|
180
|
+
end
|
181
|
+
|
182
|
+
it "should keep the created_at timestamp untouched after creation" do
|
183
|
+
subject.save
|
184
|
+
the_stamp = subject.created_at
|
185
|
+
subject.vita = "Some random info"
|
186
|
+
subject.save
|
187
|
+
subject.created_at.should == the_stamp
|
188
|
+
end
|
189
|
+
|
190
|
+
it "should update the updated_at timestamp" do
|
191
|
+
subject.save
|
192
|
+
the_stamp = subject.updated_at
|
193
|
+
subject.vita = "Some random info"
|
194
|
+
subject.save
|
195
|
+
subject.updated_at.should > the_stamp
|
196
|
+
end
|
197
|
+
|
198
|
+
end
|
199
|
+
|
165
200
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -41,6 +41,7 @@ class Person < Architect4r::Model::Node
|
|
41
41
|
property :birthday, :cast_to => Date
|
42
42
|
property :age_when_enlightend, :cast_to => Integer
|
43
43
|
property :note, :cast_to => String, :localize => true
|
44
|
+
timestamps!
|
44
45
|
|
45
46
|
# Validations
|
46
47
|
validates :name, :presence => true, :length => { :minimum => 3, :allow_nil => true }
|
metadata
CHANGED
@@ -1,13 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: architect4r
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 89
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 3
|
9
|
-
-
|
10
|
-
|
9
|
+
- 3
|
10
|
+
- 1
|
11
|
+
version: 0.3.3.1
|
11
12
|
platform: ruby
|
12
13
|
authors:
|
13
14
|
- Maximilian Schulz
|