require "spec_helper" describe Mongoid::Relations::Referenced::ManyToMany do before(:all) do Mongoid.raise_not_found_error = true Person.autosaved_relations.delete_one(:preferences) Person.autosave(Person.relations["preferences"].merge!(autosave: true)) Person.synced(Person.relations["preferences"]) end after(:all) do Person.reset_callbacks(:save) Person.reset_callbacks(:destroy) end [ :<<, :push ].each do |method| describe "##{method}" do context "when the inverse_of is nil" do let!(:article) do Article.create end context "when the child document is new" do let(:preference) do Preference.new end before do article.preferences.send(method, preference) end it "persists the child document" do preference.should be_persisted end end context "when the child document is not new" do let(:preference) do Preference.create end it "does not persist the child document" do preference.should_receive(:save).never article.preferences.send(method, preference) end end end context "when the parent is a new record" do let(:person) do Person.new end let!(:preference) do Preference.new end let(:result) do person.preferences.send(method, preference) end it "returns an array of loaded documents" do result.should eq([ preference ]) end end context "when the parent is not a new record" do let(:person) do Person.create end let!(:preference) do Preference.new end let(:result) do person.preferences.send(method, preference) end it "returns an array of loaded documents" do result.should eq([ preference ]) end end context "when the relations are not polymorphic" do context "when the inverse relation is not defined" do let(:person) do Person.new end let(:house) do House.new end before do person.houses << house end it "appends the document to the relation" do person.houses.should eq([ house ]) end it "sets the foreign key on the relation" do person.house_ids.should eq([ house.id ]) end end context "when appending in a parent create block" do let!(:preference) do Preference.create(name: "testing") end let!(:person) do Person.create do |doc| doc.preferences << preference end end it "adds the documents to the relation" do person.preferences.should eq([ preference ]) end it "sets the foreign key on the relation" do person.preference_ids.should eq([ preference.id ]) end it "sets the foreign key on the inverse relation" do preference.person_ids.should eq([ person.id ]) end it "saves the target" do preference.should be_persisted end it "adds the correct number of documents" do person.preferences.size.should eq(1) end it "persists the link" do person.reload.preferences.should eq([ preference ]) end end context "when the parent is a new record" do let(:person) do Person.new end context "when the child is new" do let(:preference) do Preference.new end before do person.preferences.send(method, preference) end it "adds the documents to the relation" do person.preferences.should eq([ preference ]) end it "sets the foreign key on the relation" do person.preference_ids.should eq([ preference.id ]) end it "sets the foreign key on the inverse relation" do preference.person_ids.should eq([ person.id ]) end it "does not save the target" do preference.should be_new_record end it "adds the correct number of documents" do person.preferences.size.should eq(1) end context "when appending a second time" do before do person.preferences.send(method, preference) end it "does not allow the document to be added again" do person.preferences.should eq([ preference ]) end it "does not allow duplicate ids" do person.preference_ids.should eq([ preference.id ]) end end end context "when the child is already persisted" do let!(:persisted) do Preference.create(name: "testy") end let(:preference) do Preference.first end before do person.preferences.send(method, preference) person.save end it "adds the documents to the relation" do person.preferences.should eq([ preference ]) end it "sets the foreign key on the relation" do person.preference_ids.should eq([ preference.id ]) end it "sets the foreign key on the inverse relation" do preference.person_ids.should eq([ person.id ]) end it "saves the target" do preference.should be_persisted end it "adds the correct number of documents" do person.preferences.size.should eq(1) end it "persists the link" do person.reload.preferences.should eq([ preference ]) end end context "when setting via the associated ids" do let!(:persisted) do Preference.create(name: "testy") end let(:preference) do Preference.first end let(:person) do Person.new(preference_ids: [ preference.id ]) end before do person.save end it "adds the documents to the relation" do person.preferences.should eq([ preference ]) end it "sets the foreign key on the relation" do person.preference_ids.should eq([ preference.id ]) end it "sets the foreign key on the inverse relation" do preference.reload.person_ids.should eq([ person.id ]) end it "adds the correct number of documents" do person.preferences.size.should eq(1) end it "persists the link" do person.reload.preferences.should eq([ preference ]) end end end context "when the parent is not a new record" do let(:person) do Person.create end let(:preference) do Preference.new end before do person.preferences.send(method, preference) end it "adds the documents to the relation" do person.preferences.should eq([ preference ]) end it "sets the foreign key on the relation" do person.preference_ids.should eq([ preference.id ]) end it "sets the foreign key on the inverse relation" do preference.person_ids.should eq([ person.id ]) end it "sets the base on the inverse relation" do preference.people.should eq([ person ]) end it "sets the same instance on the inverse relation" do preference.people.first.should eql(person) end it "saves the target" do preference.should_not be_new_record end it "adds the document to the target" do person.preferences.count.should eq(1) end context "when documents already exist on the relation" do let(:preference_two) do Preference.new end before do person.preferences.send(method, preference_two) end it "adds the documents to the relation" do person.preferences.should eq([ preference, preference_two ]) end it "sets the foreign key on the relation" do person.preference_ids.should eq([ preference.id, preference_two.id ]) end it "sets the foreign key on the inverse relation" do preference_two.person_ids.should eq([ person.id ]) end it "sets the base on the inverse relation" do preference_two.people.should eq([ person ]) end it "sets the same instance on the inverse relation" do preference_two.people.first.should eql(person) end it "saves the target" do preference.should_not be_new_record end it "adds the document to the target" do person.preferences.count.should eq(2) end end end context "when both sides have been persisted" do let(:person) do Person.create end let(:event) do Event.create end before do person.administrated_events << event end it "sets the front side of the relation" do person.administrated_events.should eq([ event ]) end it "sets the inverse side of the relation" do event.administrators(true).should eq([ person ]) end context "when reloading" do it "sets the front side of the relation" do person.reload.administrated_events.should eq([ event ]) end it "sets the inverse side of the relation" do event.reload.administrators.should eq([ person ]) end end context "when performing a new database query" do let(:loaded_person) do Person.find(person.id) end let(:loaded_event) do Event.find(event.id) end it "sets the front side of the relation" do loaded_person.administrated_events.should eq([ event ]) end it "sets the inverse side of the relation" do loaded_event.administrators.should eq([ person ]) end end end context "when the relation also includes a has_many relation" do let(:artwork) do Artwork.create end let(:exhibition) do Exhibition.create end let(:exhibitor) do Exhibitor.create(exhibition: exhibition) end before do artwork.exhibitors << exhibitor end it "creates a single artwork object" do Artwork.count.should eq(1) end end context "when the relation is self referencing" do let(:tag_one) do Tag.create(text: "one") end let(:tag_two) do Tag.create(text: "two") end before do tag_one.related << tag_two end it "sets the front side of the relation" do tag_one.related.should eq([ tag_two ]) end it "sets the inverse side of the relation" do tag_two.related(true).should eq([ tag_one ]) end context "when reloading" do it "sets the front side of the relation" do tag_one.reload.related.should eq([ tag_two ]) end it "sets the inverse side of the relation" do tag_two.reload.related.should eq([ tag_one ]) end end context "when performing a new database query" do let(:loaded_tag_one) do Tag.find(tag_one.id) end let(:loaded_tag_two) do Tag.find(tag_two.id) end it "sets the front side of the relation" do loaded_tag_one.related.should eq([ tag_two ]) end it "sets the inverse side of the relation" do loaded_tag_two.related.should eq([ tag_one ]) end end end end context "when association has callbacks" do let(:post) do Post.new end let(:tag) do Tag.new end context "when the callback is a before_add" do it "executes the callback" do post.tags.send(method, tag) post.before_add_called.should be_true end context "when errors are raised" do before do post.should_receive(:before_add_tag).and_raise end it "does not add the document to the relation" do expect { post.tags.send(method, tag) }.to raise_error post.tags.should be_empty end end end context "when the callback is an after_add" do it "executes the callback" do post.tags.send(method, tag) post.after_add_called.should be_true end context "when errors are raised" do before do post.should_receive(:after_add_tag).and_raise end it "adds the document to the relation" do expect { post.tags.send(method, tag) }.to raise_error post.tags.should eq([ tag ]) end end end end end end describe "#=" do context "when trying to add duplicate entries" do let(:person) do Person.new end let(:preference) do Preference.create(name: "one") end before do person.preferences = [ preference, preference ] end context "when the document is new" do it "does not add the duplicates" do person.preferences.should eq([ preference ]) end it "does not create duplicate keys" do person.preference_ids.should eq([ preference.id ]) end end context "when the document is persisted" do before do person.save end it "does not add the duplicates" do person.preferences.should eq([ preference ]) end it "does not create duplicate keys" do person.preference_ids.should eq([ preference.id ]) end it "does not add duplicates on the inverse" do preference.people.should eq([ person ]) end it "does not add duplicate inverse keys" do preference.person_ids.should eq([ person.id ]) end end end context "when the relation is not polymorphic" do context "when the parent and relation are new records" do let(:person) do Person.new end let(:preference) do Preference.new end before do person.preferences = [ preference ] end it "sets the relation" do person.preferences.should eq([ preference ]) end it "sets the foreign key on the relation" do person.preference_ids.should eq([ preference.id ]) end it "sets the foreign key on the inverse relation" do preference.person_ids.should eq([ person.id ]) end it "does not save the target" do preference.should be_new_record end end context "when the parent is new but the relation exists" do let(:person) do Person.new end let!(:preference) do Preference.create end before do person.preferences = [ preference ] end it "sets the relation" do person.preferences.should eq([ preference ]) end it "sets the foreign key on the relation" do person.preference_ids.should eq([ preference.id ]) end it "sets the foreign key on the inverse relation" do preference.person_ids.should eq([ person.id ]) end context "and the parent is persisted" do before do person.save! preference.reload end it "maintains the relation" do person.preferences.should eq([ preference ]) end it "maintains the foreign key on the relation" do person.preference_ids.should eq([ preference.id ]) end it "maintains the foreign key on the inverse relation" do preference.person_ids.should eq([ person.id ]) end it "maintains the base on the inverse relation" do preference.people.first.should eq(person) end end end context "when the parent is not a new record" do let(:person) do Person.create end let(:preference) do Preference.new end before do person.preferences = [ preference ] end it "sets the relation" do person.preferences.should eq([ preference ]) end it "sets the foreign key on the relation" do person.preference_ids.should eq([ preference.id ]) end it "sets the foreign key on the inverse relation" do preference.person_ids.should eq([ person.id ]) end it "sets the base on the inverse relation" do preference.people.first.should eq(person) end it "saves the target" do preference.should be_persisted end it "persists the relation" do person.reload.preferences == [ preference ] end context "when overwriting an existing relation" do let(:another_preference) do Preference.new end before do person.preferences = [ another_preference ] end it "sets the relation" do person.preferences.should eq([ another_preference ]) end it "saves the target" do another_preference.should be_persisted end it "does not leave foreign keys of the previous relation" do person.preference_ids.should eq([ another_preference.id ]) end it "clears its own key on the foreign relation" do preference.person_ids.should be_empty end context "and then overwriting it again with the same value" do before do person.preferences = [ another_preference ] end it "persists the relation between another_preference and person" do another_preference.reload.people.should eq([ person ]) end end context "and person reloaded instead of saved" do before do person.reload another_preference.reload end it "persists the relation between person and another_preference" do person.preferences.should eq([ another_preference ]) end it "persists the relation between another_prefrence and person" do another_preference.people.should eq([ person ]) end it "no longer has any relation between preference and person" do preference.people.should be_empty end end context "and person is saved" do before do person.save person.reload another_preference.reload end it "persists the relation between person and another_preference" do person.preferences.should eq([ another_preference ]) end it "persists the relation between another_prefrence and person" do another_preference.people.should eq([ person ]) end it "no longer has any relation between preference and person" do preference.people.should be_empty end end end end end end [ nil, [] ].each do |value| describe "#= #{value}" do context "when the relation is not polymorphic" do context "when the inverse relation is not defined" do let(:person) do Person.new end let(:house) do House.new end before do person.houses << house person.houses = value end it "clears the relation" do person.houses.should be_empty end it "clears the foreign keys" do person.house_ids.should be_empty end end context "when the parent is a new record" do let(:person) do Person.new end let(:preference) do Preference.new end before do person.preferences = [ preference ] person.preferences = value end it "sets the relation to an empty array" do person.preferences.should be_empty end it "removed the inverse relation" do preference.people.should be_empty end it "removes the foreign key values" do person.preference_ids.should be_empty end it "removes the inverse foreign key values" do preference.person_ids.should be_empty end end context "when the parent is not a new record" do context "when the relation has been loaded" do let(:person) do Person.create end let(:preference) do Preference.new end before do person.preferences = [ preference ] person.preferences = value end it "sets the relation to an empty array" do person.preferences.should be_empty end it "removed the inverse relation" do preference.people.should be_empty end it "removes the foreign key values" do person.preference_ids.should be_empty end it "removes the inverse foreign key values" do preference.person_ids.should be_empty end it "does not delete the target from the database" do preference.should_not be_destroyed end end context "when the relation has not been loaded" do let(:preference) do Preference.new end let(:person) do Person.create.tap do |p| p.preferences = [ preference ] end end let!(:from_db) do Person.find(person.id) end before do from_db.preferences = value end it "sets the relation to an empty array" do from_db.preferences.should be_empty end it "removes the foreign key values" do from_db.preference_ids.should be_empty end end end end end end [ :build, :new ].each do |method| describe "##{method}" do context "when providing scoped mass assignment" do let(:person) do Person.new end let(:house) do person.houses.send( method, { name: "Dream", model: "Home" }, as: :admin ) end it "sets the attributes for the provided role" do house.name.should eq("Dream") end it "does not set the attributes for other roles" do house.model.should be_nil end end context "when the relation is not polymorphic" do context "when the parent is a new record" do let(:person) do Person.new end let!(:preference) do person.preferences.send(method, name: "settings") end it "adds the document to the relation" do person.preferences.should eq([ preference ]) end it "sets the foreign key on the relation" do person.preference_ids.should eq([ preference.id ]) end it "sets the inverse foreign key on the relation" do preference.person_ids.should eq([ person.id ]) end it "sets the attributes" do preference.name.should eq("settings") end it "does not save the target" do preference.should be_new_record end it "adds the correct number of documents" do person.preferences.size.should eq(1) end end context "when the parent is not a new record" do let(:person) do Person.create end let!(:preference) do person.preferences.send(method, name: "settings") end it "adds the document to the relation" do person.preferences.should eq([ preference ]) end it "sets the foreign key on the relation" do person.preference_ids.should eq([ preference.id ]) end it "sets the inverse foreign key on the relation" do preference.person_ids.should eq([ person.id ]) end it "sets the base on the inverse relation" do preference.people.should eq([ person ]) end it "sets the attributes" do preference.name.should eq("settings") end it "does not save the target" do preference.should be_new_record end it "adds the correct number of documents" do person.preferences.size.should eq(1) end context "when saving the target" do before do preference.save end it "persists the parent keys" do person.reload.preference_ids.should eq([ preference.id ]) end end end end end end describe ".builder" do let(:builder_klass) do Mongoid::Relations::Builders::Referenced::ManyToMany end let(:document) do stub end let(:metadata) do stub(extension?: false) end it "returns the embedded in builder" do described_class.builder(nil, metadata, document).should be_a_kind_of(builder_klass) end end describe "#clear" do context "when the relation is not polymorphic" do context "when the parent has been persisted" do let!(:person) do Person.create end context "when the children are persisted" do let!(:preference) do person.preferences.create(name: "settings") end let!(:relation) do person.preferences.clear end it "clears out the relation" do person.preferences.should be_empty end it "removes the parent from the inverse relation" do preference.people.should_not include(person) end it "removes the foreign keys" do person.preference_ids.should be_empty end it "removes the parent key from the inverse" do preference.person_ids.should_not include(person.id) end it "does not delete the documents" do preference.should_not be_destroyed end it "persists the nullification" do person.reload.preferences.should be_empty end it "returns the relation" do relation.should be_empty end end context "when the children are not persisted" do let!(:preference) do person.preferences.build(name: "setting") end let!(:relation) do person.preferences.clear end it "clears out the relation" do person.preferences.should be_empty end end end context "when the parent is not persisted" do let(:person) do Person.new end let!(:preference) do person.preferences.build(name: "setting") end let!(:relation) do person.preferences.clear end it "clears out the relation" do person.preferences.should be_empty end end end context "when the association has callbacks" do let(:post) do Post.new end let(:tag) do Tag.new end before do post.tags << tag end context "when the callback is a before_remove" do context "when no errors are raised" do before do post.tags.clear end it "executes the callback" do post.before_remove_called.should be_true end it "removes the document from the relation" do post.tags.should be_empty end end context "when errors are raised" do before do post.should_receive(:before_remove_tag).and_raise end it "does not remove the document from the relation" do expect { post.tags.clear }.to raise_error post.tags.should eq([ tag ]) end end end context "when the callback is an after_remove" do context "when no errors are raised" do before do post.tags.clear end it "executes the callback" do post.after_remove_called.should be_true end it "removes the document from the relation" do post.tags.should be_empty end end context "when errors are raised" do before do post.should_receive(:after_remove_tag).and_raise end it "removes the document from the relation" do expect { post.tags.clear }.to raise_error post.tags.should be_empty end end end end end describe "#concat" do context "when the parent is a new record" do let(:person) do Person.new end let!(:preference) do Preference.new end let(:result) do person.preferences.concat([ preference ]) end it "returns an array of loaded documents" do result.should eq([ preference ]) end end context "when the parent is not a new record" do let(:person) do Person.create end let!(:preference) do Preference.new end let(:result) do person.preferences.concat([ preference ]) end it "returns an array of loaded documents" do result.should eq([ preference ]) end end context "when the relations are not polymorphic" do context "when the inverse relation is not defined" do let(:person) do Person.new end let(:house) do House.new end before do person.houses.concat([ house ]) end it "appends the document to the relation" do person.houses.should eq([ house ]) end it "sets the foreign key on the relation" do person.house_ids.should eq([ house.id ]) end end context "when appending in a parent create block" do let!(:preference) do Preference.create(name: "testing") end let!(:person) do Person.create do |doc| doc.preferences.concat([ preference ]) end end it "adds the documents to the relation" do person.preferences.should eq([ preference ]) end it "sets the foreign key on the relation" do person.preference_ids.should eq([ preference.id ]) end it "sets the foreign key on the inverse relation" do preference.person_ids.should eq([ person.id ]) end it "saves the target" do preference.should be_persisted end it "adds the correct number of documents" do person.preferences.size.should eq(1) end it "persists the link" do person.reload.preferences.should eq([ preference ]) end end context "when the parent is a new record" do let(:person) do Person.new end context "when the child is new" do let(:preference) do Preference.new end before do person.preferences.concat([ preference ]) end it "adds the documents to the relation" do person.preferences.should eq([ preference ]) end it "sets the foreign key on the relation" do person.preference_ids.should eq([ preference.id ]) end it "sets the foreign key on the inverse relation" do preference.person_ids.should eq([ person.id ]) end it "does not save the target" do preference.should be_new_record end it "adds the correct number of documents" do person.preferences.size.should eq(1) end context "when appending a second time" do before do person.preferences.concat([ preference ]) end it "does not allow the document to be added again" do person.preferences.should eq([ preference ]) end it "does not allow duplicate ids" do person.preference_ids.should eq([ preference.id ]) end end end context "when the child is already persisted" do let!(:persisted) do Preference.create(name: "testy") end let(:preference) do Preference.first end before do person.preferences.concat([ preference ]) person.save end it "adds the documents to the relation" do person.preferences.should eq([ preference ]) end it "sets the foreign key on the relation" do person.preference_ids.should eq([ preference.id ]) end it "sets the foreign key on the inverse relation" do preference.person_ids.should eq([ person.id ]) end it "saves the target" do preference.should be_persisted end it "adds the correct number of documents" do person.preferences.size.should eq(1) end it "persists the link" do person.reload.preferences.should eq([ preference ]) end end context "when setting via the associated ids" do let!(:persisted) do Preference.create(name: "testy") end let(:preference) do Preference.first end let(:person) do Person.new(preference_ids: [ preference.id ]) end before do person.save end it "adds the documents to the relation" do person.preferences.should eq([ preference ]) end it "sets the foreign key on the relation" do person.preference_ids.should eq([ preference.id ]) end it "sets the foreign key on the inverse relation" do preference.reload.person_ids.should eq([ person.id ]) end it "adds the correct number of documents" do person.preferences.size.should eq(1) end it "persists the link" do person.reload.preferences.should eq([ preference ]) end end end context "when the parent is not a new record" do let(:person) do Person.create end let(:preference) do Preference.new end before do person.preferences.concat([ preference ]) end it "adds the documents to the relation" do person.preferences.should eq([ preference ]) end it "sets the foreign key on the relation" do person.preference_ids.should eq([ preference.id ]) end it "sets the foreign key on the inverse relation" do preference.person_ids.should eq([ person.id ]) end it "sets the base on the inverse relation" do preference.people.should eq([ person ]) end it "sets the same instance on the inverse relation" do preference.people.first.should eql(person) end it "saves the target" do preference.should_not be_new_record end it "adds the document to the target" do person.preferences.count.should eq(1) end context "when documents already exist on the relation" do let(:preference_two) do Preference.new end before do person.preferences.concat([ preference_two ]) end it "adds the documents to the relation" do person.preferences.should eq([ preference, preference_two ]) end it "sets the foreign key on the relation" do person.preference_ids.should eq([ preference.id, preference_two.id ]) end it "sets the foreign key on the inverse relation" do preference_two.person_ids.should eq([ person.id ]) end it "sets the base on the inverse relation" do preference_two.people.should eq([ person ]) end it "sets the same instance on the inverse relation" do preference_two.people.first.should eql(person) end it "saves the target" do preference.should_not be_new_record end it "adds the document to the target" do person.preferences.count.should eq(2) end end end context "when both sides have been persisted" do let(:person) do Person.create end let(:event) do Event.create end before do person.administrated_events.concat([ event ]) end it "sets the front side of the relation" do person.administrated_events.should eq([ event ]) end it "sets the inverse side of the relation" do event.administrators(true).should eq([ person ]) end context "when reloading" do it "sets the front side of the relation" do person.reload.administrated_events.should eq([ event ]) end it "sets the inverse side of the relation" do event.reload.administrators.should eq([ person ]) end end context "when performing a new database query" do let(:loaded_person) do Person.find(person.id) end let(:loaded_event) do Event.find(event.id) end it "sets the front side of the relation" do loaded_person.administrated_events.should eq([ event ]) end it "sets the inverse side of the relation" do loaded_event.administrators.should eq([ person ]) end end end context "when the relation also includes a has_many relation" do let(:artwork) do Artwork.create end let(:exhibition) do Exhibition.create end let(:exhibitor) do Exhibitor.create(exhibition: exhibition) end before do artwork.exhibitors.concat([ exhibitor ]) end it "creates a single artwork object" do Artwork.count.should eq(1) end end context "when the relation is self referencing" do let(:tag_one) do Tag.create(text: "one") end let(:tag_two) do Tag.create(text: "two") end before do tag_one.related.concat([ tag_two ]) end it "sets the front side of the relation" do tag_one.related.should eq([ tag_two ]) end it "sets the inverse side of the relation" do tag_two.related(true).should eq([ tag_one ]) end context "when reloading" do it "sets the front side of the relation" do tag_one.reload.related.should eq([ tag_two ]) end it "sets the inverse side of the relation" do tag_two.reload.related.should eq([ tag_one ]) end end context "when performing a new database query" do let(:loaded_tag_one) do Tag.find(tag_one.id) end let(:loaded_tag_two) do Tag.find(tag_two.id) end it "sets the front side of the relation" do loaded_tag_one.related.should eq([ tag_two ]) end it "sets the inverse side of the relation" do loaded_tag_two.related.should eq([ tag_one ]) end end end end end describe "#count" do let(:person) do Person.create end context "when nothing exists on the relation" do context "when the document is destroyed" do before do Meat.create! end let!(:sandwich) do Sandwich.create! end it "returns zero" do sandwich.destroy sandwich.meats.count.should eq(0) end end end context "when documents have been persisted" do let!(:preference) do person.preferences.create(name: "setting") end it "returns the number of persisted documents" do person.preferences.count.should eq(1) end end context "when appending to a loaded relation" do let!(:preference) do person.preferences.create(name: "setting") end before do person.preferences.count person.preferences << Preference.create(name: "two") end it "returns the number of persisted documents" do person.preferences.count.should eq(2) end end context "when documents have not been persisted" do let!(:preference) do person.preferences.build(name: "settings") end it "returns 0" do person.preferences.count.should eq(0) end end context "when new documents exist in the database" do context "when the documents are part of the relation" do before do Preference.create(person_ids: [ person.id ]) end it "returns the count from the db" do person.reload.preferences.count.should eq(1) end end context "when the documents are not part of the relation" do before do Preference.create end it "returns the count from the db" do person.preferences.count.should eq(0) end end end context "when the inverse relation is not defined" do context "when documents have been persisted" do let!(:house) do person.houses.create(name: "Wayne Manor") end it "returns the number of persisted documents" do person.houses.count.should eq(1) end end context "when documents have not been persisted" do let!(:house) do person.houses.build(name: "Ryugyong Hotel") end it "returns 0" do person.preferences.count.should eq(0) end end end end [ :create, :create! ].each do |method| describe "##{method}" do context "when providing scoped mass assignment" do let(:person) do Person.create end let(:house) do person.houses.send( method, { name: "Dream", model: "Home" }, as: :admin ) end it "sets the attributes for the provided role" do house.name.should eq("Dream") end it "does not set the attributes for other roles" do house.model.should be_nil end end context "when the relation is not polymorphic" do context "when using string keys" do let(:agent) do Agent.create(number: "007") end before do agent.accounts.create(name: "testing again") end it "does not convert the string key to an object id" do agent.account_ids.should eq([ "testing-again" ]) end end context "when the parent is a new record" do let(:person) do Person.new end it "raises an unsaved document error" do expect { person.preferences.send(method, name: "Testing") }.to raise_error(Mongoid::Errors::UnsavedDocument) end end context "when the parent is not a new record" do let(:person) do Person.send(method) end let!(:preference) do person.preferences.send(method, name: "Testing") end it "sets the foreign key on the relation" do person.preference_ids.should eq([ preference.id ]) end it "sets the foreign key on the inverse relation" do preference.person_ids.should eq([ person.id ]) end it "adds the document" do person.preferences.should eq([ preference ]) end it "sets the base on the inverse relation" do preference.people.should eq([ person ]) end it "sets the attributes" do preference.name.should eq("Testing") end it "saves the target" do preference.should be_persisted end it "adds the document to the target" do person.preferences.count.should eq(1) end it "does not duplicate documents" do person.reload.preferences.count.should eq(1) end it "does not duplicate ids" do person.reload.preference_ids.count.should eq(1) end end end end end describe "#create!" do context "when validation fails" do let(:person) do Person.create end context "when the relation is not polymorphic" do it "raises an error" do expect { person.preferences.create!(name: "a") }.to raise_error(Mongoid::Errors::Validations) end end end end describe "#delete" do let(:person) do Person.create end let(:preference_one) do Preference.create(name: "Testing") end let(:preference_two) do Preference.create(name: "Test") end before do person.preferences << [ preference_one, preference_two ] end context "when the document exists" do let!(:deleted) do person.preferences.delete(preference_one) end it "removes the document from the relation" do person.preferences.should eq([ preference_two ]) end it "returns the document" do deleted.should eq(preference_one) end it "removes the document key from the foreign key" do person.preference_ids.should eq([ preference_two.id ]) end it "removes the inverse reference" do deleted.reload.people.should be_empty end it "removes the base id from the inverse keys" do deleted.reload.person_ids.should be_empty end context "and person and preferences are reloaded" do before do person.reload preference_one.reload preference_two.reload end it "nullifies the deleted preference" do person.preferences.should eq([ preference_two ]) end it "retains the ids for one preference" do person.preference_ids.should eq([ preference_two.id ]) end end end context "when the document does not exist" do let!(:deleted) do person.preferences.delete(Preference.new) end it "returns nil" do deleted.should be_nil end it "does not modify the relation" do person.preferences.should eq([ preference_one, preference_two ]) end it "does not modify the keys" do person.preference_ids.should eq([ preference_one.id, preference_two.id ]) end end context "when :dependent => :nullify is set" do context "when :inverse_of is set" do let(:event) do Event.create end before do person.administrated_events << [ event ] end it "deletes the document" do event.delete.should be_true end end end context "when the relationships are self referencing" do let(:tag_one) do Tag.create(text: "one") end let(:tag_two) do Tag.create(text: "two") end before do tag_one.related << tag_two end context "when deleting without reloading" do let!(:deleted) do tag_one.related.delete(tag_two) end it "deletes the document from the relation" do tag_one.related.should be_empty end it "deletes the foreign key from the relation" do tag_one.related_ids.should be_empty end it "removes the reference from the inverse" do deleted.related.should be_empty end it "removes the foreign keys from the inverse" do deleted.related_ids.should be_empty end end context "when deleting with reloading" do context "when deleting from the front side" do let(:reloaded) do tag_one.reload end let!(:deleted) do reloaded.related.delete(tag_two) end it "deletes the document from the relation" do reloaded.related.should be_empty end it "deletes the foreign key from the relation" do reloaded.related_ids.should be_empty end it "removes the reference from the inverse" do deleted.related.should be_empty end it "removes the foreign keys from the inverse" do deleted.related_ids.should be_empty end end context "when deleting from the inverse side" do let(:reloaded) do tag_two.reload end let!(:deleted) do reloaded.related.delete(tag_one) end it "deletes the document from the relation" do reloaded.related.should be_empty end it "deletes the foreign key from the relation" do reloaded.related_ids.should be_empty end it "removes the foreign keys from the inverse" do deleted.related_ids.should be_empty end end end end context "when the association has callbacks" do let(:post) do Post.new end let(:tag) do Tag.new end before do post.tags << tag end context "when the callback is a before_remove" do context "when there are no errors" do before do post.tags.delete tag end it "executes the callback" do post.before_remove_called.should be_true end it "removes the document from the relation" do post.tags.should be_empty end end context "when errors are raised" do before do post.should_receive(:before_remove_tag).and_raise end it "does not remove the document from the relation" do expect { post.tags.delete tag }.to raise_error post.tags.should eq([ tag ]) end end end context "when the callback is an after_remove" do context "when no errors are raised" do before do post.tags.delete(tag) end it "executes the callback" do post.after_remove_called.should be_true end it "removes the document from the relation" do post.tags.should be_empty end end context "when errors are raised" do before do post.should_receive(:after_remove_tag).and_raise end it "removes the document from the relation" do expect { post.tags.delete(tag) }.to raise_error post.tags.should be_empty end end end end end [ :delete_all, :destroy_all ].each do |method| describe "##{method}" do context "when the relation is not polymorphic" do context "when conditions are provided" do let(:person) do Person.create end let!(:preference_one) do person.preferences.create(name: "Testing") end let!(:preference_two) do person.preferences.create(name: "Test") end let!(:deleted) do person.preferences.send( method, { name: "Testing" } ) end it "removes the correct preferences" do person.preferences.count.should eq(1) end it "deletes the documents from the database" do Preference.where(name: "Testing").count.should eq(0) end it "returns the number of documents deleted" do deleted.should eq(1) end it "removes the ids from the foreign key" do person.preference_ids.should eq([ preference_two.id ]) end end context "when conditions are not provided" do let(:person) do Person.create.tap do |person| person.preferences.create(name: "Testing") person.preferences.create(name: "Test") end end let!(:deleted) do person.preferences.send(method) end it "removes the correct preferences" do person.preferences.count.should eq(0) end it "deletes the documents from the database" do Preference.count.should eq(0) end it "returns the number of documents deleted" do deleted.should eq(2) end end end end end describe ".eager_load" do before do Mongoid.identity_map_enabled = true end after do Mongoid.identity_map_enabled = false end context "when the relation is not polymorphic" do let!(:person) do Person.create end let!(:preference) do person.preferences.create(name: "testing") end let(:metadata) do Person.relations["preferences"] end let(:ids) do [ preference.id ] end let!(:eager) do described_class.eager_load(metadata, ids) end let(:map) do Mongoid::IdentityMap.get(Preference, ids) end it "puts the documents in the identity map" do map.should eq([ preference ]) end end end describe ".embedded?" do it "returns false" do described_class.should_not be_embedded end end describe "#exists?" do let!(:person) do Person.create end context "when documents exist in the database" do before do person.preferences.create end it "returns true" do person.preferences.exists?.should be_true end end context "when no documents exist in the database" do before do person.preferences.build end it "returns false" do person.preferences.exists?.should be_false end end end describe "#find" do context "when the relation is not polymorphic" do let(:person) do Person.create end let!(:preference_one) do person.preferences.create(name: "Test") end let!(:preference_two) do person.preferences.create(name: "OMG I has relations") end let!(:unrelated_pref) do Preference.create(name: "orphan annie") end let!(:unrelated_pref_two) do Preference.create(name: "orphan two") end context "when providing an id" do context "when the id matches" do let(:preference) do person.preferences.find(preference_one.id) end it "returns the matching document" do preference.should eq(preference_one) end end context "when the id matches an unreferenced document" do let(:preference) do person.preferences.find(unrelated_pref.id) end it "raises an error" do expect { preference }.to raise_error(Mongoid::Errors::DocumentNotFound) end end context "when the id does not match" do context "when config set to raise error" do before do Mongoid.raise_not_found_error = true end it "raises an error" do expect { person.preferences.find(Moped::BSON::ObjectId.new) }.to raise_error(Mongoid::Errors::DocumentNotFound) end end context "when config set not to raise error" do let(:preference) do person.preferences.find(Moped::BSON::ObjectId.new) end before do Mongoid.raise_not_found_error = false end after do Mongoid.raise_not_found_error = true end it "returns nil" do preference.should be_nil end end end end context "when providing an array of ids" do context "when the ids match" do let(:preferences) do person.preferences.find([ preference_one.id, preference_two.id ]) end it "returns the matching documents" do preferences.should eq([ preference_one, preference_two ]) end end context "when the ids matche unreferenced documents" do let(:preferences) do person.preferences.find( [ unrelated_pref.id, unrelated_pref_two.id ] ) end it "raises an error" do expect { preferences }.to raise_error(Mongoid::Errors::DocumentNotFound) end end context "when the ids do not match" do context "when config set to raise error" do before do Mongoid.raise_not_found_error = true end it "raises an error" do expect { person.preferences.find([ Moped::BSON::ObjectId.new ]) }.to raise_error(Mongoid::Errors::DocumentNotFound) end end context "when config set not to raise error" do let(:preferences) do person.preferences.find([ Moped::BSON::ObjectId.new ]) end before do Mongoid.raise_not_found_error = false end after do Mongoid.raise_not_found_error = true end it "returns an empty array" do preferences.should be_empty end end end end end end describe "#find_or_create_by" do context "when the relation is not polymorphic" do let(:person) do Person.create end let!(:preference) do person.preferences.create(name: "Testing") end context "when the document exists" do let(:found) do person.preferences.find_or_create_by(name: "Testing") end it "returns the document" do found.should eq(preference) end end context "when the document does not exist" do let(:found) do person.preferences.find_or_create_by(name: "Test") end it "sets the new document attributes" do found.name.should eq("Test") end it "returns a newly persisted document" do found.should be_persisted end end end end describe "#find_or_initialize_by" do context "when the relation is not polymorphic" do let(:person) do Person.create end let!(:preference) do person.preferences.create(name: "Testing") end context "when the document exists" do let(:found) do person.preferences.find_or_initialize_by(name: "Testing") end it "returns the document" do found.should eq(preference) end end context "when the document does not exist" do let(:found) do person.preferences.find_or_initialize_by(name: "Test") end it "sets the new document attributes" do found.name.should eq("Test") end it "returns a non persisted document" do found.should_not be_persisted end end end end describe ".foreign_key_suffix" do it "returns _ids" do described_class.foreign_key_suffix.should eq("_ids") end end describe ".macro" do it "returns has_and_belongs_to_many" do described_class.macro.should eq(:has_and_belongs_to_many) end end describe "#max" do let(:person) do Person.create end let(:preference_one) do Preference.create(ranking: 5) end let(:preference_two) do Preference.create(ranking: 10) end before do person.preferences.push(preference_one, preference_two) end let(:max) do person.preferences.max do |a,b| a.ranking <=> b.ranking end end it "returns the document with the max value of the supplied field" do max.should eq(preference_two) end end describe "#max_by" do let(:person) do Person.create end let(:preference_one) do Preference.create(ranking: 5) end let(:preference_two) do Preference.create(ranking: 10) end before do person.preferences.push(preference_one, preference_two) end let(:max) do person.preferences.max_by(&:ranking) end it "returns the document with the max value of the supplied field" do max.should eq(preference_two) end end describe "#method_missing" do let!(:person) do Person.create end let!(:preference_one) do person.preferences.create(name: "First", value: "Posting") end let!(:preference_two) do person.preferences.create(name: "Second", value: "Testing") end let!(:unrelated) do Preference.create(name: "Third") end context "when providing a single criteria" do let(:preferences) do person.preferences.where(name: "First") end it "applies the criteria to the documents" do preferences.should eq([ preference_one ]) end end context "when providing a criteria on id" do let(:preferences) do person.preferences.where(_id: unrelated.id) end it "does not return unrelated documents" do preferences.should be_empty end end context "when providing a criteria class method" do let(:preferences) do person.preferences.posting end it "applies the criteria to the documents" do preferences.should eq([ preference_one ]) end end context "when chaining criteria" do let(:preferences) do person.preferences.posting.where(:name.in => [ "First" ]) end it "applies the criteria to the documents" do preferences.should eq([ preference_one ]) end end context "when delegating methods" do describe "#distinct" do it "returns the distinct values for the fields" do person.preferences.distinct(:name).should =~ [ "First", "Second"] end context "when the inverse relation is not defined" do let!(:house) do person.houses.create(name: "Wayne Manor") end it "returns the distinct values for the fields" do person.houses.distinct(:name).should eq([ house.name ]) end end end end end describe "#min" do let(:person) do Person.create end let(:preference_one) do Preference.create(ranking: 5) end let(:preference_two) do Preference.create(ranking: 10) end before do person.preferences.push(preference_one, preference_two) end let(:min) do person.preferences.min do |a, b| a.ranking <=> b.ranking end end it "returns the min value of the supplied field" do min.should eq(preference_one) end end describe "#min_by" do let(:person) do Person.create end let(:preference_one) do Preference.create(ranking: 5) end let(:preference_two) do Preference.create(ranking: 10) end before do person.preferences.push(preference_one, preference_two) end let(:min) do person.preferences.min_by(&:ranking) end it "returns the min value of the supplied field" do min.should eq(preference_one) end end describe "#nil?" do it "returns false" do Person.new.preferences.should_not be_nil end end describe "#nullify_all" do let(:person) do Person.create end let!(:preference_one) do person.preferences.create(name: "One") end let!(:preference_two) do person.preferences.create(name: "Two") end before do person.preferences.nullify_all end it "removes the foreign key from the base document" do [ preference_one, preference_two ].each do |preference| person.preference_ids.should_not include(preference.id) end end it "removes the foreign key from the target documents" do [ preference_one, preference_two ].each do |preference| preference.person_ids.should_not include(person.id) end end it "removes the reference from the base document" do [ preference_one, preference_two ].each do |preference| person.preferences.should_not include(preference) end end it "removes the reference from the target documents" do [ preference_one, preference_two ].each do |preference| preference.people.should_not include(person) end end it "saves the documents" do preference_one.reload.people.should_not include(person) end end describe "#respond_to?" do let(:person) do Person.new end let(:preferences) do person.preferences end Array.public_instance_methods.each do |method| context "when checking #{method}" do it "returns true" do preferences.respond_to?(method).should be_true end end end Mongoid::Relations::Referenced::Many.public_instance_methods.each do |method| context "when checking #{method}" do it "returns true" do preferences.respond_to?(method).should be_true end end end Preference.scopes.keys.each do |method| context "when checking #{method}" do it "returns true" do preferences.respond_to?(method).should be_true end end end end describe ".stores_foreign_key?" do it "returns true" do described_class.stores_foreign_key?.should be_true end end describe "#scoped" do let(:person) do Person.new end let(:scoped) do person.preferences.scoped end it "returns the relation criteria" do scoped.should be_a(Mongoid::Criteria) end it "returns with an empty selector" do scoped.selector.should eq({ "$and" => [{ "_id" => { "$in" => [] }}]}) end end [ :size, :length ].each do |method| describe "##{method}" do let(:person) do Person.create end context "when documents have been persisted" do let!(:preference) do person.preferences.create(name: "Testing") end it "returns the number of documents" do person.preferences.send(method).should eq(1) end end context "when documents have not been persisted" do before do person.preferences.build(name: "Test") person.preferences.create(name: "Test 2") end it "returns the total number of documents" do person.preferences.send(method).should eq(2) end end end end describe "#unscoped" do context "when the relation has no default scope" do let!(:person) do Person.create end let!(:preference_one) do person.preferences.create(name: "first") end let!(:preference_two) do Preference.create(name: "second") end let(:unscoped) do person.preferences.unscoped end it "returns only the associated documents" do unscoped.should eq([ preference_one ]) end end context "when the relation has a default scope" do let!(:person) do Person.create end let!(:house_one) do person.houses.create(name: "first") end let!(:house_two) do House.create(name: "second") end let(:unscoped) do person.houses.unscoped end it "only returns associated documents" do unscoped.should eq([ house_one ]) end it "removes the default scoping options" do unscoped.options.should eq({}) end end end describe ".valid_options" do it "returns the valid options" do described_class.valid_options.should eq( [ :after_add, :after_remove, :autosave, :before_add, :before_remove, :dependent, :foreign_key, :index, :order, :primary_key ] ) end end describe ".validation_default" do it "returns true" do described_class.validation_default.should be_true end end context "when setting the ids directly after the documents" do let!(:person) do Person.create!(title: "The Boss") end let!(:girlfriend_house) do House.create!(name: "Girlfriend") end let!(:wife_house) do House.create!(name: "Wife") end let!(:exwife_house) do House.create!(name: "Ex-Wife") end before do person.update_attributes( houses: [ wife_house, exwife_house, girlfriend_house ] ) person.update_attributes(house_ids: [ girlfriend_house.id ]) end context "when reloading" do it "properly sets the references" do person.houses(true).should eq([ girlfriend_house ]) end end end context "when setting both sides in a single call" do context "when the documents are new" do let(:user) do User.new(name: "testing") end let(:business) do Business.new(name: "serious", owners: [ user ]) end before do user.businesses = [ business ] end it "sets the businesses" do user.businesses.should eq([ business ]) end it "sets the inverse users" do user.businesses.first.owners.first.should eq(user) end it "sets the inverse businesses" do business.owners.should eq([ user ]) end end context "when one side is persisted" do let!(:user) do User.new(name: "testing") end let!(:business) do Business.create(name: "serious", owners: [ user ]) end before do user.businesses = [ business ] end it "sets the businesses" do user.businesses.should eq([ business ]) end it "sets the inverse users" do user.businesses.first.owners.first.should eq(user) end it "sets the inverse businesses" do business.owners.should eq([ user ]) end context "when reloading" do before do user.reload business.reload end it "persists the businesses" do user.businesses.should eq([ business ]) end it "persists the inverse users" do user.businesses.first.owners.first.should eq(user) end it "persists the inverse businesses" do business.owners.should eq([ user ]) end end end context "when the documents are persisted" do let(:user) do User.create(name: "tst") end let(:business) do Business.create(name: "srs", owners: [ user ]) end before do user.businesses = [ business ] end it "sets the businesses" do user.businesses.should eq([ business ]) end it "sets the inverse users" do user.businesses.first.owners.first.should eq(user) end it "sets the inverse businesses" do business.owners.should eq([ user ]) end context "when reloading" do before do user.reload business.reload end it "persists the businesses" do user.businesses.should eq([ business ]) end it "persists the inverse users" do user.businesses.first.owners.first.should eq(user) end it "persists the inverse businesses" do business.owners.should eq([ user ]) end end end end context "when binding the relation multiple times" do let(:person) do Person.create end let(:preference) do person.preferences.create(name: "testing") end before do 2.times do person.preferences.each do |preference| preference.person_ids.should eq([ person.id ]) end end end it "does not duplicate foreign keys" do person.preference_ids.should eq([ preference.id ]) end end context "when the association has order criteria" do let(:person) do Person.create end let(:preference_one) do OrderedPreference.create(name: 'preference-1', value: 10) end let(:preference_two) do OrderedPreference.create(name: 'preference-2', value: 20) end let(:preference_three) do OrderedPreference.create(name: 'preference-3', value: 20) end before do person.ordered_preferences.nullify_all person.ordered_preferences.push(preference_one, preference_two, preference_three) end it "orders the documents" do person.ordered_preferences(true).should eq( [preference_two, preference_three, preference_one] ) end it "chains default criteria with additional" do person.ordered_preferences.order_by(:name.desc).to_a.should eq( [preference_three, preference_two, preference_one] ) end end context "when the parent is not a new record and freshly loaded" do let(:person) do Person.create end let(:preference) do Preference.new end before do person.preferences = [ preference ] person.save person.reload person.preferences = nil end it "sets the relation to an empty array" do person.preferences.should be_empty end it "removes the foreign key values" do person.preference_ids.should be_empty end it "does not delete the target from the database" do expect { preference.reload }.not_to raise_error(Mongoid::Errors::DocumentNotFound) end end context "when reloading the relation" do let!(:person) do Person.create end let!(:preference_one) do Preference.create(name: "one") end let!(:preference_two) do Preference.create(name: "two") end before do person.preferences << preference_one end context "when the relation references the same documents" do before do Preference.collection.find({ _id: preference_one.id }). update({ "$set" => { name: "reloaded" }}) end let(:reloaded) do person.preferences(true) end it "reloads the document from the database" do reloaded.first.name.should eq("reloaded") end end context "when the relation references different documents" do before do person.preferences << preference_two end let(:reloaded) do person.preferences(true) end it "reloads the new document from the database" do reloaded.should eq([ preference_one, preference_two ]) end end end context "when adding to a relation via a field setter" do context "when the document is new" do let!(:person) do Person.create(preference_names: "one, two") end let(:preference_one) do person.reload.preferences.first end let(:preference_two) do person.reload.preferences.last end it "persists the first preference" do preference_one.should_not be_nil end it "sets the first inverse" do preference_one.people.should eq([ person ]) end it "persists the second preference" do preference_two.should_not be_nil end it "sets the second inverse keys" do preference_two.people.should eq([ person ]) end end end context "when changing the order of existing ids" do let(:person) do Person.new end let(:preference_one) do Preference.create(name: "one") end let(:preference_two) do Preference.create(name: "two") end before do person.preference_ids = [ preference_one.id, preference_two.id ] person.save end context "and the order is changed" do before do person.preference_ids = [ preference_two.id, preference_one.id ] person.save end let(:reloaded) do Person.find(person.id) end it "persists the change in id order" do reloaded.preference_ids.should eq( [ preference_two.id, preference_one.id ] ) end end context "and the order is changed and an element is added" do let(:preference_three) do Preference.create(name: "three") end before do person.preference_ids = [ preference_two.id, preference_one.id, preference_three.id ] person.save end let(:reloaded) do Person.find(person.id) end it "also persists the change in id order" do reloaded.preference_ids.should eq( [ preference_two.id, preference_one.id, preference_three.id ] ) end end context "and the order is changed and an element is removed" do let(:preference_three) do Preference.create(name: "three") end before do person.preference_ids = [ preference_one.id, preference_two.id, preference_three.id ] person.save person.preference_ids = [ preference_three.id, preference_two.id ] person.save end let(:reloaded) do Person.find(person.id) end it "also persists the change in id order" do reloaded.preference_ids.should eq( [ preference_three.id, preference_two.id ] ) end end end context "when adding a document" do let(:person) do Person.new end let(:preference_one) do Preference.new end let(:first_add) do person.preferences.push(preference_one) end context "when chaining a second add" do let(:preference_two) do Preference.new end let(:result) do first_add.push(preference_two) end it "adds both documents" do result.should eq([ preference_one, preference_two ]) end end end context "when setting the relation via the foreign key" do context "when the relation exists" do let!(:person) do Person.create end let!(:pref_one) do person.preferences.create end let!(:pref_two) do Preference.create end before do person.preference_ids = [ pref_two.id ] end it "sets the new documents on the relation" do person.preferences.should eq([ pref_two ]) end end end context "when using a different primary key" do let(:dog) do Dog.create(name: 'Doggie') end let(:cat) do Cat.create(name: 'Kitty') end let(:fire_hydrant) do FireHydrant.create(location: '221B Baker Street') end context "when adding to a one-way many to many" do before do fire_hydrant.cats.push(cat) end it "adds the pk value to the fk set" do expect(fire_hydrant.cat_ids).to eq([cat.name]) end end context "when adding to a two-way many to many" do before do fire_hydrant.dogs.push(dog) end it "adds the pk value to the fk set" do expect(fire_hydrant.dog_ids).to eq([dog.name]) end it "adds the base pk value to the inverse fk set" do expect(dog.fire_hydrant_ids).to eq([fire_hydrant.location]) end end context "when deleting from a two-way many to many" do before do dog.fire_hydrants.push(fire_hydrant) fire_hydrant.dogs.delete(dog) end it "removes the pk value from the fk set" do expect(fire_hydrant.dog_ids).to eq([]) end it "removes the base pk value from the inverse fk set" do expect(dog.fire_hydrant_ids).to eq([]) end end end end