bigrecord 0.0.8 → 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -26,11 +26,9 @@ module BigRecord
26
26
  # TODO: this sucks... aren't there a better way to do it?
27
27
  if self.class < ActiveRecord::Base
28
28
  class MacroReflectionAbstract < ActiveRecord::Reflection::MacroReflection
29
-
30
29
  end
31
30
  else
32
31
  class MacroReflectionAbstract < BigRecord::ArReflection::MacroReflection
33
-
34
32
  end
35
33
  end
36
34
 
@@ -88,7 +86,7 @@ module BigRecord
88
86
 
89
87
  # Gets an array of possible :through source reflection names
90
88
  #
91
- # [singularized, pluralized]
89
+ # [singularized, pluralized]
92
90
  #
93
91
  def source_reflection_names
94
92
  @source_reflection_names ||= (options[:source] ? [options[:source]] : [name.to_s.singularize, name]).collect { |n| n.to_sym }
@@ -1,175 +1,15 @@
1
1
  module BigRecord
2
2
  module ConnectionAdapters # :nodoc:
3
3
  module DatabaseStatements
4
- # # Returns an array of record hashes with the column names as keys and
5
- # # column values as values.
6
- # def select_all(sql, name = nil)
7
- # select(sql, name)
8
- # end
9
- #
10
- # # Returns a record hash with the column names as keys and column values
11
- # # as values.
12
- # def select_one(sql, name = nil)
13
- # result = select_all(sql, name)
14
- # result.first if result
15
- # end
16
- #
17
- # # Returns a single value from a record
18
- # def select_value(sql, name = nil)
19
- # if result = select_one(sql, name)
20
- # result.values.first
21
- # end
22
- # end
23
- #
24
- # # Returns an array of the values of the first column in a select:
25
- # # select_values("SELECT id FROM companies LIMIT 3") => [1,2,3]
26
- # def select_values(sql, name = nil)
27
- # result = select_rows(sql, name)
28
- # result.map { |v| v[0] }
29
- # end
30
- #
31
- # # Returns an array of arrays containing the field values.
32
- # # Order is the same as that returned by #columns.
33
- # def select_rows(sql, name = nil)
34
- # raise NotImplementedError, "select_rows is an abstract method"
35
- # end
36
- #
37
- # # Executes the SQL statement in the context of this connection.
38
- # def execute(sql, name = nil)
39
- # raise NotImplementedError, "execute is an abstract method"
40
- # end
41
- #
42
- # # Returns the last auto-generated ID from the affected table.
43
- # def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
44
- # insert_sql(sql, name, pk, id_value, sequence_name)
45
- # end
46
- #
47
- # # Executes the update statement and returns the number of rows affected.
48
- # def update(sql, name = nil)
49
- # update_sql(sql, name)
50
- # end
51
- #
52
- # # Executes the delete statement and returns the number of rows affected.
53
- # def delete(sql, name = nil)
54
- # delete_sql(sql, name)
55
- # end
56
- #
57
- # # Wrap a block in a transaction. Returns result of block.
58
- # def transaction(start_db_transaction = true)
59
- # transaction_open = false
60
- # begin
61
- # if block_given?
62
- # if start_db_transaction
63
- # begin_db_transaction
64
- # transaction_open = true
65
- # end
66
- # yield
67
- # end
68
- # rescue Exception => database_transaction_rollback
69
- # if transaction_open
70
- # transaction_open = false
71
- # rollback_db_transaction
72
- # end
73
- # raise unless database_transaction_rollback.is_a? ActiveRecord::Rollback
74
- # end
75
- # ensure
76
- # if transaction_open
77
- # begin
78
- # commit_db_transaction
79
- # rescue Exception => database_transaction_rollback
80
- # rollback_db_transaction
81
- # raise
82
- # end
83
- # end
84
- # end
85
- #
86
- # # Begins the transaction (and turns off auto-committing).
87
- # def begin_db_transaction() end
88
- #
89
- # # Commits the transaction (and turns on auto-committing).
90
- # def commit_db_transaction() end
91
- #
92
- # # Rolls back the transaction (and turns on auto-committing). Must be
93
- # # done if the transaction block raises an exception or returns false.
94
- # def rollback_db_transaction() end
95
- #
96
- # # Alias for #add_limit_offset!.
97
- # def add_limit!(sql, options)
98
- # add_limit_offset!(sql, options) if options
99
- # end
100
- #
101
- # # Appends +LIMIT+ and +OFFSET+ options to an SQL statement.
102
- # # This method *modifies* the +sql+ parameter.
103
- # # ===== Examples
104
- # # add_limit_offset!('SELECT * FROM suppliers', {:limit => 10, :offset => 50})
105
- # # generates
106
- # # SELECT * FROM suppliers LIMIT 10 OFFSET 50
107
- # def add_limit_offset!(sql, options)
108
- # if limit = options[:limit]
109
- # sql << " LIMIT #{limit}"
110
- # if offset = options[:offset]
111
- # sql << " OFFSET #{offset}"
112
- # end
113
- # end
114
- # end
115
- #
116
- # # Appends a locking clause to an SQL statement.
117
- # # This method *modifies* the +sql+ parameter.
118
- # # # SELECT * FROM suppliers FOR UPDATE
119
- # # add_lock! 'SELECT * FROM suppliers', :lock => true
120
- # # add_lock! 'SELECT * FROM suppliers', :lock => ' FOR UPDATE'
121
- # def add_lock!(sql, options)
122
- # case lock = options[:lock]
123
- # when true; sql << ' FOR UPDATE'
124
- # when String; sql << " #{lock}"
125
- # end
126
- # end
127
- #
128
- # def default_sequence_name(table, column)
129
- # nil
130
- # end
131
- #
132
- # # Set the sequence to the max value of the table's column.
133
- # def reset_sequence!(table, column, sequence = nil)
134
- # # Do nothing by default. Implement for PostgreSQL, Oracle, ...
135
- # end
136
-
137
4
  # Inserts the given fixture into the table. Overridden in adapters that require
138
5
  # something beyond a simple insert (eg. Oracle).
139
6
  def insert_fixture(fixture, table_name)
140
- # execute "INSERT INTO #{quote_table_name(table_name)} (#{fixture.key_list}) VALUES (#{fixture.value_list})", 'Fixture Insert'
7
+ # execute "INSERT INTO #{quote_table_name(table_name)} (#{fixture.key_list}) VALUES (#{fixture.value_list})", 'Fixture Insert'
141
8
  attributes = fixture.to_hash.dup
142
9
  id = attributes.delete("id")
143
10
  raise ArgumentError, "the id is missing" unless id
144
11
  update(table_name, id, attributes, Time.now.to_bigrecord_timestamp)
145
12
  end
146
-
147
- # def empty_insert_statement(table_name)
148
- # "INSERT INTO #{quote_table_name(table_name)} VALUES(DEFAULT)"
149
- # end
150
- #
151
- # protected
152
- # # Returns an array of record hashes with the column names as keys and
153
- # # column values as values.
154
- # def select(sql, name = nil)
155
- # raise NotImplementedError, "select is an abstract method"
156
- # end
157
- #
158
- # # Returns the last auto-generated ID from the affected table.
159
- # def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
160
- # execute(sql, name)
161
- # id_value
162
- # end
163
- #
164
- # # Executes the update statement and returns the number of rows affected.
165
- # def update_sql(sql, name = nil)
166
- # execute(sql, name)
167
- # end
168
- #
169
- # # Executes the delete statement and returns the number of rows affected.
170
- # def delete_sql(sql, name = nil)
171
- # update_sql(sql, name)
172
- # end
173
13
  end
174
14
  end
175
15
  end
@@ -7,7 +7,7 @@ module BigRecord
7
7
  module ConnectionAdapters # :nodoc:
8
8
  # All the concrete database adapters follow the interface laid down in this class.
9
9
  # You can use this interface directly by borrowing the database connection from the Base with
10
- # Base.connection.
10
+ # BigRecord::Base.connection
11
11
  #
12
12
  # Most of the methods in the adapter are useful during migrations. Most
13
13
  # notably, SchemaStatements#create_table, SchemaStatements#drop_table,
@@ -172,19 +172,3 @@ module BigRecord
172
172
  end # class AbstractAdapter
173
173
  end # module ConnectionAdapters
174
174
  end # module BigRecord
175
-
176
-
177
- # Open the time class to add logic for the hbase timestamp
178
- class Time
179
- # Return this time is the hbase timestamp format, i.e. a 'long'. The 4 high bytes contain
180
- # the number of seconds since epoch and the 4 low bytes contain the microseconds. That
181
- # format is an arbitrary one and could have been something else.
182
- def to_bigrecord_timestamp
183
- (self.to_i << 32) + self.usec
184
- end
185
-
186
- def self.from_bigrecord_timestamp(timestamp)
187
- Time.at(timestamp >> 32, timestamp & 0xFFFFFFFF)
188
- end
189
-
190
- end
@@ -103,6 +103,7 @@ module BigRecord
103
103
  end
104
104
 
105
105
  # Returns the Ruby class that corresponds to the abstract data type.
106
+ # View the source for the actual mappings.
106
107
  def klass
107
108
  @klass ||=
108
109
  case type
@@ -339,36 +340,6 @@ module BigRecord
339
340
  parse_collection(value).collect{|v| string_to_dummy_time(v.to_s)}
340
341
  end
341
342
 
342
- # def hash_to_time_collection(hash)
343
- # return []
344
- # return hash unless hash.is_a?(Hash)
345
- # hash_to_collection(hash).collect do |attributes|
346
- # cleaned_attributes = {}
347
- # debugger
348
- # attributes.each do |k, v|
349
- # k =~ /reflect_value(.*)/
350
- # cleaned_attributes[$1] = v
351
- # end
352
- # string_to_time(cleaned_attributes)
353
- # end
354
- # end
355
- #
356
- # def hash_to_dummy_time_collection(hash)
357
- # return []
358
- # return hash unless hash.is_a?(Array)
359
- # hash.split(COLLECTION_SEPARATOR).collect{|v|string_to_dummy_time(v)}
360
- # end
361
- #
362
- # def hash_to_date_collection(hash)
363
- # return []
364
- # return hash unless hash.is_a?(Array)
365
- # hash_to_collection(hash).collect do |attributes|
366
- # debugger
367
- # callstack = extract_callstack_for_multiparameter_attributes(attributes.to_a)
368
- #
369
- # end
370
- # end
371
-
372
343
  def hash_to_boolean_collection(value)
373
344
  parse_collection(value).collect{|v| value_to_boolean(v)}
374
345
  end
@@ -2,24 +2,26 @@ require 'rubygems'
2
2
  require 'set'
3
3
  require 'drb'
4
4
 
5
- unless defined?(BigRecordDriver)
6
- begin
7
- # Bigrecord's source is included with Bigrecord-Driver, that's we check for this first
8
- require File.join(File.dirname(__FILE__), "..", "..", "..", "..", "bigrecord-driver", "lib", "big_record_driver")
9
- rescue LoadError
10
- begin
11
- gem 'bigrecord-driver'
12
- require 'bigrecord_driver'
13
- rescue Gem::LoadError
14
- puts "bigrecord-driver not available. Install it with: sudo gem install bigrecord-driver -s http://gemcutter.org"
15
- end
16
- end
17
- end
18
-
19
5
  module BigRecord
20
6
  class Base
21
7
  # Establishes a connection to the database that's used by all Active Record objects.
22
8
  def self.hbase_connection(config) # :nodoc:
9
+ unless defined?(BigRecordDriver)
10
+ begin
11
+ # Bigrecord's source is included with Bigrecord-Driver, that's where we check for it first.
12
+ require File.join(File.dirname(__FILE__), "..", "..", "..", "..", "bigrecord-driver", "lib", "big_record_driver")
13
+ rescue LoadError
14
+ # Then we'll require it from the load path (or rubygems)
15
+ begin
16
+ require 'bigrecord_driver'
17
+ rescue LoadError => e
18
+ # If it couldn't be found, we'll just prompt the user to install the gem.
19
+ puts "[BigRecord] bigrecord-driver is needed for HbaseAdapter. Install it with: gem install bigrecord-driver"
20
+ raise e
21
+ end
22
+ end
23
+ end
24
+
23
25
  config = config.symbolize_keys
24
26
 
25
27
  zookeeper_host = config[:zookeeper_host]
@@ -233,7 +235,7 @@ module BigRecord
233
235
  end
234
236
 
235
237
  def create_table(table_name, options = {})
236
- table_definition = TableDefinition.new
238
+ table_definition = HbaseAdapterTable.new
237
239
 
238
240
  yield table_definition if block_given?
239
241
 
@@ -398,7 +400,7 @@ module BigRecord
398
400
  end
399
401
  end
400
402
 
401
- class TableDefinition
403
+ class HbaseAdapterTable
402
404
 
403
405
  def initialize
404
406
  @column_families = []
@@ -1,22 +1,27 @@
1
1
  require 'set'
2
- require 'hbase'
3
2
 
4
3
  module BigRecord
5
4
  class Base
6
5
  # Establishes a connection to the database that's used by all Active Record objects.
7
6
  def self.hbase_rest_connection(config) # :nodoc:
7
+ begin
8
+ require 'hbase'
9
+ rescue LoadError => e
10
+ puts "[BigRecord] hbase-ruby is needed for HbaseRestAdapter. Install it with: gem install hbase-ruby"
11
+ raise e
12
+ end
13
+
8
14
  config = config.symbolize_keys
9
15
 
10
16
  api_address = config[:api_address]
11
-
12
17
  hbase = HBase::Client.new(api_address)
13
-
14
18
  ConnectionAdapters::HbaseRestAdapter.new(hbase, logger, [], config)
15
19
  end
16
20
  end
17
21
 
18
22
  module ConnectionAdapters
19
23
  class HbaseRestAdapter < AbstractAdapter
24
+
20
25
  @@emulate_booleans = true
21
26
  cattr_accessor :emulate_booleans
22
27
 
@@ -83,7 +88,7 @@ module BigRecord
83
88
  result = nil
84
89
 
85
90
  columns = columns_to_hbase_format(values)
86
- timestamp = Time.now.to_bigrecord_timestamp
91
+ timestamp ||= Time.now.to_bigrecord_timestamp
87
92
 
88
93
  log "UPDATE #{table_name} SET #{values.inspect if values} WHERE ROW=#{row};" do
89
94
  @connection.create_row(table_name, row, timestamp, columns)
@@ -171,16 +176,12 @@ module BigRecord
171
176
 
172
177
  result = rows.collect do |row|
173
178
  cols = {}
179
+ cols['id'] = row.name
174
180
  row.columns.each do |col|
175
181
  key = col.name
176
182
  value = col.value
177
183
  begin
178
- cols[key] =
179
- if key == 'id'
180
- value
181
- else
182
- deserialize(value)
183
- end
184
+ cols[key] = deserialize(value)
184
185
  rescue Exception => e
185
186
  puts "Could not load column value #{key} for row=#{row.name}"
186
187
  end
@@ -228,7 +229,7 @@ module BigRecord
228
229
  end
229
230
 
230
231
  def create_table(table_name, options = {})
231
- table_definition = TableDefinition.new
232
+ table_definition = HbaseRestAdapterTable.new
232
233
 
233
234
  yield table_definition if block_given?
234
235
 
@@ -310,68 +311,70 @@ module BigRecord
310
311
  end
311
312
  end
312
313
 
313
- private
314
+ private
314
315
 
315
- def connect
316
- end
316
+ def connect
317
+ end
317
318
 
318
- protected
319
- def log(str, name = nil)
320
- if block_given?
321
- if @logger and @logger.level <= Logger::INFO
322
- result = nil
323
- seconds = Benchmark.realtime { result = yield }
324
- @runtime += seconds
325
- log_info(str, name, seconds)
326
- result
327
- else
328
- yield
329
- end
319
+ protected
320
+
321
+ def log(str, name = nil)
322
+ if block_given?
323
+ if @logger and @logger.level <= Logger::INFO
324
+ result = nil
325
+ seconds = Benchmark.realtime { result = yield }
326
+ @runtime += seconds
327
+ log_info(str, name, seconds)
328
+ result
330
329
  else
331
- log_info(str, name, 0)
332
- nil
330
+ yield
333
331
  end
334
- rescue Exception => e
335
- # Log message and raise exception.
336
- # Set last_verfication to 0, so that connection gets verified
337
- # upon reentering the request loop
338
- @last_verification = 0
339
- message = "#{e.class.name}: #{e.message}: #{str}"
340
- log_info(message, name, 0)
341
- raise e
332
+ else
333
+ log_info(str, name, 0)
334
+ nil
342
335
  end
343
-
344
- def log_info(str, name, runtime)
345
- return unless @logger
346
-
347
- @logger.debug(
348
- format_log_entry(
349
- "#{name.nil? ? "HBASE" : name} (#{sprintf("%f", runtime)})",
350
- str.gsub(/ +/, " ")
351
- )
336
+ rescue Exception => e
337
+ # Log message and raise exception.
338
+ # Set last_verfication to 0, so that connection gets verified
339
+ # upon reentering the request loop
340
+ @last_verification = 0
341
+ message = "#{e.class.name}: #{e.message}: #{str}"
342
+ log_info(message, name, 0)
343
+ raise e
344
+ end
345
+
346
+ def log_info(str, name, runtime)
347
+ return unless @logger
348
+
349
+ @logger.debug(
350
+ format_log_entry(
351
+ "#{name.nil? ? "HBASE" : name} (#{sprintf("%f", runtime)})",
352
+ str.gsub(/ +/, " ")
352
353
  )
353
- end
354
-
355
- def format_log_entry(message, dump = nil)
356
- if BigRecord::Base.colorize_logging
357
- if @@row_even
358
- @@row_even = false
359
- message_color, dump_color = "4;36;1", "0;1"
360
- else
361
- @@row_even = true
362
- message_color, dump_color = "4;35;1", "0"
363
- end
354
+ )
355
+ end
364
356
 
365
- log_entry = " \e[#{message_color}m#{message}\e[0m "
366
- log_entry << "\e[#{dump_color}m%#{String === dump ? 's' : 'p'}\e[0m" % dump if dump
367
- log_entry
357
+ def format_log_entry(message, dump = nil)
358
+ if BigRecord::Base.colorize_logging
359
+ if @@row_even
360
+ @@row_even = false
361
+ message_color, dump_color = "4;36;1", "0;1"
368
362
  else
369
- "%s %s" % [message, dump]
363
+ @@row_even = true
364
+ message_color, dump_color = "4;35;1", "0"
370
365
  end
366
+
367
+ log_entry = " \e[#{message_color}m#{message}\e[0m "
368
+ log_entry << "\e[#{dump_color}m%#{String === dump ? 's' : 'p'}\e[0m" % dump if dump
369
+ log_entry
370
+ else
371
+ "%s %s" % [message, dump]
371
372
  end
373
+ end
374
+
372
375
  end
373
376
 
374
- class TableDefinition
377
+ class HbaseRestAdapterTable
375
378
 
376
379
  ##
377
380
  # Given an column descriptor's options hash from Bigrecord, translate it into
@@ -1,4 +1,18 @@
1
1
  module BigRecord
2
+
3
+ # = Dynamic Schema
4
+ #
5
+ # The dynamic schema functionality of Bigrecord refers to the ability to
6
+ # modify the attributes of a model within the class itself, rather than being
7
+ # bounded by the database. This is an inherit property of using the BigTable
8
+ # database model, and Bigrecord leverages its use.
9
+ #
10
+ # New attributes defined will simply return nil for records that existed
11
+ # before their addition into the model, while attributes that are removed
12
+ # from the model will just be ignored when accessing existing records.
13
+ #
14
+ # Refer to {BigRecord::ConnectionAdapters::Column} for more information.
15
+ #
2
16
  module DynamicSchema
3
17
 
4
18
  def self.included(base) #:nodoc:
@@ -3,12 +3,6 @@ module BigRecord
3
3
  class AssociationProxy #:nodoc:
4
4
  instance_methods.each { |m| undef_method m unless m =~ /(^__|^nil\?$|^send$|proxy_)/ }
5
5
 
6
- # def initialize(owner, reflection)
7
- # @owner, @reflection = owner, reflection
8
- # Array(reflection.options[:extend]).each { |ext| proxy_extend(ext) }
9
- # reset
10
- # end
11
-
12
6
  def find(id)
13
7
  @target.select{|s| s.id == id}.first
14
8
  end
@@ -1,5 +1,5 @@
1
1
  module BigRecord
2
- # Big Record automatically timestamps create and update if the table has fields
2
+ # BigRecord automatically timestamps create and update if the table has fields
3
3
  # created_at/created_on or updated_at/updated_on.
4
4
  #
5
5
  # Timestamping can be turned off by setting
@@ -15,7 +15,7 @@ module BigRecord
15
15
  # end
16
16
  #
17
17
  # Timestamps are in the local timezone by default but can use UTC by setting
18
- # <tt>ActiveRecord::Base.default_timezone = :utc</tt>
18
+ # <tt>BigRecord::Base.default_timezone = :utc</tt>
19
19
  module Timestamp
20
20
  def self.included(base) #:nodoc:
21
21
  super
@@ -49,3 +49,29 @@ module BigRecord
49
49
  end
50
50
  end
51
51
  end
52
+
53
+ # Open the Time class to add methods which convert the time into the Bigrecord
54
+ # timestamp format.
55
+ class Time
56
+
57
+ # Return the time in the Bigrecord timestamp format, i.e. a 'long' where the
58
+ # 4 high bytes contain the number of seconds since epoch and the 4 low bytes
59
+ # contain the microseconds.
60
+ #
61
+ # @example
62
+ # > Time.now.to_bigrecord_timestamp
63
+ # => 5410405886576175030
64
+ def to_bigrecord_timestamp
65
+ (self.to_i << 32) + self.usec
66
+ end
67
+
68
+ # Converts a timestamp in Bigrecord format into a regular Time object.
69
+ #
70
+ # @example
71
+ # > Time.from_bigrecord_timestamp(5410405886576175030)
72
+ # => Tue Dec 01 17:58:05 -0500 2009
73
+ def self.from_bigrecord_timestamp(timestamp)
74
+ Time.at(timestamp >> 32, timestamp & 0xFFFFFFFF)
75
+ end
76
+
77
+ end
data/lib/big_record.rb CHANGED
@@ -32,7 +32,7 @@ end
32
32
  begin
33
33
  require 'active_record'
34
34
  rescue LoadError
35
- puts "[Bigrecord] ActiveRecord could not be loaded. Bigrecord associations with AR models disabled."
35
+ raise LoadError, "Bigrecord depends on ActiveRecord. Install it with: gem install activerecord"
36
36
  end
37
37
 
38
38
  require dir + '/routing_ext'
@@ -40,7 +40,6 @@ require dir + '/abstract_base'
40
40
  require dir + '/base'
41
41
  require dir + '/embedded'
42
42
  require dir + '/validations'
43
- #require dir + '/callbacks'
44
43
  require dir + '/ar_reflection'
45
44
  require dir + '/br_reflection'
46
45
  require dir + '/ar_associations'
@@ -60,7 +59,6 @@ require dir + '/action_view_extensions'
60
59
 
61
60
  BigRecord::Base.class_eval do
62
61
  include BigRecord::Validations
63
- # include BigRecord::Callbacks
64
62
  include ActiveRecord::Callbacks
65
63
  include BigRecord::Timestamp
66
64
  include BigRecord::ArAssociations
@@ -75,7 +73,6 @@ end
75
73
 
76
74
  BigRecord::Embedded.class_eval do
77
75
  include BigRecord::Validations
78
- # include BigRecord::Callbacks
79
76
  include ActiveRecord::Callbacks
80
77
  include BigRecord::Timestamp
81
78
  include BigRecord::ArAssociations
data/lib/bigrecord.rb CHANGED
@@ -1 +1 @@
1
- require 'big_record'
1
+ require File.join(File.dirname(__FILE__), 'big_record')
@@ -1,7 +1,7 @@
1
- hbase:
1
+ hbase_rest:
2
2
  adapter: hbase_rest
3
3
  api_address: http://localhost:8080
4
- hbase_brd:
4
+ hbase:
5
5
  adapter: hbase
6
6
  zookeeper_quorum: localhost
7
7
  zookeeper_client_port: 2181