spec/lib/zermelo/associations/multiple_spec.rb in zermelo-1.2.1 vs spec/lib/zermelo/associations/multiple_spec.rb in zermelo-1.3.0
- old
+ new
@@ -18,27 +18,27 @@
child = child_class.new(:id => '3', :important => true)
expect(child.save).to be_truthy
children = parent.children.all
- expect(children).to be_an(Array)
+ expect(children).to be_a(Set)
expect(children).to be_empty
parent.children << child
children = parent.children.all
- expect(children).to be_an(Array)
+ expect(children).to be_a(Set)
expect(children.size).to eq(1)
end
it "loads a child from a parent's has_many relationship" do
create_child(parent, :id => '3')
children = parent.children.all
- expect(children).to be_an(Array)
+ expect(children).to be_a(Set)
expect(children.size).to eq(1)
child = children.first
expect(child).to be_a(child_class)
expect(child.id).to eq('3')
end
@@ -59,32 +59,32 @@
expect(parent.children.count).to eq(2)
child = child_class.find_by_id('3')
parent.children.remove(child)
expect(parent.children.count).to eq(1)
- expect(parent.children.ids).to eq(['4'])
+ expect(parent.children.ids).to eq(Set.new(['4']))
end
it "deletes a record from the set by id" do
create_child(parent, :id => '3')
create_child(parent, :id => '4')
expect(parent.children.count).to eq(2)
parent.children.remove_ids('3')
expect(parent.children.count).to eq(1)
- expect(parent.children.ids).to eq(['4'])
+ expect(parent.children.ids).to eq(Set.new(['4']))
end
it "clears all records from the set" do
create_child(parent, :id => '3')
create_child(parent, :id => '4')
expect(parent.children.count).to eq(2)
child = child_class.find_by_id('3')
parent.children.clear
expect(parent.children.count).to eq(0)
- expect(parent.children.ids).to eq([])
+ expect(parent.children.ids).to eq(Set.new)
end
it "does not add a child if the before_add callback raises an exception" # do
# create_child(nil, :id => '6', :important => true)
# child = child_class.find_by_id('6')
@@ -123,29 +123,29 @@
end
it "by indexed attribute values" do
important_kids = parent.children.intersect(:important => true).all
expect(important_kids).not_to be_nil
- expect(important_kids).to be_an(Array)
+ expect(important_kids).to be_a(Set)
expect(important_kids.size).to eq(2)
- expect(important_kids.map(&:id)).to match_array(['3', '4'])
+ expect(important_kids.map(&:id)).to eq(['3', '4'])
end
it "by intersecting ids" do
important_kids = parent.children.intersect(:important => true, :id => ['4', '5']).all
expect(important_kids).not_to be_nil
- expect(important_kids).to be_an(Array)
+ expect(important_kids).to be_a(Set)
expect(important_kids.size).to eq(1)
expect(important_kids.map(&:id)).to match_array(['4'])
end
it "applies chained intersect and union filters to a has_many association" do
create_child(parent, :id => '3', :important => true)
create_child(parent, :id => '4', :important => false)
result = parent.children.intersect(:important => true).union(:id => '4').all
- expect(result).to be_an(Array)
+ expect(result).to be_a(Set)
expect(result.size).to eq(2)
expect(result.map(&:id)).to eq(['3', '4'])
end
it "checks whether a record id exists through a has_many filter" do
@@ -170,20 +170,41 @@
assoc_ids = parent_class.intersect(:id => [ '8', '9', '10']).
associated_ids_for(:children)
expect(assoc_ids).to eq('8' => Set.new(['3', '4', '5']),
'9' => Set.new(['6']),
- '10' => Set.new())
+ '10' => Set.new)
assoc_parent_ids = child_class.intersect(:id => ['3', '4', '5', '6']).
associated_ids_for(:parent)
expect(assoc_parent_ids).to eq('3' => '8',
'4' => '8',
'5' => '8',
'6' => '9')
end
+ it 'returns associations for multiple parent ids' do
+ create_parent(:id => '9')
+ parent_9 = parent_class.find_by_id('9')
+
+ create_child(parent_9, :id => '6', :important => false)
+
+ create_parent(:id => '10')
+
+ assocs = parent_class.intersect(:id => [ '8', '9', '10']).
+ associations_for(:children)
+ expect(assocs).to be_a(Hash)
+ expect(assocs.keys).to match_array(['8', '9', '10'])
+ expect(assocs.values.all? {|r| r.is_a?(Zermelo::Associations::Multiple)}).to be true
+
+ expect(assocs['8'].count).to eq(3)
+ expect(assocs['8'].ids).to eq(Set.new(['3', '4', '5']))
+ expect(assocs['9'].count).to eq(1)
+ expect(assocs['9'].ids).to eq(Set.new(['6']))
+ expect(assocs['10'].count).to eq(0)
+ expect(assocs['10'].ids).to eq(Set.new)
+ end
end
end
context 'redis', :redis => true, :has_many => true do
@@ -308,10 +329,110 @@
expect(redis.keys).to match_array(["#{ck}::attrs:ids",
"#{ck}::indices:by_important:boolean:true",
"#{ck}:6:attrs"])
end
+ it 'queries using association objects' do
+ create_parent(:id => '8')
+ parent_8 = parent_class.find_by_id('8')
+ create_child(parent_8, :id => '5')
+ create_child(parent_8, :id => '6')
+
+ create_parent(:id => '9')
+ parent_9 = parent_class.find_by_id('9')
+ create_child(parent_9, :id => '7')
+
+ create_parent(:id => '10')
+
+ assocs = parent_class.intersect(:id => ['8', '10']).
+ associations_for(:children).values
+
+ children = child_class.intersect(:id => assocs)
+ expect(children.count).to eq(2)
+ expect(children.ids).to eq(Set.new(['5', '6']))
+ end
+
+ it 'queries using multiple association objects' do
+ create_parent(:id => '8')
+ parent_8 = parent_class.find_by_id('8')
+ create_child(parent_8, :id => '5')
+ create_child(parent_8, :id => '6')
+
+ create_parent(:id => '9')
+ parent_9 = parent_class.find_by_id('9')
+ create_child(parent_9, :id => '7')
+
+ create_parent(:id => '10')
+ parent_10 = parent_class.find_by_id('10')
+ create_child(parent_10, :id => '4')
+
+ children = child_class.intersect(:id => [parent_8.children, parent_9.children])
+ expect(children.count).to eq(3)
+ expect(children.ids).to eq(Set.new(['5', '6', '7']))
+ end
+
+ it 'queries using a single filter object' do
+ create_parent(:id => '8')
+ parent_8 = parent_class.find_by_id('8')
+ create_child(parent_8, :id => '5')
+ create_child(parent_8, :id => '6')
+
+ create_parent(:id => '9')
+ parent_9 = parent_class.find_by_id('9')
+ create_child(parent_9, :id => '7')
+
+ create_parent(:id => '10')
+
+ par = parent_class.intersect(:id => ['8', '10'])
+
+ parent_ids = parent_class.intersect(:id => par).ids
+ expect(parent_ids).to eq(Set.new(['8', '10']))
+ end
+
+ it 'queries using multiple filter objects' do
+ create_parent(:id => '8')
+ parent_8 = parent_class.find_by_id('8')
+ create_child(parent_8, :id => '5')
+ create_child(parent_8, :id => '6')
+
+ create_parent(:id => '9')
+ parent_9 = parent_class.find_by_id('9')
+ create_child(parent_9, :id => '7')
+
+ create_parent(:id => '10')
+
+ par_1 = parent_class.intersect(:id => ['8'])
+ par_2 = parent_class.intersect(:id => ['10'])
+
+ parent_ids = parent_class.intersect(:id => [par_1, par_2]).ids
+ expect(parent_ids).to eq(Set.new(['8', '10']))
+ end
+
+ it 'queries using a combination of bare value, association and filter object' do
+ create_parent(:id => '8')
+ parent_8 = parent_class.find_by_id('8')
+ create_child(parent_8, :id => '5')
+ create_child(parent_8, :id => '6')
+
+ create_parent(:id => '9')
+ parent_9 = parent_class.find_by_id('9')
+ create_child(parent_9, :id => '7')
+
+ create_parent(:id => '10')
+ parent_10 = parent_class.find_by_id('10')
+ create_child(parent_10, :id => '4')
+
+ assocs = parent_class.intersect(:id => ['8']).
+ associations_for(:children).values
+
+ children = child_class.intersect(:id => assocs + [
+ parent_9.children.intersect(:id => '7'), '4'
+ ])
+ expect(children.count).to eq(4)
+ expect(children.ids).to eq(Set.new(['4', '5', '6', '7']))
+ end
+
end
context 'influxdb', :influxdb => true, :has_many => true do
let(:influxdb) { Zermelo.influxdb }
@@ -347,10 +468,13 @@
attrs[:important] = attrs[:important].to_s unless attrs[:important].nil?
Zermelo.influxdb.write_point("#{ck}/#{attrs[:id]}", attrs)
par.children.add(child_class.find_by_id!(attrs[:id]))
end
+ # FIXME not implemented yet for InfluxDB, see SetStep
+ it 'queries associated filters transparently'
+
end
end
@@ -370,11 +494,11 @@
secondary.primaries << primary
secondaries = primary.secondaries.all
- expect(secondaries).to be_an(Array)
+ expect(secondaries).to be_a(Set)
expect(secondaries.size).to eq(1)
other_secondary = secondaries.first
expect(other_secondary).to be_a(secondary_class)
expect(other_secondary.id).to eq(secondary.id)
end
@@ -410,13 +534,13 @@
secondary.primaries.remove(primary)
expect(secondary.primaries.count).to eq(1)
expect(primary.secondaries.count).to eq(0)
expect(primary_2.secondaries.count).to eq(1)
- expect(secondary.primaries.ids).to eq(['9'])
- expect(primary.secondaries.ids).to eq([])
- expect(primary_2.secondaries.ids).to eq(['2'])
+ expect(secondary.primaries.ids).to eq(Set.new(['9']))
+ expect(primary.secondaries.ids).to eq(Set.new)
+ expect(primary_2.secondaries.ids).to eq(Set.new(['2']))
end
it "deletes a record from the set by id" do
create_primary(:id => '9', :active => false)
primary = primary_class.find_by_id('8')
@@ -432,13 +556,13 @@
secondary.primaries.remove_ids('8')
expect(secondary.primaries.count).to eq(1)
expect(primary.secondaries.count).to eq(0)
expect(primary_2.secondaries.count).to eq(1)
- expect(secondary.primaries.ids).to eq(['9'])
- expect(primary.secondaries.ids).to eq([])
- expect(primary_2.secondaries.ids).to eq(['2'])
+ expect(secondary.primaries.ids).to eq(Set.new(['9']))
+ expect(primary.secondaries.ids).to eq(Set.new)
+ expect(primary_2.secondaries.ids).to eq(Set.new(['2']))
end
it "clears all records from the set" do
create_primary(:id => '9', :active => false)
primary = primary_class.find_by_id('8')
@@ -454,13 +578,13 @@
secondary.primaries.clear
expect(secondary.primaries.count).to eq(0)
expect(primary.secondaries.count).to eq(0)
expect(primary_2.secondaries.count).to eq(0)
- expect(secondary.primaries.ids).to eq([])
- expect(primary.secondaries.ids).to eq([])
- expect(primary_2.secondaries.ids).to eq([])
+ expect(secondary.primaries.ids).to eq(Set.new)
+ expect(primary.secondaries.ids).to eq(Set.new)
+ expect(primary_2.secondaries.ids).to eq(Set.new)
end
context 'filters' do
it "filters has_and_belongs_to_many records by indexed attribute values" do
@@ -476,11 +600,11 @@
primary_2.secondaries << secondary
primary_3.secondaries << secondary
primaries = secondary.primaries.intersect(:active => true).all
expect(primaries).not_to be_nil
- expect(primaries).to be_an(Array)
+ expect(primaries).to be_a(Set)
expect(primaries.size).to eq(2)
expect(primaries.map(&:id)).to match_array(['8', '10'])
end
it "checks whether a record id exists through a has_and_belongs_to_many filter" do
@@ -745,11 +869,11 @@
create_child(parent, :id => '4', :emotion => 'indifferent', :timestamp => time)
child = child_class.find_by_id('4')
children = parent.children.all
- expect(children).to be_an(Array)
+ expect(children).to be_a(Zermelo::OrderedSet)
expect(children.size).to eq(1)
child = children.first
expect(child).to be_a(child_class)
expect(child.timestamp).to be_within(1).of(time) # ignore fractional differences
end
@@ -864,13 +988,13 @@
create_child(parent_10, :id => '5', :timestamp => time,
:emotion => 'not_ok')
assoc_ids = parent_class.intersect(:id => ['8', '9', '10']).
associated_ids_for(:children)
- expect(assoc_ids).to eq('8' => ['3', '4'],
- '9' => [],
- '10' => ['5'])
+ expect(assoc_ids).to eq('8' => Zermelo::OrderedSet.new(['3', '4']),
+ '9' => Zermelo::OrderedSet.new,
+ '10' => Zermelo::OrderedSet.new(['5']))
end
it "deletes a record from the set" do
create_child(parent, :id => '3', :timestamp => time - 20,
:emotion => 'ok')
@@ -879,11 +1003,11 @@
expect(parent.children.count).to eq(2)
child = child_class.find_by_id('3')
parent.children.remove(child)
expect(parent.children.count).to eq(1)
- expect(parent.children.ids).to eq(['4'])
+ expect(parent.children.ids).to eq(Set.new(['4']))
end
it "deletes a record from the set by id" do
create_child(parent, :id => '3', :timestamp => time - 20,
:emotion => 'ok')
@@ -891,11 +1015,11 @@
:emotion => 'ok')
expect(parent.children.count).to eq(2)
parent.children.remove_ids('3')
expect(parent.children.count).to eq(1)
- expect(parent.children.ids).to eq(['4'])
+ expect(parent.children.ids).to eq(Zermelo::OrderedSet.new(['4']))
end
it "clears all records from the set" do
create_child(parent, :id => '3', :timestamp => time - 20,
:emotion => 'ok')
@@ -904,11 +1028,11 @@
expect(parent.children.count).to eq(2)
child = child_class.find_by_id('3')
parent.children.clear
expect(parent.children.count).to eq(0)
- expect(parent.children.ids).to eq([])
+ expect(parent.children.ids).to eq(Zermelo::OrderedSet.new)
end
context 'filters' do
before do
create_child(parent, :id => '4', :timestamp => time - 20,
@@ -920,56 +1044,56 @@
end
it "by indexed attribute values" do
upset_children = parent.children.intersect(:emotion => 'upset').all
expect(upset_children).not_to be_nil
- expect(upset_children).to be_an(Array)
+ expect(upset_children).to be_a(Zermelo::OrderedSet)
expect(upset_children.size).to eq(2)
expect(upset_children.map(&:id)).to eq(['4', '6'])
end
it "by indexed attribute values with a regex search" do
upset_children = parent.children.intersect(:emotion => /^ups/).all
expect(upset_children).not_to be_nil
- expect(upset_children).to be_an(Array)
+ expect(upset_children).to be_a(Zermelo::OrderedSet)
expect(upset_children.size).to eq(2)
expect(upset_children.map(&:id)).to eq(['4', '6'])
end
it "a subset of a sorted set by index" do
range = Zermelo::Filters::IndexRange.new(0, 1)
children = parent.children.intersect(:timestamp => range).all
expect(children).not_to be_nil
- expect(children).to be_an(Array)
+ expect(children).to be_a(Zermelo::OrderedSet)
expect(children.size).to eq(2)
expect(children.map(&:id)).to eq(['4', '5'])
end
it "a reversed subset of a sorted set by index" do
range = Zermelo::Filters::IndexRange.new(1, 2)
children = parent.children.intersect(:timestamp => range).sort(:id, :desc => true).all
expect(children).not_to be_nil
- expect(children).to be_an(Array)
+ expect(children).to be_a(Zermelo::OrderedSet)
expect(children.size).to eq(2)
expect(children.map(&:id)).to eq(['6', '5'])
end
it "a subset of a sorted set by score" do
range = Zermelo::Filters::IndexRange.new(time - 25, time - 5, :by_score => true)
children = parent.children.intersect(:timestamp => range).all
expect(children).not_to be_nil
- expect(children).to be_an(Array)
+ expect(children).to be_a(Zermelo::OrderedSet)
expect(children.size).to eq(2)
expect(children.map(&:id)).to eq(['4', '5'])
end
it "a reversed subset of a sorted set by score" do
range = Zermelo::Filters::IndexRange.new(time - 25, time - 5, :by_score => true)
children = parent.children.intersect(:timestamp => range).
sort(:timestamp, :desc => true).all
expect(children).not_to be_nil
- expect(children).to be_an(Array)
+ expect(children).to be_a(Zermelo::OrderedSet)
expect(children.size).to eq(2)
expect(children.map(&:id)).to eq(['5', '4'])
end
it "checks whether a record exists" do
@@ -992,54 +1116,54 @@
it "ANDs multiple union arguments, not ORs them" do
children = parent.children.intersect(:id => ['4']).
union(:emotion => 'upset', :id => ['4', '6']).all
expect(children).not_to be_nil
- expect(children).to be_an(Array)
+ expect(children).to be_a(Zermelo::OrderedSet)
expect(children.size).to eq(2)
expect(children.map(&:id)).to eq(['4', '6'])
end
it "ANDs multiple diff arguments, not ORs them" do
children = parent.children.diff(:emotion => 'upset', :id => ['4', '5']).all
expect(children).not_to be_nil
- expect(children).to be_an(Array)
+ expect(children).to be_a(Zermelo::OrderedSet)
expect(children.size).to eq(2)
expect(children.map(&:id)).to eq(['5', '6'])
end
it "the exclusion of a sorted set by index" do
range = Zermelo::Filters::IndexRange.new(0, 1)
children = parent.children.diff(:timestamp => range).all
expect(children).not_to be_nil
- expect(children).to be_an(Array)
+ expect(children).to be_a(Zermelo::OrderedSet)
expect(children.size).to eq(1)
expect(children.map(&:id)).to eq(['6'])
end
it "a reversed exclusion of a sorted set by index" do
range = Zermelo::Filters::IndexRange.new(2, 2)
children = parent.children.diff(:timestamp => range).sort(:id, :desc => true).all
expect(children).not_to be_nil
- expect(children).to be_an(Array)
+ expect(children).to be_a(Zermelo::OrderedSet)
expect(children.size).to eq(2)
expect(children.map(&:id)).to eq(['5', '4'])
end
it "the exclusion of a sorted set by score" do
range = Zermelo::Filters::IndexRange.new(time - 25, time - 5, :by_score => true)
children = parent.children.diff(:timestamp => range).all
expect(children).not_to be_nil
- expect(children).to be_an(Array)
+ expect(children).to be_a(Zermelo::OrderedSet)
expect(children.size).to eq(1)
expect(children.map(&:id)).to eq(['6'])
end
it "a reversed exclusion of a sorted set by score" do
range = Zermelo::Filters::IndexRange.new(time - 5, time, :by_score => true)
children = parent.children.diff(:timestamp => range).sort(:timestamp, :desc => true).all
expect(children).not_to be_nil
- expect(children).to be_an(Array)
+ expect(children).to be_a(Zermelo::OrderedSet)
expect(children.size).to eq(2)
expect(children.map(&:id)).to eq(['5', '4'])
end
end
\ No newline at end of file