diametric 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -9,7 +9,7 @@ describe Diametric::Entity do
9
9
  it { should respond_to(:from_query) }
10
10
 
11
11
  it "should generate a schema" do
12
- Person.schema.should == [
12
+ expected = [
13
13
  { :"db/id" => Person.send(:tempid, :"db.part/db"),
14
14
  :"db/ident" => :"person/name",
15
15
  :"db/valueType" => :"db.type/string",
@@ -49,8 +49,27 @@ describe Diametric::Entity do
49
49
  :"db/valueType" => :"db.type/string",
50
50
  :"db/cardinality" => :"db.cardinality/one",
51
51
  :"db/fulltext" => true,
52
+ :"db.install/_attribute" => :"db.part/db" },
53
+ { :"db/id" => Person.send(:tempid, :"db.part/db"),
54
+ :"db/ident" => :"person/middle_name",
55
+ :"db/valueType" => :"db.type/string",
56
+ :"db/cardinality" => :"db.cardinality/one",
57
+ :"db.install/_attribute" => :"db.part/db" },
58
+ { :"db/id" => Person.send(:tempid, :"db.part/db"),
59
+ :"db/ident" => :"person/nicknames",
60
+ :"db/valueType" => :"db.type/string",
61
+ :"db/cardinality" => :"db.cardinality/many",
62
+ :"db.install/_attribute" => :"db.part/db" },
63
+ { :"db/id" => Person.send(:tempid, :"db.part/db"),
64
+ :"db/ident" => :"person/parent",
65
+ :"db/valueType" => :"db.type/ref",
66
+ :"db/cardinality" => :"db.cardinality/many",
67
+ :"db/doc" => "A person's parent",
52
68
  :"db.install/_attribute" => :"db.part/db" }
53
69
  ]
70
+ Person.schema.each do |s|
71
+ s.should == expected.shift
72
+ end
54
73
  end
55
74
  end
56
75
 
@@ -67,6 +86,7 @@ describe Diametric::Entity do
67
86
  subject.name = "Clinton"
68
87
  subject.name.should == "Clinton"
69
88
  end
89
+
70
90
  end
71
91
 
72
92
  describe ".new" do
@@ -79,6 +99,14 @@ describe Diametric::Entity do
79
99
  person.name.should == "Dashiell D"
80
100
  person.secret_name.should == "Monito"
81
101
  end
102
+
103
+ it "should defaults attributes" do
104
+ Person.new.middle_name.should == "Danger"
105
+ end
106
+
107
+ it "should transform default arrays into sets" do
108
+ Person.new.nicknames.should == Set.new(["Buddy", "Pal"])
109
+ end
82
110
  end
83
111
 
84
112
  describe ".from_query" do
@@ -91,38 +119,79 @@ describe Diametric::Entity do
91
119
  end
92
120
 
93
121
  describe "#tx_data" do
94
- let(:goat) { Goat.new(:name => "Beans", :birthday => Date.parse("2002-04-15"))}
95
-
96
- describe "without a dbid" do
97
- it "should generate a transaction with a new tempid" do
98
- # Equivalence is currently wrong on EDN tagged values.
99
- tx = goat.tx_data.first
100
- tx.keys.should == [:"db/id", :"goat/name", :"goat/birthday"]
101
- tx[:"db/id"].to_edn.should match(%r"#db/id \[:db.part/user \-\d+\]")
102
- tx[:"goat/name"].should == "Beans"
103
- tx[:"goat/birthday"].should == goat.birthday
122
+ context "for an entity with cardinality/many attributes" do
123
+
124
+ let(:entity_class) do
125
+ gen_entity_class(named = "test") do
126
+ attribute :many, String, :cardinality => :many
127
+ end
128
+ end
129
+
130
+ describe "with a dbid" do
131
+ it "should generate a protraction tx for added entries" do
132
+ entity = entity_class.new(:many => %w|foo bar|)
133
+ entity.many.should == Set["foo", "bar"]
134
+ entity.dbid = 1
135
+ entity.tx_data.should == [[:"db/add", 1, :"test/many", ["foo", "bar"]]]
136
+ end
137
+
138
+ it "should generate a retraction tx for removed entries" do
139
+ entity = entity_class.new
140
+ entity.dbid = 1
141
+ entity.instance_variable_set(:"@changed_attributes", { 'many' => Set["original", "unchanged"]})
142
+ entity.many = Set["unchanged", "new"]
143
+ entity.tx_data.should == [
144
+ [:"db/retract", 1, :"test/many", ["original"]],
145
+ [:"db/add", 1, :"test/many", ["new"]]
146
+ ]
147
+ end
148
+ end
149
+
150
+ describe "without a db/id" do
151
+ it "should generate a protraction tx" do
152
+ entity = entity_class.new(:many => %w|foo bar|)
153
+ tx = entity.tx_data.first
154
+ tx.should =~ [:"db/add", entity.send(:tempid), :"test/many", ['foo', 'bar']]
155
+ end
104
156
  end
105
157
  end
106
158
 
107
- describe "with a dbid" do
108
- it "should generate a transaction with the dbid" do
109
- goat.dbid = 1
110
- goat.tx_data.should == [
111
- { :"db/id" => 1,
112
- :"goat/name" => "Beans",
113
- :"goat/birthday" => goat.birthday
114
- }
115
- ]
159
+ context "for an entity with only cardinality/one attributes" do
160
+ let(:goat) { Goat.new(:name => "Beans", :birthday => Date.parse("2002-04-15"))}
161
+
162
+ describe "without a dbid" do
163
+ it "should generate a transaction with a new tempid" do
164
+ # Equivalence is currently wrong on EDN tagged values.
165
+ tx = goat.tx_data.first
166
+ tx.keys.should =~ [:"db/id", :"goat/name", :"goat/birthday"]
167
+ tx[:"db/id"].to_edn.should match(%r"#db/id \[:db.part/user \-\d+\]")
168
+ tx[:"goat/name"].should == "Beans"
169
+ tx[:"goat/birthday"].should == goat.birthday
170
+ end
116
171
  end
117
172
 
118
- it "should generate a transaction with only specified attributes" do
119
- goat.dbid = 1
120
- goat.tx_data(:name).should == [
121
- { :"db/id" => 1,
122
- :"goat/name" => "Beans"
123
- }
124
- ]
173
+ describe "with a dbid" do
174
+ it "should generate a transaction with the dbid" do
175
+ goat.dbid = 1
176
+ goat.tx_data.should == [
177
+ { :"db/id" => 1,
178
+ :"goat/name" => "Beans",
179
+ :"goat/birthday" => goat.birthday
180
+ }
181
+ ]
182
+ end
183
+
184
+ it "should generate a transaction with only specified attributes" do
185
+ goat.dbid = 1
186
+ goat.tx_data(:name).should == [
187
+ { :"db/id" => 1,
188
+ :"goat/name" => "Beans"
189
+ }
190
+ ]
191
+ end
125
192
  end
193
+
126
194
  end
195
+
127
196
  end
128
197
  end
@@ -21,7 +21,7 @@ describe Diametric::Persistence::Peer, :jruby do
21
21
  let(:db_uri) { 'datomic:mem://hello' }
22
22
 
23
23
  it "can connect to a Datomic database" do
24
- subject.connect(db_uri)
24
+ subject.connect(:uri => db_uri)
25
25
  subject.connection.should be_a(Java::DatomicPeer::LocalConnection)
26
26
  end
27
27
 
@@ -29,7 +29,7 @@ describe Diametric::Persistence::Peer, :jruby do
29
29
  let(:model_class) { Rat }
30
30
 
31
31
  before(:all) do
32
- subject.connect(db_uri)
32
+ subject.connect(:uri => db_uri)
33
33
  Diametric::Persistence::Peer.create_schemas
34
34
  end
35
35
  end
@@ -10,12 +10,19 @@ describe Diametric::Persistence::REST, :integration do
10
10
  attribute :age, Integer
11
11
  end
12
12
 
13
+ let(:connection_options) do
14
+ {
15
+ :uri => db_uri,
16
+ :storage => storage,
17
+ :database => dbname
18
+ }
19
+ end
13
20
  let(:db_uri) { ENV['DATOMIC_URI'] || 'http://localhost:9000' }
14
- let(:storage) { ENV['DATOMIC_STORAGE'] || 'test' }
21
+ let(:storage) { ENV['DATOMIC_STORAGE'] || 'free' }
15
22
  let(:dbname) { ENV['DATOMIC_NAME'] || "test-#{Time.now.to_i}" }
16
23
 
17
24
  it "can connect to a Datomic database" do
18
- subject.connect(db_uri, storage, dbname)
25
+ subject.connect(connection_options)
19
26
  subject.connection.should be_a(Datomic::Client)
20
27
  end
21
28
 
@@ -23,7 +30,7 @@ describe Diametric::Persistence::REST, :integration do
23
30
  let(:model_class) { Mouse }
24
31
 
25
32
  before(:all) do
26
- subject.connect(db_uri, storage, dbname)
33
+ subject.connect(connection_options)
27
34
  Diametric::Persistence::REST.create_schemas
28
35
  end
29
36
  end
@@ -0,0 +1,59 @@
1
+ require 'spec_helper'
2
+
3
+ # Prevent CRuby from blowing up
4
+ module Diametric
5
+ module Persistence
6
+ module Peer
7
+ end
8
+ end
9
+ end
10
+
11
+ describe Diametric::Persistence do
12
+ let(:settings) { { :uri => 'http://example.com:9000' } }
13
+ let(:rest_class) { Diametric::Persistence::REST }
14
+
15
+ describe ".establish_base_connection" do
16
+ before { Diametric::Persistence.stub(:persistence_class => rest_class) }
17
+
18
+ it "connects" do
19
+ settings = { :uri => 'http://example.com:9000' }
20
+ rest_class.should_receive(:connect).with(settings)
21
+
22
+ Diametric::Persistence.establish_base_connection(settings)
23
+ end
24
+
25
+ it "records the base persistence class" do
26
+ rest_class.stub(:connect)
27
+ Diametric::Persistence.establish_base_connection(settings)
28
+ Diametric::Persistence.instance_variable_get(:"@_persistence_class").should == rest_class
29
+ end
30
+ end
31
+
32
+ describe ".included" do
33
+ before { Diametric::Persistence.stub(:persistence_class => rest_class) }
34
+
35
+ it "includes the recorded base persistence class" do
36
+ class FooEntity; end
37
+ FooEntity.should_receive(:send).with(:include, rest_class)
38
+ Diametric::Persistence.instance_variable_set(:"@_persistence_class", rest_class)
39
+
40
+ class FooEntity
41
+ include Diametric::Persistence
42
+ end
43
+ end
44
+ end
45
+
46
+ describe ".persistence_class" do
47
+ it "returns REST for REST-like options" do
48
+ klass = Diametric::Persistence.persistence_class("http://localhost:9000")
49
+ klass.should be Diametric::Persistence::REST
50
+ Diametric::Persistence.rest?.should == true
51
+ end
52
+
53
+ it "returns Peer for Peer-like options", :jruby do
54
+ klass = Diametric::Persistence.persistence_class("datomic:free://localhost:9000/sample")
55
+ klass.should be Diametric::Persistence::Peer
56
+ Diametric::Persistence.peer?.should == true
57
+ end
58
+ end
59
+ end
@@ -8,6 +8,8 @@ describe Diametric::Query do
8
8
  query.where(:age => 2)
9
9
  query.conditions.should be_empty
10
10
  end
11
+
12
+ it "raises when non-searchable conditions (id?) are passed"
11
13
  end
12
14
 
13
15
  describe "#filter" do
@@ -17,6 +19,60 @@ describe Diametric::Query do
17
19
  end
18
20
  end
19
21
 
22
+ describe "#each" do
23
+ it "collapses cardinality/many attribute results" do
24
+ model = gen_entity_class :person do
25
+ attribute :name, String
26
+ attribute :likes, String, :cardinality => :many
27
+ end
28
+ model.stub(:q => [[1, "Stu", "chocolate"], [1, "Stu", "vanilla"]])
29
+
30
+ model.should_receive(:from_query).with([1, "Stu", ["chocolate", "vanilla"]])
31
+ Diametric::Query.new(model).each {|x| x}
32
+ end
33
+ end
34
+
35
+ describe "#collapse_results" do
36
+ let (:model) do
37
+ gen_entity_class do
38
+ attribute :name, String
39
+ attribute :likes, String, :cardinality => :many
40
+ end
41
+ end
42
+ let(:query) { Diametric::Query.new(model) }
43
+
44
+ context "with multiple results per entity" do
45
+ it "collapses cardinality/many attributes into lists" do
46
+ results = [[1, "Stu", "chocolate"], [1, "Stu", "vanilla"], [1, "Stu", "raspberry"]]
47
+ collapsed = query.send(:collapse_results, results).first
48
+ collapsed.should == [1, "Stu", ["chocolate", "vanilla", "raspberry"]]
49
+ end
50
+ end
51
+
52
+ context "with single result per entity" do
53
+ it "collapses cardinality/many attributes into lists" do
54
+ results = [[1, "Stu", "chocolate"]]
55
+ collapsed = query.send(:collapse_results, results).first
56
+ collapsed.should == [1, "Stu", ["chocolate"]]
57
+ end
58
+ end
59
+ end
60
+
61
+ describe "#all" do
62
+ it "returns set for values of cardinality/many" do
63
+ model = gen_entity_class :person do
64
+ attribute :name, String
65
+ attribute :likes, String, :cardinality => :many
66
+ end
67
+ model.stub(:q => [[1, "Stu", "chocolate"], [1, "Stu", "vanilla"]])
68
+ Diametric::Query.new(model).all.each do |e|
69
+ e.name.should == "Stu"
70
+ e.likes.class.should == Set
71
+ e.likes.should include "chocolate"
72
+ e.likes.should include "vanilla"
73
+ end
74
+ end
75
+ end
20
76
 
21
77
  describe "#data" do
22
78
  it "should generate a query given no conditions or filters" do
@@ -7,7 +7,7 @@ require 'datomic/client'
7
7
  describe Diametric::Entity, :integration => true do
8
8
  before(:all) do
9
9
  @datomic_uri = ENV['DATOMIC_URI'] || 'http://localhost:9000'
10
- @storage = ENV['DATOMIC_STORAGE'] || 'test'
10
+ @storage = ENV['DATOMIC_STORAGE'] || 'free'
11
11
  @dbname = ENV['DATOMIC_NAME'] || "test-#{Time.now.to_i}"
12
12
  @client = Datomic::Client.new @datomic_uri, @storage
13
13
  @client.create_database(@dbname)
@@ -64,4 +64,32 @@ describe Diametric::Entity, :integration => true do
64
64
  end
65
65
  end
66
66
 
67
+ describe "with persistence module" do
68
+ before(:all) do
69
+ Robin.create_schema
70
+ end
71
+
72
+ let(:query) { Diametric::Query.new(Robin) }
73
+ it "can update entity" do
74
+ robin = Robin.new(:name => "Mary", :age => 2)
75
+ robin.save
76
+ robin.update(:age => 3)
77
+ robin.name.should == "Mary"
78
+ robin.age.should == 3
79
+ end
80
+ it "should search upadated attributes" do
81
+ robin = query.where(:name => "Mary").first
82
+ robin.name.should == "Mary"
83
+ robin.age.should == 3
84
+ end
85
+ it "can destroy entity" do
86
+ robin = Robin.new(:name => "Mary", :age => 2)
87
+ robin.save
88
+ number_of_robins = Robin.all.size
89
+ number_of_robins.should >= 1
90
+ robin.destroy
91
+ Robin.all.size.should == (number_of_robins -1)
92
+ end
93
+ end
94
+
67
95
  end
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+ require 'datomic/client'
3
+
4
+ # Datomic's `rest` needs to run for these tests to pass:
5
+ # bin/rest 9000 test datomic:mem://
6
+
7
+ describe Diametric::Entity, :integration => true, :jruby => true do
8
+ before(:all) do
9
+ @datomic_uri = ENV['DATOMIC_URI'] || 'datomic:mem://animals'
10
+ Diametric::Persistence.establish_base_connection({:uri => @datomic_uri})
11
+ Penguin.create_schema
12
+ end
13
+
14
+ let(:query) { Diametric::Query.new(Penguin) }
15
+ it "should update entity" do
16
+ penguin = Penguin.new(:name => "Mary", :age => 2)
17
+ penguin.save
18
+ penguin.update(:age => 3)
19
+ penguin.name.should == "Mary"
20
+ penguin.age.should == 3
21
+ end
22
+
23
+ it "should search upadated attributes" do
24
+ penguin = query.where(:name => "Mary").first
25
+ penguin.name.should == "Mary"
26
+ penguin.age.should == 3
27
+ end
28
+
29
+ it "should destroy entity" do
30
+ penguin = Penguin.new(:name => "Mary", :age => 2)
31
+ penguin.save
32
+ number_of_penguins = Penguin.all.size
33
+ number_of_penguins.should >= 1
34
+ penguin.destroy
35
+ Penguin.all.size.should == (number_of_penguins -1)
36
+ end
37
+ end
@@ -43,6 +43,9 @@ class Person
43
43
  attribute :ssn, String, :unique => :value
44
44
  attribute :secret_name, String, :unique => :identity
45
45
  attribute :bio, String, :fulltext => true
46
+ attribute :middle_name, String, :default => "Danger"
47
+ attribute :nicknames, String, :cardinality => :many, :default => ["Buddy", "Pal"]
48
+ attribute :parent, Ref, :cardinality => :many, :doc => "A person's parent"
46
49
  end
47
50
 
48
51
  class Goat
@@ -51,3 +54,23 @@ class Goat
51
54
  attribute :name, String
52
55
  attribute :birthday, DateTime
53
56
  end
57
+
58
+ require 'diametric/persistence/rest'
59
+ class Robin
60
+ include Diametric::Entity
61
+ include Diametric::Persistence::REST
62
+
63
+ attribute :name, String
64
+ attribute :age, Integer
65
+ end
66
+
67
+ if RUBY_ENGINE == "jruby"
68
+ require 'diametric/persistence/peer'
69
+ class Penguin
70
+ include Diametric::Entity
71
+ include Diametric::Persistence::Peer
72
+
73
+ attribute :name, String
74
+ attribute :age, Integer
75
+ end
76
+ end