bigrecord 0.0.8 → 0.0.9
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +5 -4
- data/VERSION +1 -1
- data/lib/big_record/abstract_base.rb +21 -14
- data/lib/big_record/base.rb +38 -30
- data/lib/big_record/br_associations.rb +100 -773
- data/lib/big_record/br_reflection.rb +1 -3
- data/lib/big_record/connection_adapters/abstract/database_statements.rb +1 -161
- data/lib/big_record/connection_adapters/abstract_adapter.rb +1 -17
- data/lib/big_record/connection_adapters/column.rb +1 -30
- data/lib/big_record/connection_adapters/hbase_adapter.rb +18 -16
- data/lib/big_record/connection_adapters/hbase_rest_adapter.rb +64 -61
- data/lib/big_record/dynamic_schema.rb +14 -0
- data/lib/big_record/embedded_associations/association_proxy.rb +0 -6
- data/lib/big_record/timestamp.rb +28 -2
- data/lib/big_record.rb +1 -4
- data/lib/bigrecord.rb +1 -1
- data/spec/connections/bigrecord.yml +2 -2
- data/spec/debug.log +215 -172
- data/spec/unit/ar_associations_spec.rb +0 -7
- data/spec/unit/{abstract_base_spec.rb → attributes_spec.rb} +20 -3
- data/spec/unit/callback_spec.rb +1 -0
- data/spec/unit/{base_spec.rb → columns_spec.rb} +2 -2
- data/spec/unit/embedded_spec.rb +1 -1
- data/spec/unit/find_spec.rb +10 -0
- data/spec/unit/model_spec.rb +13 -4
- data/spec/unit/scanner_spec.rb +44 -0
- data/tasks/gem.rb +0 -1
- data/tasks/rdoc.rb +1 -1
- metadata +6 -14
@@ -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
|
-
#
|
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
|
-
#
|
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 =
|
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
|
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
|
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 =
|
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
|
-
|
314
|
+
private
|
314
315
|
|
315
|
-
|
316
|
-
|
316
|
+
def connect
|
317
|
+
end
|
317
318
|
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
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
|
-
|
332
|
-
nil
|
330
|
+
yield
|
333
331
|
end
|
334
|
-
|
335
|
-
|
336
|
-
|
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
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
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
|
-
|
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
|
-
|
366
|
-
|
367
|
-
|
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
|
-
|
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
|
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
|
data/lib/big_record/timestamp.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
module BigRecord
|
2
|
-
#
|
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>
|
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
|
-
|
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')
|