diametric 0.1.2-java → 0.1.3-java
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.
- checksums.yaml +4 -4
- data/Gemfile +3 -3
- data/Jarfile +13 -6
- data/LICENSE.txt +2 -2
- data/README.md +57 -26
- data/Rakefile +1 -0
- data/bin/datomic-rest +1 -1
- data/bin/download-datomic +1 -1
- data/datomic_version.yml +2 -2
- data/diametric-java.gemspec +11 -10
- data/ext/diametric/DiametricCollection.java +45 -38
- data/ext/diametric/DiametricConnection.java +16 -15
- data/ext/diametric/DiametricDatabase.java +9 -8
- data/ext/diametric/DiametricEntity.java +104 -21
- data/ext/diametric/DiametricObject.java +12 -1
- data/ext/diametric/DiametricPeer.java +52 -31
- data/ext/diametric/DiametricService.java +2 -0
- data/ext/diametric/DiametricSet.java +11 -4
- data/ext/diametric/DiametricUUID.java +8 -1
- data/ext/diametric/DiametricUtils.java +90 -62
- data/lib/diametric.rb +1 -0
- data/lib/diametric/associations/collection.rb +103 -0
- data/lib/diametric/entity.rb +166 -103
- data/lib/diametric/persistence/common.rb +0 -44
- data/lib/diametric/persistence/peer.rb +53 -2
- data/lib/diametric/persistence/rest.rb +27 -1
- data/lib/diametric/query.rb +49 -31
- data/lib/diametric/rest_service.rb +8 -9
- data/lib/diametric/service_base.rb +7 -7
- data/lib/diametric/transactor.rb +6 -5
- data/lib/diametric/version.rb +1 -1
- data/lib/diametric_service.jar +0 -0
- data/spec/config/free-transactor-template.properties +6 -6
- data/spec/developer_query_spec.rb +17 -6
- data/spec/diametric/entity_spec.rb +62 -139
- data/spec/diametric/peer_api_spec.rb +23 -23
- data/spec/diametric/persistence/peer_spec.rb +73 -11
- data/spec/diametric/persistence/rest_spec.rb +108 -16
- data/spec/diametric/query_spec.rb +3 -3
- data/spec/diametric/rest_service_spec.rb +4 -4
- data/spec/diametric/schema_spec.rb +526 -0
- data/spec/diametric/transactor_spec.rb +5 -6
- data/spec/integration_spec.rb +7 -7
- data/spec/peer_integration_spec.rb +25 -1
- data/spec/peer_seattle_spec.rb +1 -2
- data/spec/spec_helper.rb +31 -4
- data/spec/support/cardinarity_many_example.rb +37 -0
- data/spec/support/entities.rb +127 -0
- data/spec/support/has_a_example.rb +31 -0
- data/spec/support/has_many_example.rb +79 -0
- data/spec/support/persistence_examples.rb +13 -5
- data/spec/support/various_types_examples.rb +163 -0
- data/spec/test_version_file.yml +2 -2
- metadata +147 -75
@@ -23,22 +23,22 @@ describe "Transactor Service", :transactor =>true do
|
|
23
23
|
end
|
24
24
|
|
25
25
|
it "should return false for version no" do
|
26
|
-
transactor.datomic_conf_file?("
|
26
|
+
transactor.datomic_conf_file?("0.9.4497").should be_false
|
27
27
|
end
|
28
28
|
|
29
29
|
it "should know datomic version specified" do
|
30
|
-
transactor.datomic_version("spec/test_version_file.yml").should == "
|
31
|
-
transactor.datomic_version("
|
30
|
+
transactor.datomic_version("spec/test_version_file.yml").should == ["free", "0.9.4497"]
|
31
|
+
transactor.datomic_version("0.9.4497").should == ["free", "0.9.4497"]
|
32
32
|
end
|
33
33
|
|
34
34
|
it "should know the specified version of datomic has been downloaded" do
|
35
35
|
transactor.downloaded?("spec/test_version_file.yml", "tmp/datomic").should be_false
|
36
|
-
transactor.downloaded?("
|
36
|
+
transactor.downloaded?("0.9.4497", "tmp/datomic").should be_false
|
37
37
|
|
38
38
|
transactor.download("spec/test_version_file.yml", "tmp/datomic")
|
39
39
|
|
40
40
|
transactor.downloaded?("spec/test_version_file.yml", "tmp/datomic").should be_true
|
41
|
-
transactor.downloaded?("
|
41
|
+
transactor.downloaded?("0.9.4497", "tmp/datomic").should be_true
|
42
42
|
end
|
43
43
|
|
44
44
|
context Diametric::Transactor do
|
@@ -64,5 +64,4 @@ describe "Transactor Service", :transactor =>true do
|
|
64
64
|
transactor.stop
|
65
65
|
end
|
66
66
|
end
|
67
|
-
|
68
67
|
end
|
data/spec/integration_spec.rb
CHANGED
@@ -7,10 +7,10 @@ require 'securerandom'
|
|
7
7
|
# bin/rest 9000 test datomic:mem://
|
8
8
|
|
9
9
|
describe Diametric::Entity, :integration => true do
|
10
|
-
before
|
10
|
+
before do
|
11
11
|
@datomic_uri = ENV['DATOMIC_URI'] || 'http://localhost:46291'
|
12
12
|
@storage = ENV['DATOMIC_STORAGE'] || 'free'
|
13
|
-
@dbname = ENV['DATOMIC_NAME'] || "test-#{SecureRandom.uuid}"
|
13
|
+
@dbname = ENV['DATOMIC_NAME'] || "integratin-test-#{SecureRandom.uuid}"
|
14
14
|
@client = Datomic::Client.new @datomic_uri, @storage
|
15
15
|
@client.create_database(@dbname)
|
16
16
|
sleep 0.5
|
@@ -24,8 +24,7 @@ describe Diametric::Entity, :integration => true do
|
|
24
24
|
end
|
25
25
|
|
26
26
|
describe "with a schema" do
|
27
|
-
before
|
28
|
-
@client.transact(@dbname, Person.schema)
|
27
|
+
before do
|
29
28
|
@client.transact(@dbname, Goat.schema)
|
30
29
|
end
|
31
30
|
|
@@ -40,13 +39,14 @@ describe Diametric::Entity, :integration => true do
|
|
40
39
|
end
|
41
40
|
|
42
41
|
describe "with an entity" do
|
43
|
-
before
|
42
|
+
before do
|
43
|
+
@client.transact(@dbname, Goat.schema)
|
44
44
|
goat = Goat.new(:name => "Josef", :birthday => DateTime.parse("1976-09-04"))
|
45
45
|
@client.transact(@dbname, goat.tx_data)
|
46
46
|
end
|
47
47
|
|
48
48
|
it "can query for that entity" do
|
49
|
-
query, args = Diametric::Query.new(Goat).where(:name => "Josef").data
|
49
|
+
query, args = Diametric::Query.new(Goat, nil, true).where(:name => "Josef").data
|
50
50
|
args = args.unshift({:"db/alias" => "#{@storage}/#{@dbname}"})
|
51
51
|
resp = @client.query(query, args)
|
52
52
|
resp.code.should == 200
|
@@ -67,7 +67,7 @@ describe Diametric::Entity, :integration => true do
|
|
67
67
|
end
|
68
68
|
|
69
69
|
describe "with persistence module" do
|
70
|
-
before
|
70
|
+
before do
|
71
71
|
Robin.create_schema
|
72
72
|
end
|
73
73
|
|
@@ -64,7 +64,7 @@ describe Diametric::Entity, :integration => true, :jruby => true do
|
|
64
64
|
Penguin.new(name: "Mary Jen.", birthday: DateTime.parse('1999-12-31'), awesomeness: true).save
|
65
65
|
Penguin.new(name: "Mary Jr.", birthday: DateTime.parse('2013-01-01'), awesomeness: false).save
|
66
66
|
Penguin.new(name: "Mary Jay.", birthday: DateTime.parse('1850-02-22'), awesomeness: false).save
|
67
|
-
query = Penguin.filter(:<, :birthday, DateTime.parse('1900-01-01'))
|
67
|
+
query = Penguin.filter(@conn, :<, :birthday, DateTime.parse('1900-01-01'))
|
68
68
|
result = query.all
|
69
69
|
result.size.should == 2
|
70
70
|
result.collect(&:name).should =~ ["Mary Jay.", "Mary Jo."]
|
@@ -150,6 +150,30 @@ describe Diametric::Entity, :integration => true, :jruby => true do
|
|
150
150
|
account2.deposit.should include(100.0)
|
151
151
|
account2.deposit.should include(200.0)
|
152
152
|
end
|
153
|
+
end
|
154
|
+
|
155
|
+
context 'issue43' do
|
156
|
+
before do
|
157
|
+
@datomic_uri = 'datomic:mem://issue43'
|
158
|
+
@conn_issue43 = Diametric::Persistence.establish_base_connection({:uri => @datomic_uri})
|
159
|
+
This::Bug.create_schema(@conn_issue43).get
|
160
|
+
Outermost::Outer::Inner::Innermost.create_schema(@conn_issue43).get
|
161
|
+
end
|
162
|
+
|
163
|
+
after do
|
164
|
+
@conn_issue43.release
|
165
|
+
end
|
166
|
+
|
167
|
+
it 'should get all entities' do
|
168
|
+
This::Bug.new(id: '123').save
|
169
|
+
result = This::Bug.all
|
170
|
+
result.first.id.should == '123'
|
171
|
+
end
|
153
172
|
|
173
|
+
it 'should get all entities of nested modules' do
|
174
|
+
Outermost::Outer::Inner::Innermost.new(name: 'nested').save
|
175
|
+
result = Outermost::Outer::Inner::Innermost.all
|
176
|
+
result.first.name.should == 'nested'
|
177
|
+
end
|
154
178
|
end
|
155
179
|
end
|
data/spec/peer_seattle_spec.rb
CHANGED
@@ -94,8 +94,7 @@ describe Diametric::Entity, :integration => true, :jruby => true do
|
|
94
94
|
|
95
95
|
result = []
|
96
96
|
neighborhood.parse_tx_data(neighborhood.tx_data, result)
|
97
|
-
result.first["
|
98
|
-
|
97
|
+
result.first[:"neighborhood/district"].to_s.should match(/^\d+/)
|
99
98
|
neighborhood.save(@n_conn2)
|
100
99
|
district.tx_data.should be_empty
|
101
100
|
neighborhood.tx_data.should be_empty
|
data/spec/spec_helper.rb
CHANGED
@@ -28,9 +28,11 @@ RSpec.configure do |c|
|
|
28
28
|
c.treat_symbols_as_metadata_keys_with_true_values = true
|
29
29
|
|
30
30
|
c.before(:suite) do
|
31
|
-
|
32
|
-
|
33
|
-
|
31
|
+
unless ENV['RESTSERVICE']
|
32
|
+
@rest = Diametric::RestService.new("spec/test_version_file.yml", "tmp/datomic")
|
33
|
+
@rest.start(:port => 46291, :db_alias => @storage, :uri => "datomic:mem://")
|
34
|
+
PID = @rest.pid
|
35
|
+
end
|
34
36
|
if ENV['TRANSACTOR']
|
35
37
|
FileUtils.cp(File.join('spec', 'config', 'logback.xml'), File.join('bin', 'logback.xml'))
|
36
38
|
end
|
@@ -38,13 +40,38 @@ RSpec.configure do |c|
|
|
38
40
|
|
39
41
|
c.after(:suite) do
|
40
42
|
Diametric::Persistence::Peer.shutdown(true) if is_jruby?
|
41
|
-
|
43
|
+
unless ENV['RESTSERVICE']
|
44
|
+
Process.kill("HUP", PID)
|
45
|
+
end
|
42
46
|
if ENV['TRANSACTOR']
|
43
47
|
FileUtils.rm(File.join('bin', 'logback.xml'), :force => true)
|
44
48
|
end
|
45
49
|
end
|
46
50
|
end
|
47
51
|
|
52
|
+
RSpec::Matchers.define :be_an_equivalent_hash do |expected|
|
53
|
+
match do |actual|
|
54
|
+
status = true
|
55
|
+
expected.keys.each do |k|
|
56
|
+
next if k == :"db/id"
|
57
|
+
status = false if actual[k].nil?
|
58
|
+
status = false unless actual[k] == expected[k]
|
59
|
+
end
|
60
|
+
status
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
RSpec::Matchers.define :be_an_equivalent_array do |expected|
|
65
|
+
match do |actual|
|
66
|
+
status = true
|
67
|
+
expected.each_with_index do |e, index|
|
68
|
+
next if e.kind_of?(String) && (e.gsub(/ /, "") == "#db/id[:db.part/user]")
|
69
|
+
status = false unless actual[index] == e
|
70
|
+
end
|
71
|
+
status
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
48
75
|
shared_examples "ActiveModel" do |model|
|
49
76
|
require 'test/unit/assertions'
|
50
77
|
require 'active_model/lint'
|
@@ -0,0 +1,37 @@
|
|
1
|
+
shared_examples "supports cardinality many" do
|
2
|
+
describe "entity instance" do
|
3
|
+
let(:model) { model_class.new }
|
4
|
+
|
5
|
+
it "can save" do
|
6
|
+
model.words = ["hopefully", "likely", "possibly"]
|
7
|
+
model.save.should be_true
|
8
|
+
model.should be_persisted
|
9
|
+
|
10
|
+
model.class.all.first.words.should == Set.new(["hopefully", "likely", "possibly"])
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "#assign_attributes" do
|
14
|
+
let(:words) {
|
15
|
+
model.words = ["sadlly", "happily", "joyfully"]
|
16
|
+
model.save
|
17
|
+
model
|
18
|
+
}
|
19
|
+
|
20
|
+
it "updates words" do
|
21
|
+
new_values = { "words" => ["calmly", "peacefully", "joyfully"] }
|
22
|
+
words.update_attributes(new_values)
|
23
|
+
|
24
|
+
words.should_not be_changed
|
25
|
+
words.words.should == Set.new(["calmly", "peacefully", "joyfully"])
|
26
|
+
|
27
|
+
if model_class.ancestors.include? Diametric::Persistence::Peer
|
28
|
+
result = model_class.where({:words => new_values["words"]}, nil, true).first
|
29
|
+
else
|
30
|
+
# not sure, but for some reason, REST likes singular.
|
31
|
+
result = model_class.where({:word => new_values["words"]}).first
|
32
|
+
end
|
33
|
+
result.dbid.should == words.dbid
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/spec/support/entities.rb
CHANGED
@@ -72,6 +72,77 @@ class Mouse
|
|
72
72
|
attribute :age, Integer
|
73
73
|
end
|
74
74
|
|
75
|
+
class ScarletMacaw
|
76
|
+
include Diametric::Entity
|
77
|
+
include Diametric::Persistence::Peer
|
78
|
+
|
79
|
+
attribute :name, String
|
80
|
+
attribute :description, String, :fulltext => true
|
81
|
+
attribute :talkative, Boolean
|
82
|
+
attribute :colors, Integer
|
83
|
+
attribute :average_speed, Float
|
84
|
+
attribute :observed, DateTime
|
85
|
+
attribute :case_no, UUID, :index => true
|
86
|
+
attribute :serial, UUID, :unique => :value
|
87
|
+
end
|
88
|
+
|
89
|
+
class Peacock
|
90
|
+
include Diametric::Entity
|
91
|
+
include Diametric::Persistence::REST
|
92
|
+
|
93
|
+
attribute :name, String
|
94
|
+
attribute :description, String, :fulltext => true
|
95
|
+
attribute :talkative, Boolean
|
96
|
+
attribute :colors, Integer
|
97
|
+
attribute :average_speed, Float
|
98
|
+
attribute :observed, DateTime
|
99
|
+
# REST failes to save UUID
|
100
|
+
#attribute :case_no, UUID, :index => true
|
101
|
+
#attribute :serial, UUID, :unique => :value
|
102
|
+
end
|
103
|
+
|
104
|
+
class MyWords
|
105
|
+
include Diametric::Entity
|
106
|
+
include Diametric::Persistence::Peer
|
107
|
+
|
108
|
+
attribute :words, String, :cardinality => :many
|
109
|
+
end
|
110
|
+
|
111
|
+
class YourWords
|
112
|
+
include Diametric::Entity
|
113
|
+
include Diametric::Persistence::REST
|
114
|
+
|
115
|
+
attribute :words, String, :cardinality => :many
|
116
|
+
end
|
117
|
+
|
118
|
+
class Cage
|
119
|
+
include Diametric::Entity
|
120
|
+
include Diametric::Persistence::Peer
|
121
|
+
|
122
|
+
attribute :pet, Ref
|
123
|
+
end
|
124
|
+
|
125
|
+
class Box
|
126
|
+
include Diametric::Entity
|
127
|
+
include Diametric::Persistence::REST
|
128
|
+
|
129
|
+
attribute :pet, Ref
|
130
|
+
end
|
131
|
+
|
132
|
+
class BigCage
|
133
|
+
include Diametric::Entity
|
134
|
+
include Diametric::Persistence::Peer
|
135
|
+
|
136
|
+
attribute :pets, Ref, :cardinality => :many
|
137
|
+
end
|
138
|
+
|
139
|
+
class BigBox
|
140
|
+
include Diametric::Entity
|
141
|
+
include Diametric::Persistence::REST
|
142
|
+
|
143
|
+
attribute :pets, Ref, :cardinality => :many
|
144
|
+
end
|
145
|
+
|
75
146
|
class Author
|
76
147
|
include Diametric::Entity
|
77
148
|
include Diametric::Persistence::Peer
|
@@ -88,6 +159,38 @@ class Book
|
|
88
159
|
attribute :authors, Ref, :cardinality => :many
|
89
160
|
end
|
90
161
|
|
162
|
+
class Writer
|
163
|
+
include Diametric::Entity
|
164
|
+
include Diametric::Persistence::REST
|
165
|
+
|
166
|
+
attribute :name, String
|
167
|
+
attribute :books, Ref, :cardinality => :many
|
168
|
+
end
|
169
|
+
|
170
|
+
class Article
|
171
|
+
include Diametric::Entity
|
172
|
+
include Diametric::Persistence::REST
|
173
|
+
|
174
|
+
attribute :title, String
|
175
|
+
attribute :authors, Ref, :cardinality => :many
|
176
|
+
end
|
177
|
+
|
178
|
+
class Role
|
179
|
+
include Diametric::Entity
|
180
|
+
include Diametric::Persistence::Peer
|
181
|
+
|
182
|
+
attribute :type, Ref
|
183
|
+
enum :type, [:accountant, :manager, :developer]
|
184
|
+
end
|
185
|
+
|
186
|
+
class Position
|
187
|
+
include Diametric::Entity
|
188
|
+
include Diametric::Persistence::REST
|
189
|
+
|
190
|
+
attribute :type, Ref
|
191
|
+
enum :type, [:accountant, :manager, :developer]
|
192
|
+
end
|
193
|
+
|
91
194
|
class Choice
|
92
195
|
include Diametric::Entity
|
93
196
|
include Diametric::Persistence::Peer
|
@@ -157,3 +260,27 @@ class District
|
|
157
260
|
attribute :region, Ref, :cardinality => :one, :doc => "A district region enum value"
|
158
261
|
enum :region, [:n, :ne, :e, :se, :s, :sw, :w, :nw]
|
159
262
|
end
|
263
|
+
|
264
|
+
# issue 43
|
265
|
+
module This
|
266
|
+
class Bug
|
267
|
+
include Diametric::Entity
|
268
|
+
include Diametric::Persistence::Peer
|
269
|
+
|
270
|
+
attribute :id, String, index: true
|
271
|
+
attribute :name, String
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
module Outermost
|
276
|
+
module Outer
|
277
|
+
module Inner
|
278
|
+
class Innermost
|
279
|
+
include Diametric::Entity
|
280
|
+
include Diametric::Persistence::Peer
|
281
|
+
|
282
|
+
attribute :name, String
|
283
|
+
end
|
284
|
+
end
|
285
|
+
end
|
286
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
shared_examples "supports has_one association" do
|
2
|
+
describe "entity instance" do
|
3
|
+
let(:parent) { parent_class.new }
|
4
|
+
let(:child) { child_class.new }
|
5
|
+
|
6
|
+
it "can save child" do
|
7
|
+
# similar to thing.pet_id = pet.id; pet.save
|
8
|
+
# diametric does pet.save; thing.pet = pet.dbid
|
9
|
+
child.name = "Sophia"
|
10
|
+
child.age = 5
|
11
|
+
parent.pet = child
|
12
|
+
|
13
|
+
child.should be_persisted
|
14
|
+
child.dbid.to_i.should > 0
|
15
|
+
child.class.all.first.name.should == "Sophia"
|
16
|
+
end
|
17
|
+
|
18
|
+
it "can save parent" do
|
19
|
+
child.name = "Jacob"
|
20
|
+
child.age = 3
|
21
|
+
parent.pet = child
|
22
|
+
parent.save
|
23
|
+
|
24
|
+
parent.should be_persisted
|
25
|
+
parent.dbid.to_i.should > 0
|
26
|
+
searched_child = parent.class.all.first.pet
|
27
|
+
searched_child.name.should == "Jacob"
|
28
|
+
searched_child.age.should == 3
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
shared_examples "supporting has_many association" do
|
2
|
+
describe "entity instance" do
|
3
|
+
let(:parent) { parent_class.new }
|
4
|
+
let(:child) { child_class.new }
|
5
|
+
|
6
|
+
it "can save child" do
|
7
|
+
child.name = "Emma"
|
8
|
+
child.age = 15
|
9
|
+
parent.pets << child
|
10
|
+
|
11
|
+
child.should be_persisted
|
12
|
+
child.dbid.to_i.should > 0
|
13
|
+
end
|
14
|
+
|
15
|
+
it "can save parent" do
|
16
|
+
child.name = "Ethan"
|
17
|
+
child.age = 14
|
18
|
+
parent.pets << child
|
19
|
+
parent.save
|
20
|
+
|
21
|
+
parent.should be_persisted
|
22
|
+
parent.dbid.to_i.should > 0
|
23
|
+
searched_children = parent.class.first.pets
|
24
|
+
searched_children.collect(&:name).should include "Ethan"
|
25
|
+
searched_children.collect(&:age).should include 14
|
26
|
+
end
|
27
|
+
|
28
|
+
it "can find children" do
|
29
|
+
child1 = child_class.new(name: "Michael", age: 10)
|
30
|
+
parent.pets << child1
|
31
|
+
child2 = child_class.new(name: "Mia", age: 9)
|
32
|
+
parent.pets << child2
|
33
|
+
parent.save
|
34
|
+
|
35
|
+
searched_parent = parent.class.first
|
36
|
+
searched_parent.pets.size.should == 2
|
37
|
+
searched_parent.pets.collect(&:name).should =~ ["Michael", "Mia"]
|
38
|
+
searched_parent.pets.collect(&:age).should =~ [10, 9]
|
39
|
+
searched_parent.pets.empty?.should == false
|
40
|
+
end
|
41
|
+
|
42
|
+
it "can destory child" do
|
43
|
+
child1 = child_class.new(name: "Alexander", age: 5)
|
44
|
+
child2 = child_class.new(name: "Abigail", age: 6)
|
45
|
+
parent.pets = [child1, child2]
|
46
|
+
parent.save
|
47
|
+
|
48
|
+
searched_parent = parent.class.first
|
49
|
+
searched_parent.pets.size.should == 2
|
50
|
+
|
51
|
+
searched_parent.pets.destroy(child1)
|
52
|
+
searched_parent.pets.size.should == 1
|
53
|
+
searched_parent.pets.collect(&:name).should == ["Abigail"]
|
54
|
+
searched_parent.pets.collect(&:age).should == [6]
|
55
|
+
|
56
|
+
searched_children = child_class.all
|
57
|
+
searched_children.size.should == 1
|
58
|
+
searched_children.first.dbid.should == child2.dbid
|
59
|
+
end
|
60
|
+
|
61
|
+
it "can delete child" do
|
62
|
+
child1 = child_class.new(name: "Joseph", age: 1)
|
63
|
+
child2 = child_class.new(name: "Janet", age: 2)
|
64
|
+
parent.pets = [child1, child2]
|
65
|
+
parent.save
|
66
|
+
|
67
|
+
searched_parent = parent.class.first
|
68
|
+
searched_parent.pets.size.should == 2
|
69
|
+
|
70
|
+
searched_parent.pets.delete(child1, child2)
|
71
|
+
searched_parent.pets.size.should == 0
|
72
|
+
|
73
|
+
searched_children = child_class.all
|
74
|
+
searched_children.size.should == 2
|
75
|
+
searched_children.collect(&:name).should =~ ["Joseph", "Janet"]
|
76
|
+
searched_children.collect(&:age).should =~ [1, 2]
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|