bigrecord 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +20 -0
- data/README.rdoc +44 -0
- data/Rakefile +17 -0
- data/VERSION +1 -0
- data/doc/bigrecord_specs.rdoc +36 -0
- data/doc/getting_started.rdoc +157 -0
- data/examples/bigrecord.yml +25 -0
- data/generators/bigrecord/bigrecord_generator.rb +17 -0
- data/generators/bigrecord/templates/bigrecord.rake +47 -0
- data/generators/bigrecord_migration/bigrecord_migration_generator.rb +13 -0
- data/generators/bigrecord_migration/templates/migration.rb +9 -0
- data/generators/bigrecord_model/bigrecord_model_generator.rb +28 -0
- data/generators/bigrecord_model/templates/migration.rb +13 -0
- data/generators/bigrecord_model/templates/model.rb +7 -0
- data/generators/bigrecord_model/templates/model_spec.rb +12 -0
- data/init.rb +9 -0
- data/install.rb +22 -0
- data/lib/big_record/abstract_base.rb +1088 -0
- data/lib/big_record/action_view_extensions.rb +266 -0
- data/lib/big_record/ar_associations/association_collection.rb +194 -0
- data/lib/big_record/ar_associations/association_proxy.rb +158 -0
- data/lib/big_record/ar_associations/belongs_to_association.rb +57 -0
- data/lib/big_record/ar_associations/belongs_to_many_association.rb +57 -0
- data/lib/big_record/ar_associations/has_and_belongs_to_many_association.rb +164 -0
- data/lib/big_record/ar_associations/has_many_association.rb +191 -0
- data/lib/big_record/ar_associations/has_one_association.rb +80 -0
- data/lib/big_record/ar_associations.rb +1608 -0
- data/lib/big_record/ar_reflection.rb +223 -0
- data/lib/big_record/attribute_methods.rb +75 -0
- data/lib/big_record/base.rb +618 -0
- data/lib/big_record/br_associations/association_collection.rb +194 -0
- data/lib/big_record/br_associations/association_proxy.rb +153 -0
- data/lib/big_record/br_associations/belongs_to_association.rb +52 -0
- data/lib/big_record/br_associations/belongs_to_many_association.rb +293 -0
- data/lib/big_record/br_associations/cached_item_proxy.rb +194 -0
- data/lib/big_record/br_associations/cached_item_proxy_factory.rb +62 -0
- data/lib/big_record/br_associations/has_and_belongs_to_many_association.rb +168 -0
- data/lib/big_record/br_associations/has_one_association.rb +80 -0
- data/lib/big_record/br_associations.rb +978 -0
- data/lib/big_record/br_reflection.rb +151 -0
- data/lib/big_record/callbacks.rb +367 -0
- data/lib/big_record/connection_adapters/abstract/connection_specification.rb +279 -0
- data/lib/big_record/connection_adapters/abstract/database_statements.rb +175 -0
- data/lib/big_record/connection_adapters/abstract/quoting.rb +58 -0
- data/lib/big_record/connection_adapters/abstract_adapter.rb +190 -0
- data/lib/big_record/connection_adapters/column.rb +491 -0
- data/lib/big_record/connection_adapters/hbase_adapter.rb +432 -0
- data/lib/big_record/connection_adapters/view.rb +27 -0
- data/lib/big_record/connection_adapters.rb +10 -0
- data/lib/big_record/deletion.rb +73 -0
- data/lib/big_record/dynamic_schema.rb +92 -0
- data/lib/big_record/embedded.rb +71 -0
- data/lib/big_record/embedded_associations/association_proxy.rb +148 -0
- data/lib/big_record/family_span_columns.rb +89 -0
- data/lib/big_record/fixtures.rb +1025 -0
- data/lib/big_record/migration.rb +380 -0
- data/lib/big_record/routing_ext.rb +65 -0
- data/lib/big_record/timestamp.rb +51 -0
- data/lib/big_record/validations.rb +830 -0
- data/lib/big_record.rb +125 -0
- data/lib/bigrecord.rb +1 -0
- data/rails/init.rb +9 -0
- data/spec/connections/bigrecord.yml +13 -0
- data/spec/connections/cassandra/connection.rb +2 -0
- data/spec/connections/hbase/connection.rb +2 -0
- data/spec/debug.log +281 -0
- data/spec/integration/br_associations_spec.rb +80 -0
- data/spec/lib/animal.rb +12 -0
- data/spec/lib/book.rb +10 -0
- data/spec/lib/broken_migrations/duplicate_name/20090706182535_add_animals_table.rb +14 -0
- data/spec/lib/broken_migrations/duplicate_name/20090706193019_add_animals_table.rb +9 -0
- data/spec/lib/broken_migrations/duplicate_version/20090706190623_add_books_table.rb +9 -0
- data/spec/lib/broken_migrations/duplicate_version/20090706190623_add_companies_table.rb +9 -0
- data/spec/lib/company.rb +14 -0
- data/spec/lib/embedded/web_link.rb +12 -0
- data/spec/lib/employee.rb +33 -0
- data/spec/lib/migrations/20090706182535_add_animals_table.rb +13 -0
- data/spec/lib/migrations/20090706190623_add_books_table.rb +15 -0
- data/spec/lib/migrations/20090706193019_add_companies_table.rb +14 -0
- data/spec/lib/migrations/20090706194512_add_employees_table.rb +13 -0
- data/spec/lib/migrations/20090706195741_add_zoos_table.rb +13 -0
- data/spec/lib/novel.rb +5 -0
- data/spec/lib/zoo.rb +17 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +55 -0
- data/spec/unit/abstract_base_spec.rb +287 -0
- data/spec/unit/adapters/abstract_adapter_spec.rb +56 -0
- data/spec/unit/adapters/adapter_shared_spec.rb +51 -0
- data/spec/unit/adapters/hbase_adapter_spec.rb +15 -0
- data/spec/unit/ar_associations_spec.rb +8 -0
- data/spec/unit/base_spec.rb +6 -0
- data/spec/unit/br_associations_spec.rb +58 -0
- data/spec/unit/embedded_spec.rb +43 -0
- data/spec/unit/find_spec.rb +34 -0
- data/spec/unit/hash_helper_spec.rb +44 -0
- data/spec/unit/migration_spec.rb +144 -0
- data/spec/unit/model_spec.rb +315 -0
- data/spec/unit/validations_spec.rb +182 -0
- data/tasks/bigrecord_tasks.rake +47 -0
- data/tasks/data_store.rb +46 -0
- data/tasks/gem.rb +22 -0
- data/tasks/rdoc.rb +8 -0
- data/tasks/spec.rb +34 -0
- metadata +189 -0
data/spec/lib/company.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
class Company < BigRecord::Base
|
2
|
+
|
3
|
+
column 'attribute:name', 'string'
|
4
|
+
column 'attribute:address', 'string'
|
5
|
+
column 'attribute:employees', 'integer'
|
6
|
+
column 'attribute:readonly', 'string'
|
7
|
+
|
8
|
+
column 'log:change', 'string', :alias => 'change_log', :collection => true
|
9
|
+
|
10
|
+
attr_create_accessible :name
|
11
|
+
attr_protected :employees
|
12
|
+
attr_readonly :readonly
|
13
|
+
|
14
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
class Employee < BigRecord::Base
|
2
|
+
|
3
|
+
column 'attribute:first_name', :string
|
4
|
+
column 'attribute:middle_name', :string
|
5
|
+
column 'attribute:last_name', :string
|
6
|
+
column 'attribute:email', :string
|
7
|
+
column 'attribute:title', :string
|
8
|
+
column 'attribute:company_id', :string
|
9
|
+
column 'attribute:password', :string
|
10
|
+
column 'attribute:gender', :string # it's not discrimination
|
11
|
+
column 'attribute:age', :integer
|
12
|
+
|
13
|
+
validates_presence_of :first_name, :last_name
|
14
|
+
validates_length_of :first_name, :last_name, :within => 2..50
|
15
|
+
validates_length_of :middle_name, :within => 1..50, :allow_nil => true
|
16
|
+
validates_format_of :first_name, :last_name, :with => /^[\w-]/
|
17
|
+
validates_format_of :middle_name, :with => /^[\w-]/, :allow_nil => true
|
18
|
+
#validates_uniqueness_of :name
|
19
|
+
validates_exclusion_of :first_name, :last_name, :in => %w( admin superuser )
|
20
|
+
validates_exclusion_of :middle_name, :in => %w( admin superuser ), :allow_nil => true
|
21
|
+
|
22
|
+
validates_presence_of :email
|
23
|
+
|
24
|
+
validates_inclusion_of :gender, :in => %w( m f )
|
25
|
+
|
26
|
+
validates_confirmation_of :password
|
27
|
+
|
28
|
+
validates_acceptance_of :contract
|
29
|
+
|
30
|
+
|
31
|
+
belongs_to_big_record :company, :foreign_key => :company_id
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class AddBooksTable < BigRecord::Migration
|
2
|
+
|
3
|
+
def self.up
|
4
|
+
create_table :books, :force => true do |t|
|
5
|
+
t.family :attribute, :versions => 100
|
6
|
+
t.family :family2
|
7
|
+
t.family :log, :versions => 100
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.down
|
12
|
+
drop_table :books
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class AddCompaniesTable < BigRecord::Migration
|
2
|
+
|
3
|
+
def self.up
|
4
|
+
create_table :companies, :force => true do |t|
|
5
|
+
t.family :attribute, :versions => 100
|
6
|
+
t.family :log, :versions => 100
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.down
|
11
|
+
drop_table :companies
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
data/spec/lib/novel.rb
ADDED
data/spec/lib/zoo.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
class Zoo < BigRecord::Base
|
2
|
+
|
3
|
+
set_default_family :attr
|
4
|
+
|
5
|
+
column 'attr:name', 'string'
|
6
|
+
column 'attr:address', 'string'
|
7
|
+
column 'attr:employees', 'integer'
|
8
|
+
column 'attr:readonly', 'string'
|
9
|
+
column :description, :string
|
10
|
+
column 'attr:weblink', 'Embedded::WebLink', :alias => "weblink"
|
11
|
+
column 'attr:animal_ids', :string, :collection => true
|
12
|
+
|
13
|
+
|
14
|
+
attr_accessible :name, :address, :description
|
15
|
+
|
16
|
+
belongs_to_many :animals, :foreign_key => 'attr:animal_ids'
|
17
|
+
end
|
data/spec/spec.opts
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require 'rubygems'
|
3
|
+
|
4
|
+
gem 'rspec', '~>1.2'
|
5
|
+
require 'spec'
|
6
|
+
|
7
|
+
SPEC_ROOT = Pathname(__FILE__).dirname.expand_path
|
8
|
+
require SPEC_ROOT.parent + 'lib/big_record'
|
9
|
+
|
10
|
+
BigRecord::Base.configurations = YAML::load(File.open(File.join(File.dirname(__FILE__), "connections", "bigrecord.yml")))
|
11
|
+
BigRecord::Base.logger = Logger.new(File.join(File.dirname(__FILE__), "debug.log"))
|
12
|
+
|
13
|
+
begin
|
14
|
+
require 'connection'
|
15
|
+
rescue LoadError
|
16
|
+
BigRecord::Base.logger.info "No data store defined. Using Hbase..."
|
17
|
+
require File.join(File.dirname(__FILE__), 'connections', 'hbase', 'connection')
|
18
|
+
end
|
19
|
+
|
20
|
+
# Load the various helpers for the spec suite
|
21
|
+
Dir.glob( File.join(File.dirname(__FILE__), "lib", "**", "*.rb") ).each do |model|
|
22
|
+
require model
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
# Redefine the Hash class to include two helper methods used only in the specs.
|
27
|
+
class Hash
|
28
|
+
# Helper method to determine if a hash is completely contained within other_hash (order is not important).
|
29
|
+
# Matches each key/value pair, and returns false as soon as a mismatch occurs. The other_hash might have
|
30
|
+
# more pairs, but those aren't considered.
|
31
|
+
#
|
32
|
+
# hash1 = { :key1 => "value1", :key2 => "value2", :key3 => "value3" }
|
33
|
+
#
|
34
|
+
# hash2 = { :key1 => "value1", :key2 => "value2", :key3 => "value3", :key4 => "value4" }
|
35
|
+
#
|
36
|
+
# hash3 = { :key1 => "value4", :key2 => "value3", :key3 => "value1", :key4 => "value2" }
|
37
|
+
#
|
38
|
+
# hash1.subset_of?(hash2) # => true
|
39
|
+
# hash2.subset_of?(hash1) # => false
|
40
|
+
# hash3.subset_of?(hash1) # => false
|
41
|
+
# hash3.subset_of?(hash2) # => false
|
42
|
+
#
|
43
|
+
def subset_of?(other_hash)
|
44
|
+
self.each_pair do |key, value|
|
45
|
+
return false if !other_hash.has_key?(key) || !(other_hash[key] == value)
|
46
|
+
end
|
47
|
+
|
48
|
+
true
|
49
|
+
end
|
50
|
+
|
51
|
+
def superset_of?(other_hash)
|
52
|
+
other_hash.subset_of?(self)
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
@@ -0,0 +1,287 @@
|
|
1
|
+
# Defined as a shared spec because embedded_spec uses it as well
|
2
|
+
describe "BigRecord::AbstractBase", :shared => true do
|
3
|
+
|
4
|
+
it "should provide #primary_key" do
|
5
|
+
Book.should respond_to(:primary_key)
|
6
|
+
end
|
7
|
+
|
8
|
+
describe '#columns' do
|
9
|
+
|
10
|
+
before(:all) do
|
11
|
+
# Grab the columns from a simple BigRecord model
|
12
|
+
@columns = Book.columns
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should return a hash of Column objects describing the columns in the model' do
|
16
|
+
# Verify that each entry is a Column object
|
17
|
+
@columns.each do |column|
|
18
|
+
column.should be_a_kind_of(BigRecord::ConnectionAdapters::Column)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Map the names of each of the columns
|
22
|
+
column_names = @columns.map{ |column| column.name }
|
23
|
+
|
24
|
+
# Verify that each attribute we defined in the Book model is present
|
25
|
+
expected_names = %w( attribute:title attribute:author attribute:description family2: log:change )
|
26
|
+
(column_names & expected_names).sort.should == expected_names.sort
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should save a default alias name for each column (e.g. attribute:name become alias name automatically)' do
|
30
|
+
lookup = { 'attribute:id' => 'id',
|
31
|
+
'attribute:title' => 'title',
|
32
|
+
'attribute:author' => 'author',
|
33
|
+
'attribute:description' => 'description'}
|
34
|
+
|
35
|
+
# Go through each column and if an attribute name is found that matches the lookup table above,
|
36
|
+
# verify that the alias name it creates is the one we expect.
|
37
|
+
@columns.each do |column|
|
38
|
+
if lookup.has_key?(column.name)
|
39
|
+
column.alias.should == lookup[column.name]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
describe 'column families' do
|
47
|
+
|
48
|
+
it 'should respond to #default_family with a default value, or with the value defined in the model' do
|
49
|
+
Book.should respond_to(:default_family)
|
50
|
+
Book.default_family.should == "attribute"
|
51
|
+
|
52
|
+
Zoo.should respond_to(:default_family)
|
53
|
+
Zoo.default_family.should == "attr"
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'should automatically append the #default_family to columns without one defined' do
|
57
|
+
Zoo.columns.map{|column| column.name}.should include("attr:description")
|
58
|
+
Zoo.new.should respond_to(:description)
|
59
|
+
Zoo.new.should respond_to(:description=)
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
describe '.attributes' do
|
65
|
+
|
66
|
+
before(:each) do
|
67
|
+
@book = Book.new
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'should have getter and setter methods for the attributes from the alias of their names' do
|
71
|
+
# Check that the getters are responding
|
72
|
+
@book.should respond_to(:title)
|
73
|
+
@book.should respond_to(:author)
|
74
|
+
@book.should respond_to(:description)
|
75
|
+
|
76
|
+
# Check that the setters are responding
|
77
|
+
@book.should respond_to(:title=)
|
78
|
+
@book.should respond_to(:author=)
|
79
|
+
@book.should respond_to(:description=)
|
80
|
+
|
81
|
+
# Now we use the setters
|
82
|
+
@book.title = "The Beach"
|
83
|
+
@book.author = "Alex Garland"
|
84
|
+
@book.description = "A furiously intelligent first novel." # this was written on the cover
|
85
|
+
|
86
|
+
# And we check that the getters are working
|
87
|
+
@book.title.should == "The Beach"
|
88
|
+
@book.author.should == "Alex Garland"
|
89
|
+
@book.description.should == "A furiously intelligent first novel."
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'should provide a list of modified attributes with #modified_attributes' do
|
93
|
+
pending "This was deprecated"
|
94
|
+
|
95
|
+
book = Book.new( :title => "The Beach",
|
96
|
+
:author => "Alex Garland",
|
97
|
+
:description => "A furiously intelligent first novel.")
|
98
|
+
|
99
|
+
book.modified_attributes.each_pair do |key, value|
|
100
|
+
%w( title author description ).include?(key.to_s).should be_true
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'should return a hash of attribute-names and values' do
|
105
|
+
# Set some attributes, and verify that they get stored in the model
|
106
|
+
@book.title = "The Beach"
|
107
|
+
@book.author = "Alex Garland"
|
108
|
+
@book.description = "A furiously intelligent first novel."
|
109
|
+
|
110
|
+
expected_hash = {"log:change"=>[], "attribute:description"=>"A furiously intelligent first novel.", "attribute:title"=>"The Beach", "attribute:links"=>[], "attribute:author"=>"Alex Garland"}
|
111
|
+
|
112
|
+
@book.attributes.superset_of?(expected_hash).should be_true
|
113
|
+
end
|
114
|
+
|
115
|
+
it "should return a hash with all nil or empty list values if the instance is new and has no default values" do
|
116
|
+
@book.attributes.superset_of?({"log:change"=>[], "attribute:description"=>nil, "attribute:title"=>nil, "attribute:links"=>[], "attribute:author"=>nil}).should be_true
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
120
|
+
|
121
|
+
describe ".attributes=" do
|
122
|
+
|
123
|
+
it 'should be able to mass assign attributes' do
|
124
|
+
# Check that the mass asssignment of attributes works with #new
|
125
|
+
@book = Book.new( :title => "The Beach",
|
126
|
+
:author => "Alex Garland",
|
127
|
+
:description => "A furiously intelligent first novel.")
|
128
|
+
|
129
|
+
@book.attributes.superset_of?({"log:change"=>[], "attribute:description"=>"A furiously intelligent first novel.", "attribute:title"=>"The Beach", "attribute:links"=>[], "attribute:author"=>"Alex Garland"}).should be_true
|
130
|
+
|
131
|
+
# Check that it works with the #attributes= method
|
132
|
+
@book.attributes = {:title => "28 Days Later"}
|
133
|
+
|
134
|
+
@book.attributes.superset_of?({"log:change"=>[], "attribute:description"=>"A furiously intelligent first novel.", "attribute:title"=>"28 Days Later", "attribute:links"=>[], "attribute:author"=>"Alex Garland"}).should be_true
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
|
139
|
+
describe "protected attributes" do
|
140
|
+
|
141
|
+
it 'should respond to the method #protected_attributes' do
|
142
|
+
Company.should respond_to(:protected_attributes)
|
143
|
+
end
|
144
|
+
|
145
|
+
it 'should list #protected_attributes' do
|
146
|
+
Company.protected_attributes.should be_a_kind_of(Set)
|
147
|
+
Company.protected_attributes.should include("employees")
|
148
|
+
end
|
149
|
+
|
150
|
+
it 'should be handled properly' do
|
151
|
+
# Employees is a protected attribute here, so it shouldn't be saved.
|
152
|
+
@company = Company.new(:name => "The Company", :address => "Unknown", :employees => 18000, :readonly => "secret")
|
153
|
+
|
154
|
+
@company.attributes.superset_of?({"attribute:employees"=>nil, "attribute:address"=>"Unknown", "attribute:readonly"=>"secret", "log:change"=>[], "attribute:name"=>"The Company"}).should be_true
|
155
|
+
|
156
|
+
# Check it against the attributes= method
|
157
|
+
@company.attributes = {:employees => 18000}
|
158
|
+
|
159
|
+
@company.attributes.superset_of?({"attribute:employees"=>nil, "attribute:address"=>"Unknown", "attribute:readonly"=>"secret", "log:change"=>[], "attribute:name"=>"The Company"}).should be_true
|
160
|
+
|
161
|
+
# Now check that we can access it with the employees= method
|
162
|
+
@company.employees = 18000
|
163
|
+
|
164
|
+
@company.attributes.superset_of?({"attribute:employees"=>18000, "attribute:address"=>"Unknown", "attribute:readonly"=>"secret", "log:change"=>[], "attribute:name"=>"The Company"}).should be_true
|
165
|
+
end
|
166
|
+
|
167
|
+
end
|
168
|
+
|
169
|
+
describe "accessible attributes" do
|
170
|
+
|
171
|
+
it 'should respond to the method #accessible_attributes' do
|
172
|
+
Zoo.should respond_to(:accessible_attributes)
|
173
|
+
Zoo.accessible_attributes.should_not be_empty
|
174
|
+
end
|
175
|
+
|
176
|
+
it 'should list #accessible_attributes' do
|
177
|
+
Zoo.accessible_attributes.should be_a_kind_of(Set)
|
178
|
+
Zoo.accessible_attributes.should include("address")
|
179
|
+
Zoo.accessible_attributes.should include("description")
|
180
|
+
end
|
181
|
+
|
182
|
+
it 'should be handled properly' do
|
183
|
+
# name, address, and description are accessible attributes here
|
184
|
+
attributes_hash = { :name => "San Francisco",
|
185
|
+
:address => "Some Address",
|
186
|
+
:description => "This is a pretty awesome zoo",
|
187
|
+
:employees => 10000,
|
188
|
+
:readonly => "should not work" }
|
189
|
+
|
190
|
+
zoo = Zoo.new(attributes_hash)
|
191
|
+
|
192
|
+
zoo.attributes.superset_of?({"attr:readonly"=>nil, "attr:address"=>"Some Address", "attr:description"=>"This is a pretty awesome zoo", "attr:employees"=>nil, "attr:name"=>"San Francisco"}).should be_true
|
193
|
+
|
194
|
+
zoo.attributes = {:address => "1 Zoo Rd", :description => "Awesome address", :employees => 1000}
|
195
|
+
|
196
|
+
zoo.attributes.superset_of?({"attr:readonly"=>nil, "attr:address"=>"1 Zoo Rd", "attr:description"=>"Awesome address", "attr:employees"=>nil, "attr:name"=>"San Francisco"}).should be_true
|
197
|
+
|
198
|
+
zoo.employees = 1000
|
199
|
+
|
200
|
+
zoo.attributes.superset_of?({"attr:readonly"=>nil, "attr:address"=>"1 Zoo Rd", "attr:description"=>"Awesome address", "attr:employees"=>1000, "attr:name"=>"San Francisco"})
|
201
|
+
end
|
202
|
+
|
203
|
+
end
|
204
|
+
|
205
|
+
describe "readonly attributes" do
|
206
|
+
|
207
|
+
it 'should respond to the method #readonly_attributes' do
|
208
|
+
Company.should respond_to(:readonly_attributes)
|
209
|
+
end
|
210
|
+
|
211
|
+
it 'should list #readonly_attributes' do
|
212
|
+
Company.readonly_attributes.should be_a_kind_of(Set)
|
213
|
+
Company.readonly_attributes.should include("readonly")
|
214
|
+
end
|
215
|
+
|
216
|
+
it 'should be handled properly' do
|
217
|
+
pending "this still needs to be implemented in BigRecord::AbstractBase"
|
218
|
+
|
219
|
+
# readonly is the readonly attribute here
|
220
|
+
@company = Company.new(:name => "The Company", :address => "Unknown", :readonly => "secret")
|
221
|
+
|
222
|
+
# It should've been set successfully since this is a new record
|
223
|
+
@company.attributes.superset_of?({"attribute:employees"=>nil, "attribute:address"=>"Unknown", "attribute:readonly"=>"secret", "log:change"=>[], "attribute:name"=>"The Company"}).should be_true
|
224
|
+
|
225
|
+
# It should still also be accessible with the attributes= method
|
226
|
+
@company.attributes = {:readonly => "another secret"}
|
227
|
+
|
228
|
+
@company.attributes.superset_of?({"attribute:employees"=>nil, "attribute:address"=>"Unknown", "attribute:readonly"=>"another secret", "log:change"=>[], "attribute:name"=>"The Company"}).should be_true
|
229
|
+
|
230
|
+
# Now when we save it, it should no longer be accessible with mass assignment
|
231
|
+
|
232
|
+
# Mock new_record? so it's essentially acting like it was saved.
|
233
|
+
@company.stub!(:new_record?).and_return(false)
|
234
|
+
|
235
|
+
@company.attributes = {:readonly => "compromised secret"}
|
236
|
+
|
237
|
+
@company.attributes.superset_of?({"attribute:employees"=>nil, "attribute:address"=>"Unknown", "attribute:readonly"=>"another secret", "log:change"=>[], "attribute:name"=>"The Company"}).should be_true
|
238
|
+
|
239
|
+
# And it should still not be accessible with the explicit setter
|
240
|
+
@company.readonly = "compromised secret"
|
241
|
+
|
242
|
+
@company.attributes.superset_of?({"attribute:employees"=>nil, "attribute:address"=>"Unknown", "attribute:readonly"=>"another secret", "log:change"=>[], "attribute:name"=>"Another Company"}).should be_true
|
243
|
+
end
|
244
|
+
|
245
|
+
end
|
246
|
+
|
247
|
+
describe "create_accessible attributes" do
|
248
|
+
|
249
|
+
it 'should respond to the method #create_accessible_attributes' do
|
250
|
+
Company.should respond_to(:create_accessible_attributes)
|
251
|
+
end
|
252
|
+
|
253
|
+
it 'should list #create_accessible_attributes' do
|
254
|
+
Company.create_accessible_attributes.should be_a_kind_of(Set)
|
255
|
+
Company.create_accessible_attributes.should include("name")
|
256
|
+
end
|
257
|
+
|
258
|
+
it 'should be handled properly' do
|
259
|
+
# Name is the create_accessible attribute here
|
260
|
+
@company = Company.new(:name => "Another Company", :address => "Unknown")
|
261
|
+
|
262
|
+
# It should've been set successfully since this is a new record
|
263
|
+
@company.attributes.superset_of?({"attribute:employees"=>nil, "attribute:address"=>"Unknown", "attribute:readonly"=>nil, "log:change"=>[], "attribute:name"=>"Another Company"}).should be_true
|
264
|
+
|
265
|
+
# It should still also be accessible with the attributes= method
|
266
|
+
@company.attributes = {:name => "The Company"}
|
267
|
+
|
268
|
+
@company.attributes.superset_of?({"attribute:employees"=>nil, "attribute:address"=>"Unknown", "attribute:readonly"=>nil, "log:change"=>[], "attribute:name"=>"The Company"}).should be_true
|
269
|
+
|
270
|
+
# Now when we save it, it should no longer be accessible with mass assignment
|
271
|
+
|
272
|
+
# Mock new_record? so it's essentially acting like it was saved.
|
273
|
+
@company.stub!(:new_record?).and_return(false)
|
274
|
+
|
275
|
+
@company.attributes = {:name => "Another Company"}
|
276
|
+
|
277
|
+
@company.attributes.superset_of?({"attribute:employees"=>nil, "attribute:address"=>"Unknown", "attribute:readonly"=>nil, "log:change"=>[], "attribute:name"=>"The Company"}).should be_true
|
278
|
+
|
279
|
+
# But it should still be accessible with the explicit setter
|
280
|
+
@company.name = "Another Company"
|
281
|
+
|
282
|
+
@company.attributes.superset_of?({"attribute:employees"=>nil, "attribute:address"=>"Unknown", "attribute:readonly"=>nil, "log:change"=>[], "attribute:name"=>"Another Company"}).should be_true
|
283
|
+
end
|
284
|
+
|
285
|
+
end
|
286
|
+
|
287
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper'))
|
2
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'adapter_shared_spec'))
|
3
|
+
|
4
|
+
describe BigRecord::ConnectionAdapters::AbstractAdapter do
|
5
|
+
|
6
|
+
before do
|
7
|
+
@adapter = BigRecord::ConnectionAdapters::AbstractAdapter.new("")
|
8
|
+
end
|
9
|
+
|
10
|
+
it_should_behave_like 'a BigRecord Adapter'
|
11
|
+
|
12
|
+
it "should raise NotImplementedError when #update_raw is called" do
|
13
|
+
lambda{ @adapter.update_raw(:table_name, :row, :values, :timestamp) }.should raise_error(NotImplementedError)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should raise NotImplementedError when #update is called" do
|
17
|
+
lambda{ @adapter.update(:table_name, :row, :values, :timestamp) }.should raise_error(NotImplementedError)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should raise NotImplementedError when #get_raw is called" do
|
21
|
+
lambda{ @adapter.get_raw(:table_name, :row, :column, :options) }.should raise_error(NotImplementedError)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should raise NotImplementedError when #get is called" do
|
25
|
+
lambda{ @adapter.get(:table_name, :row, :column, :options) }.should raise_error(NotImplementedError)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should raise NotImplementedError when #get_columns_raw is called" do
|
29
|
+
lambda{ @adapter.get_columns_raw(:table_name, :row, :columns, :options) }.should raise_error(NotImplementedError)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should raise NotImplementedError when #get_columns is called" do
|
33
|
+
lambda{ @adapter.get_columns(:table_name, :row, :columns, :options) }.should raise_error(NotImplementedError)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should raise NotImplementedError when #delete is called" do
|
37
|
+
lambda{ @adapter.delete(:table_name, :row) }.should raise_error(NotImplementedError)
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should raise NotImplementedError when #delete_all is called" do
|
41
|
+
lambda{ @adapter.delete_all(:table_name) }.should raise_error(NotImplementedError)
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should raise NotImplementedError when #table_exists? is called" do
|
45
|
+
lambda{ @adapter.table_exists?(:table_name) }.should raise_error(NotImplementedError)
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should raise NotImplementedError when #create_table is called" do
|
49
|
+
lambda{ @adapter.create_table(:table_name, :column_families) }.should raise_error(NotImplementedError)
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should raise NotImplementedError when #drop_table is called" do
|
53
|
+
lambda{ @adapter.drop_table(:table_name) }.should raise_error(NotImplementedError)
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
describe "a BigRecord Adapter", :shared => true do
|
2
|
+
|
3
|
+
%w{adapter_name supports_migrations?}.each do |meth|
|
4
|
+
it "should have a ##{meth} method" do
|
5
|
+
@adapter.should respond_to(meth.intern)
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "with connection management" do
|
10
|
+
%w{active? reconnect! disconnect!}.each do |meth|
|
11
|
+
it "should have a ##{meth} method" do
|
12
|
+
@adapter.should respond_to(meth.intern)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "with data store statements" do
|
18
|
+
%w{update_raw update get_raw get get_columns_raw get_columns get_consecutive_rows_raw get_consecutive_rows delete delete_all}.each do |meth|
|
19
|
+
it "should have a ##{meth} method" do
|
20
|
+
@adapter.should respond_to(meth.intern)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "with schema statements" do
|
26
|
+
%w{table_exists? create_table drop_table}.each do |meth|
|
27
|
+
it "should have a ##{meth} method" do
|
28
|
+
@adapter.should respond_to(meth.intern)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should have the methods needed for migrations if supports_migrations? is true" do
|
33
|
+
if @adapter.supports_migrations?
|
34
|
+
%w{initialize_schema_migrations_table get_all_schema_versions add_column_family remove_column_family modify_column_family}.each do |meth|
|
35
|
+
@adapter.should respond_to(meth.intern)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "timestamp functionality" do
|
42
|
+
it "should use the default Time.to_bigrecord_timestamp or implement it's own method" do
|
43
|
+
Time.now.should respond_to(:to_bigrecord_timestamp)
|
44
|
+
Time.should respond_to(:from_bigrecord_timestamp)
|
45
|
+
|
46
|
+
Time.now.to_bigrecord_timestamp.should_not be_nil
|
47
|
+
Time.from_bigrecord_timestamp(Time.now.to_bigrecord_timestamp).should_not be_nil
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper'))
|
2
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'adapter_shared_spec'))
|
3
|
+
|
4
|
+
describe BigRecord::ConnectionAdapters::HbaseAdapter do
|
5
|
+
|
6
|
+
before do
|
7
|
+
# Make sure the connection is defined in spec/connections/bigrecord.yml
|
8
|
+
BigRecord::Base.establish_connection 'hbase'
|
9
|
+
|
10
|
+
@adapter = BigRecord::Base.connection
|
11
|
+
end
|
12
|
+
|
13
|
+
it_should_behave_like 'a BigRecord Adapter'
|
14
|
+
|
15
|
+
end
|