diametric 0.0.1 → 0.0.2

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.
@@ -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