bigrecord 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.rdoc +44 -0
  3. data/Rakefile +17 -0
  4. data/VERSION +1 -0
  5. data/doc/bigrecord_specs.rdoc +36 -0
  6. data/doc/getting_started.rdoc +157 -0
  7. data/examples/bigrecord.yml +25 -0
  8. data/generators/bigrecord/bigrecord_generator.rb +17 -0
  9. data/generators/bigrecord/templates/bigrecord.rake +47 -0
  10. data/generators/bigrecord_migration/bigrecord_migration_generator.rb +13 -0
  11. data/generators/bigrecord_migration/templates/migration.rb +9 -0
  12. data/generators/bigrecord_model/bigrecord_model_generator.rb +28 -0
  13. data/generators/bigrecord_model/templates/migration.rb +13 -0
  14. data/generators/bigrecord_model/templates/model.rb +7 -0
  15. data/generators/bigrecord_model/templates/model_spec.rb +12 -0
  16. data/init.rb +9 -0
  17. data/install.rb +22 -0
  18. data/lib/big_record/abstract_base.rb +1088 -0
  19. data/lib/big_record/action_view_extensions.rb +266 -0
  20. data/lib/big_record/ar_associations/association_collection.rb +194 -0
  21. data/lib/big_record/ar_associations/association_proxy.rb +158 -0
  22. data/lib/big_record/ar_associations/belongs_to_association.rb +57 -0
  23. data/lib/big_record/ar_associations/belongs_to_many_association.rb +57 -0
  24. data/lib/big_record/ar_associations/has_and_belongs_to_many_association.rb +164 -0
  25. data/lib/big_record/ar_associations/has_many_association.rb +191 -0
  26. data/lib/big_record/ar_associations/has_one_association.rb +80 -0
  27. data/lib/big_record/ar_associations.rb +1608 -0
  28. data/lib/big_record/ar_reflection.rb +223 -0
  29. data/lib/big_record/attribute_methods.rb +75 -0
  30. data/lib/big_record/base.rb +618 -0
  31. data/lib/big_record/br_associations/association_collection.rb +194 -0
  32. data/lib/big_record/br_associations/association_proxy.rb +153 -0
  33. data/lib/big_record/br_associations/belongs_to_association.rb +52 -0
  34. data/lib/big_record/br_associations/belongs_to_many_association.rb +293 -0
  35. data/lib/big_record/br_associations/cached_item_proxy.rb +194 -0
  36. data/lib/big_record/br_associations/cached_item_proxy_factory.rb +62 -0
  37. data/lib/big_record/br_associations/has_and_belongs_to_many_association.rb +168 -0
  38. data/lib/big_record/br_associations/has_one_association.rb +80 -0
  39. data/lib/big_record/br_associations.rb +978 -0
  40. data/lib/big_record/br_reflection.rb +151 -0
  41. data/lib/big_record/callbacks.rb +367 -0
  42. data/lib/big_record/connection_adapters/abstract/connection_specification.rb +279 -0
  43. data/lib/big_record/connection_adapters/abstract/database_statements.rb +175 -0
  44. data/lib/big_record/connection_adapters/abstract/quoting.rb +58 -0
  45. data/lib/big_record/connection_adapters/abstract_adapter.rb +190 -0
  46. data/lib/big_record/connection_adapters/column.rb +491 -0
  47. data/lib/big_record/connection_adapters/hbase_adapter.rb +432 -0
  48. data/lib/big_record/connection_adapters/view.rb +27 -0
  49. data/lib/big_record/connection_adapters.rb +10 -0
  50. data/lib/big_record/deletion.rb +73 -0
  51. data/lib/big_record/dynamic_schema.rb +92 -0
  52. data/lib/big_record/embedded.rb +71 -0
  53. data/lib/big_record/embedded_associations/association_proxy.rb +148 -0
  54. data/lib/big_record/family_span_columns.rb +89 -0
  55. data/lib/big_record/fixtures.rb +1025 -0
  56. data/lib/big_record/migration.rb +380 -0
  57. data/lib/big_record/routing_ext.rb +65 -0
  58. data/lib/big_record/timestamp.rb +51 -0
  59. data/lib/big_record/validations.rb +830 -0
  60. data/lib/big_record.rb +125 -0
  61. data/lib/bigrecord.rb +1 -0
  62. data/rails/init.rb +9 -0
  63. data/spec/connections/bigrecord.yml +13 -0
  64. data/spec/connections/cassandra/connection.rb +2 -0
  65. data/spec/connections/hbase/connection.rb +2 -0
  66. data/spec/debug.log +281 -0
  67. data/spec/integration/br_associations_spec.rb +80 -0
  68. data/spec/lib/animal.rb +12 -0
  69. data/spec/lib/book.rb +10 -0
  70. data/spec/lib/broken_migrations/duplicate_name/20090706182535_add_animals_table.rb +14 -0
  71. data/spec/lib/broken_migrations/duplicate_name/20090706193019_add_animals_table.rb +9 -0
  72. data/spec/lib/broken_migrations/duplicate_version/20090706190623_add_books_table.rb +9 -0
  73. data/spec/lib/broken_migrations/duplicate_version/20090706190623_add_companies_table.rb +9 -0
  74. data/spec/lib/company.rb +14 -0
  75. data/spec/lib/embedded/web_link.rb +12 -0
  76. data/spec/lib/employee.rb +33 -0
  77. data/spec/lib/migrations/20090706182535_add_animals_table.rb +13 -0
  78. data/spec/lib/migrations/20090706190623_add_books_table.rb +15 -0
  79. data/spec/lib/migrations/20090706193019_add_companies_table.rb +14 -0
  80. data/spec/lib/migrations/20090706194512_add_employees_table.rb +13 -0
  81. data/spec/lib/migrations/20090706195741_add_zoos_table.rb +13 -0
  82. data/spec/lib/novel.rb +5 -0
  83. data/spec/lib/zoo.rb +17 -0
  84. data/spec/spec.opts +4 -0
  85. data/spec/spec_helper.rb +55 -0
  86. data/spec/unit/abstract_base_spec.rb +287 -0
  87. data/spec/unit/adapters/abstract_adapter_spec.rb +56 -0
  88. data/spec/unit/adapters/adapter_shared_spec.rb +51 -0
  89. data/spec/unit/adapters/hbase_adapter_spec.rb +15 -0
  90. data/spec/unit/ar_associations_spec.rb +8 -0
  91. data/spec/unit/base_spec.rb +6 -0
  92. data/spec/unit/br_associations_spec.rb +58 -0
  93. data/spec/unit/embedded_spec.rb +43 -0
  94. data/spec/unit/find_spec.rb +34 -0
  95. data/spec/unit/hash_helper_spec.rb +44 -0
  96. data/spec/unit/migration_spec.rb +144 -0
  97. data/spec/unit/model_spec.rb +315 -0
  98. data/spec/unit/validations_spec.rb +182 -0
  99. data/tasks/bigrecord_tasks.rake +47 -0
  100. data/tasks/data_store.rb +46 -0
  101. data/tasks/gem.rb +22 -0
  102. data/tasks/rdoc.rb +8 -0
  103. data/tasks/spec.rb +34 -0
  104. metadata +189 -0
@@ -0,0 +1,58 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
2
+
3
+ describe BigRecord::BrAssociations do
4
+
5
+ # Clear the tables before and after these tests
6
+ before(:all) do
7
+ Animal.delete_all
8
+ Employee.delete_all
9
+ Zoo.delete_all
10
+ end
11
+
12
+ it "should list associations in #reflections" do
13
+ Animal.reflections.should have_key(:zoo)
14
+ Animal.reflections.should have_key(:books)
15
+
16
+ Animal.reflections[:zoo].macro.should == :belongs_to_big_record
17
+ Animal.reflections[:books].macro.should == :belongs_to_many
18
+
19
+ Employee.reflections.should have_key(:company)
20
+ Employee.reflections[:company].macro.should == :belongs_to_big_record
21
+
22
+ Zoo.reflections.should have_key(:animals)
23
+ Zoo.reflections[:animals].macro.should == :belongs_to_many
24
+ end
25
+
26
+ it "should mixin all the helper methods into the model for :belongs_to associations" do
27
+ animal = Animal.new
28
+
29
+ animal.should respond_to(:zoo)
30
+ animal.should respond_to(:zoo=)
31
+ animal.should respond_to(:build_zoo)
32
+ animal.should respond_to(:create_zoo)
33
+ end
34
+
35
+ it "should mixin all the helper methods into the model for :belongs_to_many associations" do
36
+ zoo = Zoo.new
37
+
38
+ zoo.should respond_to(:animals)
39
+ zoo.should respond_to(:animals=)
40
+ zoo.should respond_to(:animal_ids)
41
+ zoo.should respond_to(:animal_ids=)
42
+ zoo.animals.should respond_to(:<<)
43
+ zoo.animals.should respond_to(:delete)
44
+ zoo.animals.should respond_to(:clear)
45
+ zoo.animals.should respond_to(:empty?)
46
+ zoo.animals.should respond_to(:size)
47
+ end
48
+
49
+ it "should mixin build() and create() methods into collection assocations" do
50
+ pending "This needs to be implemented"
51
+
52
+ zoo = Zoo.new
53
+
54
+ zoo.animals.should respond_to(:build)
55
+ zoo.animals.should respond_to(:create)
56
+ end
57
+
58
+ end
@@ -0,0 +1,43 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
2
+ require File.expand_path(File.join(File.dirname(__FILE__), 'abstract_base_spec'))
3
+
4
+ describe BigRecord::Embedded do
5
+
6
+ # Clear the tables before and after these tests
7
+ before(:all) do
8
+ Zoo.delete_all
9
+ end
10
+
11
+ after(:all) do
12
+ Zoo.delete_all
13
+ end
14
+
15
+ it_should_behave_like "BigRecord::AbstractBase"
16
+
17
+ describe "embedded within a BigRecord::Base model" do
18
+
19
+ it "should save successfully" do
20
+ zoo = Zoo.new( :name => "African Lion Safari",
21
+ :address => "RR #1 Cambridge, Ontario Canada\nN1R 5S2",
22
+ :description => "Canada's Original Safari Adventure")
23
+
24
+ zoo.weblink = Embedded::WebLink.new(:title => "African Lion Safari - Wikipedia", :url => "http://en.wikipedia.org/wiki/African_Lion_Safari")
25
+ zoo.save.should be_true
26
+ zoo.reload
27
+
28
+ zoo.weblink.should_not be_nil
29
+ zoo.weblink.should be_a_kind_of(Embedded::WebLink)
30
+ zoo.weblink.title.should == "African Lion Safari - Wikipedia"
31
+ zoo.weblink.url.should == "http://en.wikipedia.org/wiki/African_Lion_Safari"
32
+
33
+ zoo.weblink = Embedded::WebLink.new(:title => "African Lion Safari", :url => "http://www.lionsafari.com/")
34
+ zoo.save.should be_true
35
+ zoo.reload
36
+
37
+ zoo.weblink.title.should == "African Lion Safari"
38
+ zoo.weblink.url.should == "http://www.lionsafari.com/"
39
+ end
40
+
41
+ end
42
+
43
+ end
@@ -0,0 +1,34 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
2
+
3
+ describe BigRecord::Base do
4
+
5
+ describe "#find" do
6
+
7
+ it "should dispatch properly to #find_every when given :first" do
8
+ zoo = Zoo.new
9
+
10
+ Zoo.should_receive(:find_every).with(hash_including(:limit => 1)).and_return([zoo])
11
+
12
+ Zoo.find(:first).should == zoo
13
+ end
14
+
15
+ it "should dispatch properly to #find_every when given :all" do
16
+ zoo = Zoo.new
17
+
18
+ Zoo.should_receive(:find_every).and_return([zoo])
19
+
20
+ Zoo.find(:all).should == [zoo]
21
+ end
22
+
23
+ it "should dispatch properly to #find_from_ids when given anything else" do
24
+ zoo = Zoo.new
25
+ id = "c6e2cf62-332d-44f0-a558-dfdfe2c7ee1e"
26
+
27
+ Zoo.should_receive(:find_from_ids).with([id], an_instance_of(Hash)).and_return([zoo])
28
+
29
+ Zoo.find(id).should == [zoo]
30
+ end
31
+
32
+ end
33
+
34
+ end
@@ -0,0 +1,44 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
2
+
3
+ # Not exactly the most comprehensive testing for this function.
4
+ describe Hash do
5
+
6
+ before(:each) do
7
+ @hash1 = { :key1 => "value1", :key2 => "value2", :key3 => "value3" }
8
+ @hash2 = { :key1 => "value1", :key2 => "value2", :key3 => "value3", :key4 => "value4" }
9
+ @hash3 = { :key1 => "value4", :key2 => "value3", :key3 => "value1", :key4 => "value2" }
10
+ @hash4 = { :key2 => "value2", :key3 => "value3" }
11
+ end
12
+
13
+ it "#subset_of? should compare 2 hashes correctly (when one really is a subset of the other)" do
14
+ @hash1.subset_of?(@hash2).should be_true
15
+ @hash2.subset_of?(@hash1).should be_false
16
+ end
17
+
18
+ it "#superset_of? should compare 2 hashes correctly (when one really is a superset of the other)" do
19
+ @hash1.superset_of?(@hash2).should be_false
20
+ @hash2.superset_of?(@hash1).should be_true
21
+ end
22
+
23
+ it "#subset_of? and #superset_of? should be true when comparing the same hash to itself" do
24
+ @hash1.subset_of?(@hash1).should be_true
25
+ @hash1.superset_of?(@hash1).should be_true
26
+
27
+ @hash2.subset_of?(@hash2).should be_true
28
+ @hash2.superset_of?(@hash2).should be_true
29
+ end
30
+
31
+ it "should return false when there's a mismatch of key/value pairs" do
32
+ @hash2.subset_of?(@hash3).should be_false
33
+ @hash2.superset_of?(@hash3).should be_false
34
+ end
35
+
36
+ it "should compare properly with missing keys in one of the hashes (even if all the other pairs match)" do
37
+ # false because @hash4 is missing :key1
38
+ @hash1.subset_of?(@hash4).should be_false
39
+
40
+ # it is a superset because all of the key/value pairs of @hash4 are contained within @hash1
41
+ @hash1.superset_of?(@hash4).should be_true
42
+ end
43
+
44
+ end
@@ -0,0 +1,144 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
2
+
3
+ describe BigRecord::Migration do
4
+
5
+ before(:each) do
6
+ @migrations_path = File.expand_path(File.join(File.dirname(__FILE__), "..", "lib", "migrations"))
7
+ @migration_files = Dir["#{@migrations_path}/[0-9]*_*.rb"]
8
+
9
+ @broken_migrations_path = File.expand_path(File.join(File.dirname(__FILE__), "..", "lib", "broken_migrations"))
10
+ @broken_migration_files = Dir["#{@broken_migrations_path}/[0-9]*_*.rb"]
11
+
12
+ # It doesn't matter whether the adapter works for this spec, so we'll mock it
13
+ @mock_connection = mock(BigRecord::ConnectionAdapters::AbstractAdapter, :null_object => true)
14
+ @mock_connection.stub!(:supports_ddl_transactions?).and_return(false)
15
+
16
+ # Replace BigRecord::Base.connection to always return the mock_connection
17
+ BigRecord::Base.stub!(:connection).and_return(@mock_connection)
18
+
19
+ # We don't want it outputting to stdout
20
+ BigRecord::Migration.verbose = false
21
+ end
22
+
23
+ describe "class methods and initialization" do
24
+
25
+ it "#proper_table_name should return the corresponding table name for the data store (with different arguments types)" do
26
+ # Check that it works with a symbol, BigRecord model, or string.
27
+ BigRecord::Migrator.proper_table_name(:animals).should == "animals"
28
+ BigRecord::Migrator.proper_table_name(Animal).should == "animals"
29
+ BigRecord::Migrator.proper_table_name("animals").should == "animals"
30
+ end
31
+
32
+ it "#get_all_versions should query from the data store" do
33
+ @mock_connection.should_receive(:get_all_schema_versions).and_return(["version1"])
34
+
35
+ BigRecord::Migrator.get_all_versions.should == ["version1"]
36
+ end
37
+
38
+ it "should initialize the migrator given a directory of migration files" do
39
+ # Assuming that the adapter supports migrations
40
+ @mock_connection.should_receive(:supports_migrations?).and_return(true)
41
+
42
+ # Setting up the migrator will initialize the schema migration table
43
+ @mock_connection.should_receive(:initialize_schema_migrations_table)
44
+
45
+ # Initializing the migrator
46
+ migrator = BigRecord::Migrator.new(:up, @migrations_path)
47
+
48
+ # Now assuming that the adapter doesn't supports migrations
49
+ @mock_connection.should_receive(:supports_migrations?).and_return(false)
50
+
51
+ # Setting up the migrator should not initialize the schema migration table
52
+ @mock_connection.should_not_receive(:initialize_schema_migrations_table)
53
+
54
+ lambda{
55
+ migrator = BigRecord::Migrator.new(:up, @migrations_path)
56
+ }.should raise_error(StandardError)
57
+ end
58
+
59
+ end
60
+
61
+ describe "migrator methods" do
62
+
63
+ before(:each) do
64
+ # Setting up the migrator will initialize the schema migration table
65
+ @mock_connection.should_receive(:initialize_schema_migrations_table)
66
+ end
67
+
68
+ it "should show all the pending migrations" do
69
+ # Initializing the migrator
70
+ @migrator = BigRecord::Migrator.new(:up, @migrations_path)
71
+
72
+ # And request all the schema versions currently within the data store
73
+ @mock_connection.should_receive(:get_all_schema_versions).and_return([])
74
+
75
+ # Verify that our migrations are listed as pending
76
+ @migration_files.each do |migration_file|
77
+ @migrator.pending_migrations.map(&:filename).should include(migration_file)
78
+ end
79
+ end
80
+
81
+ it "should run the migrations and update the schema migration table in the data store" do
82
+ # Initializing the migrator
83
+ @migrator = BigRecord::Migrator.new(:up, @migrations_path)
84
+
85
+ # And request all the schema versions currently within the data store
86
+ @mock_connection.should_receive(:get_all_schema_versions).and_return([])
87
+
88
+ # The data store will be updated once for each migration file
89
+ @mock_connection.should_receive(:update).exactly(@migration_files.size).times.and_return(true)
90
+ result = @migrator.migrate
91
+
92
+ # The pending migrations should now be listed in the migrated #migrated method and removed from #pending_migrations
93
+ result.size.should == @migration_files.size
94
+ @migrator.migrated.size.should == @migration_files.size
95
+ @migrator.pending_migrations.should be_empty
96
+ end
97
+
98
+ it "should call the appropriate adapter connection methods when migrating :up" do
99
+ # Initializing the migrator
100
+ @migrator = BigRecord::Migrator.new(:up, @migrations_path, 20090706182535) # Hard-coded target. Don't change the migration!
101
+
102
+ # And request all the schema versions currently within the data store
103
+ @mock_connection.should_receive(:get_all_schema_versions).and_return([])
104
+
105
+ @mock_connection.should_receive(:create_table).with("animals", {:force => true}).once.and_return(true)
106
+ @migrator.migrate
107
+ end
108
+
109
+ it "should call the appropriate adapter connection methods when reverting :down" do
110
+ # Initializing the migrator
111
+ @migrator = BigRecord::Migrator.new(:down, @migrations_path) # Hard-coded target. Don't change the migration!
112
+
113
+ # And request all the schema versions currently within the data store.
114
+ @mock_connection.should_receive(:get_all_schema_versions).and_return([20090706182535]) # Hard-coded target. Don't change the migration!
115
+
116
+ @mock_connection.should_receive(:drop_table).with("animals").once.and_return(true)
117
+ @migrator.migrate
118
+ end
119
+
120
+ end
121
+
122
+ describe "error handling" do
123
+
124
+ it "should raise an error on duplicate version numbers" do
125
+ # Initializing the migrator
126
+ @migrator = BigRecord::Migrator.new(:up, @broken_migrations_path+"/duplicate_version")
127
+
128
+ lambda {
129
+ @migrator.migrations
130
+ }.should raise_error(BigRecord::DuplicateMigrationVersionError)
131
+ end
132
+
133
+ it "should raise an error on duplicate migration names" do
134
+ # Initializing the migrator
135
+ @migrator = BigRecord::Migrator.new(:up, @broken_migrations_path+"/duplicate_name")
136
+
137
+ lambda {
138
+ @migrator.migrations
139
+ }.should raise_error(BigRecord::DuplicateMigrationNameError)
140
+ end
141
+
142
+ end
143
+
144
+ end
@@ -0,0 +1,315 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
2
+
3
+ describe BigRecord::Base do
4
+
5
+ # Clear the tables before and after these tests
6
+ before(:all) do
7
+ Book.delete_all
8
+ end
9
+
10
+ after(:all) do
11
+ Book.delete_all
12
+ end
13
+
14
+ it "should provide .id" do
15
+ Book.new.should respond_to(:id)
16
+ end
17
+
18
+ it "should provide hash-like attribute accessors, i.e. [] and []=" do
19
+ Book.new.should respond_to(:[])
20
+ Book.new.should respond_to(:[]=)
21
+ end
22
+
23
+ it 'should provide #create' do
24
+ Book.should respond_to(:create)
25
+ end
26
+
27
+ describe '#create' do
28
+
29
+ it 'should create a new record in the data store' do
30
+ book = Book.create(:title => "I Am Legend", :author => "Richard Matheson")
31
+
32
+ book.should be_a_kind_of(Book)
33
+ book.id.should_not be_nil
34
+ book.new_record?.should be_false
35
+
36
+ book_confirm = Book.find(book.id)
37
+
38
+ book_confirm.title.should == "I Am Legend"
39
+ book_confirm.author.should == "Richard Matheson"
40
+ end
41
+
42
+ it 'should return the unsaved object even if a record could not be created' do
43
+ attributes = {:title => "I Am Legend", :author => "Richard Matheson"}
44
+ book = Book.new(attributes)
45
+
46
+ # Mocking the #create method in Base to return a specific book object we define
47
+ Book.should_receive(:new).and_return(book)
48
+
49
+ # When #save is called on our book object, it'll return false.
50
+ book.should_receive(:save).and_return(false)
51
+
52
+ # Now we'll try the #create method on the Book class
53
+ created_book = Book.create(attributes)
54
+
55
+ # The save shouldn't have succeeded
56
+ created_book.new_record?.should be_true
57
+
58
+ # But we should still receive a book object that's the same
59
+ created_book.should == book
60
+ end
61
+
62
+ end
63
+
64
+ # Protected instance method called by .save (different than Class#create)
65
+ it 'should provide .create' do
66
+ Book.new.should respond_to(:create)
67
+ end
68
+
69
+ # Protected instance method called by .save
70
+ it 'should provide .update' do
71
+ Book.new.should respond_to(:update)
72
+ end
73
+
74
+ it 'should provide .save and .save!' do
75
+ Book.new.should respond_to(:save)
76
+ Book.new.should respond_to(:save!)
77
+ end
78
+
79
+ describe '.save and .save!' do
80
+
81
+ describe 'with a new resource' do
82
+
83
+ it 'should create new entries in the data store' do
84
+ # Create a new object
85
+ book = Book.new( :title => "I Am Legend",
86
+ :author => "Richard Matheson",
87
+ :description => "The most clever and riveting vampire novel since Dracula.")
88
+
89
+ book.new_record?.should be_true
90
+ book.id.should be_nil
91
+ book.save.should be_true
92
+
93
+ book.new_record?.should be_false
94
+ book.id.should_not be_nil
95
+
96
+ # Verify that the object was saved
97
+ book2 = Book.find(book.id)
98
+
99
+ book2.title.should == "I Am Legend"
100
+ book2.author.should == "Richard Matheson"
101
+ book2.description.should == "The most clever and riveting vampire novel since Dracula."
102
+ end
103
+
104
+ it 'should raise an exception with .save! if a record was not saved or true if successful' do
105
+ book = Book.new( :title => "I Am Legend",
106
+ :author => "Richard Matheson",
107
+ :description => "The most clever and riveting vampire novel since Dracula.")
108
+
109
+ # The actual method that's called just before the data store write is #update_big_record, which returns
110
+ # a boolean. We're going to mock this method and have it return false.
111
+ book.should_receive(:update_bigrecord).and_return(false)
112
+
113
+ # Verify that an exception is raised
114
+ lambda { book.save! }.should raise_error(BigRecord::RecordNotSaved)
115
+
116
+ # Verify that true gets returned on success
117
+ book.should_receive(:update_bigrecord).and_return(true)
118
+ book.save.should be_true
119
+ end
120
+
121
+ end
122
+
123
+ describe 'with an existing record' do
124
+
125
+ before(:each) do
126
+ # Just want to verify that the book is created properly everytime
127
+ new_book = Book.new( :title => "I Am Legend",
128
+ :author => "Richard Matheson",
129
+ :description => "The most clever and riveting vampire novel since Dracula.")
130
+
131
+ new_book.save.should be_true
132
+
133
+ # Maybe a little paranoid...
134
+ new_book.new_record?.should be_false
135
+ new_book.id.should_not be_nil
136
+
137
+ # Grab the entry from the data store and verify
138
+ @book = Book.find(new_book)
139
+ @book.title.should == "I Am Legend"
140
+ @book.author.should == "Richard Matheson"
141
+ @book.description.should == "The most clever and riveting vampire novel since Dracula."
142
+ end
143
+
144
+ it 'should update that record' do
145
+ @book.description = "One of the Ten All-Time Best Novels of Vampirism."
146
+ @book.save.should be_true
147
+
148
+ book_verify = Book.find(@book)
149
+ book_verify.description.should == "One of the Ten All-Time Best Novels of Vampirism."
150
+ book_verify.id.should == @book.id
151
+ end
152
+
153
+ end
154
+
155
+ end
156
+
157
+ describe 'modified attribute tracking' do
158
+
159
+ it "should not mark attributes as modified if they are similar" do
160
+ pending "attribute tracking needs to be implemented in BigRecord::Base"
161
+
162
+ attributes = { :title => "I Am Legend",
163
+ :author => "Richard Matheson",
164
+ :description => "The most clever and riveting vampire novel since Dracula." }
165
+
166
+ book = Book.new(attributes)
167
+ book.save.should be_true
168
+
169
+ book.attributes = attributes
170
+
171
+ book.modified_attributes.should be_empty
172
+ end
173
+
174
+ it "should track modified attributes" do
175
+ pending "attribute tracking needs to be implemented in BigRecord::Base"
176
+
177
+ attributes = { :title => "I Am Legend",
178
+ :author => "Richard Matheson",
179
+ :description => "The most clever and riveting vampire novel since Dracula." }
180
+
181
+ book = Book.new(attributes)
182
+ book.save.should be_true
183
+
184
+ book.attributes = {:description => "One of the Ten All-Time Best Novels of Vampirism."}
185
+
186
+ book.modified_attributes.has_key?(:description).should be_true
187
+ end
188
+
189
+ end
190
+
191
+ describe 'attribute functionality' do
192
+
193
+ it "should return a list of attribute names with .attribute_names" do
194
+ (Book.new.attribute_names & ["attribute:author", "attribute:description", "attribute:links", "attribute:title"]).should == ["attribute:author", "attribute:description", "attribute:links", "attribute:title"]
195
+ end
196
+
197
+ it "should provide hash-like attribute accessors, i.e. [] and []=" do
198
+ Book.new.should respond_to(:[])
199
+ Book.new.should respond_to(:[]=)
200
+ end
201
+
202
+ it "should provide attribute accessing with .read_attribute" do
203
+ book = Book.new( :title => "I Am Legend",
204
+ :author => "Richard Matheson",
205
+ :description => "The most clever and riveting vampire novel since Dracula.")
206
+
207
+ book.save.should be_true
208
+
209
+ book.read_attribute("attribute:title").should == "I Am Legend"
210
+ book.read_attribute("attribute:author").should == "Richard Matheson"
211
+ book.read_attribute("attribute:description").should == "The most clever and riveting vampire novel since Dracula."
212
+ end
213
+
214
+ it "should determine whether an attribute is present with .has_attribute?" do
215
+ book = Book.new
216
+
217
+ ["attribute:author", "attribute:description", "attribute:links", "attribute:title"].each do |attr|
218
+ book.has_attribute?(attr).should be_true
219
+ end
220
+ end
221
+
222
+ it "should determine whether an attribute is present (i.e. set either by the user or db) with .attribute_present?" do
223
+ book = Book.new
224
+
225
+ # Initially they should all be false
226
+ ["attribute:author", "attribute:description", "attribute:title"].each do |attr|
227
+ book.attribute_present?(attr).should be_false
228
+ end
229
+
230
+ book.attributes = { :title => "I Am Legend", :author => "Richard Matheson", :description => "The most clever and riveting vampire novel since Dracula." }
231
+
232
+ ["attribute:author", "attribute:description", "attribute:title"].each do |attr|
233
+ book.attribute_present?(attr).should be_true
234
+ end
235
+ end
236
+
237
+ it '.update_attribute(nil) should raise an exception' do
238
+ lambda {
239
+ Book.new.update_attribute(nil)
240
+ }.should raise_error(ArgumentError)
241
+ end
242
+
243
+ it ".update_attribute should update a single attribute of a record" do
244
+ book = Book.new( :title => "I Am Legend",
245
+ :author => "Richard Matheson",
246
+ :description => "The most clever and riveting vampire novel since Dracula.")
247
+
248
+ book.new_record?.should be_true
249
+ book.id.should be_nil
250
+ book.save.should be_true
251
+
252
+ book.update_attribute(:description, "One of the Ten All-Time Best Novels of Vampirism.")
253
+
254
+ book.description.should == "One of the Ten All-Time Best Novels of Vampirism."
255
+ end
256
+
257
+ it ".update_attribute should return false if the attribute could not be updated" do
258
+ book = Book.new( :title => "I Am Legend",
259
+ :author => "Richard Matheson",
260
+ :description => "The most clever and riveting vampire novel since Dracula.")
261
+
262
+ book.new_record?.should be_true
263
+ book.id.should be_nil
264
+ book.save.should be_true
265
+
266
+ book.should_receive(:save).and_return(false)
267
+ book.update_attribute(:description, "One of the Ten All-Time Best Novels of Vampirism.").should be_false
268
+ end
269
+
270
+ describe '' do
271
+
272
+ before(:each) do
273
+ @book = Book.new( :title => "I Am Legend",
274
+ :author => "Richard Matheson",
275
+ :description => "The most clever and riveting vampire novel since Dracula.")
276
+
277
+ @book.new_record?.should be_true
278
+ @book.id.should be_nil
279
+ @book.save.should be_true
280
+
281
+ @new_attributes = {:title => "A Stir of Echoes", :description => "One of the most important writers of the twentieth century."}
282
+ end
283
+
284
+ it ".update_attributes should update all attributes of a record" do
285
+ @book.update_attributes(@new_attributes).should be_true
286
+
287
+ @new_attributes.each do |key, value|
288
+ @book.send(key).should == value
289
+ end
290
+ end
291
+
292
+ it ".update_attributes should return false if the record couldn't be updated with those attributes" do
293
+ @book.should_receive(:save).and_return(false)
294
+ @book.update_attributes(@new_attributes).should be_false
295
+ end
296
+
297
+ it ".update_attributes! should update all attributes of a record" do
298
+ @book.update_attributes(@new_attributes).should be_true
299
+
300
+ @new_attributes.each do |key, value|
301
+ @book.send(key).should == value
302
+ end
303
+ end
304
+
305
+ it ".update_attributes! should raise an error when the record couldn't be updated" do
306
+ @book.should_receive(:save!).and_raise(BigRecord::RecordNotSaved)
307
+
308
+ lambda { @book.update_attributes!(@new_attributes) }.should raise_error(BigRecord::RecordNotSaved)
309
+ end
310
+
311
+ end
312
+
313
+ end
314
+
315
+ end