architect4r 0.3.2 → 0.3.3.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.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- architect4r (0.3.2)
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.7)
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.1)
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
@@ -1,4 +1,4 @@
1
- guard 'rspec' do
1
+ guard 'rspec', :all_after_pass => false, :version => 2 do
2
2
  # Check for changes in classes
3
3
  watch(%r{^lib/architect4r/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
4
4
 
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 => Time)
94
- property(:created_at, :cast_to => Time)
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', Time.now)
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
 
@@ -1,3 +1,3 @@
1
1
  module Architect4r
2
- VERSION = "0.3.2"
2
+ VERSION = "0.3.3.1"
3
3
  end
@@ -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: 23
4
+ hash: 89
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 3
9
- - 2
10
- version: 0.3.2
9
+ - 3
10
+ - 1
11
+ version: 0.3.3.1
11
12
  platform: ruby
12
13
  authors:
13
14
  - Maximilian Schulz