activerecord-hbase-adapter 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c9b0cf4fd299122fc45486397c36ccc43e2923c6
4
+ data.tar.gz: 109f0b4a74e3a763eee842152117aeee01a3ec21
5
+ SHA512:
6
+ metadata.gz: efdc375a03df4c79831f209565ad5ce1a377c758054d3c753802a1ce168799cd71178e40b6ad5b0e63cb05c779f04cfe1a8b1feb588ab6fae59f33c3414dbfe2
7
+ data.tar.gz: 758e44e26fb0884febac15e40e503b2f809d6aa052aecc93601efaa06499c29ce486c321760da4064f96d7bdbd1ad87a87f306e0e3031afd3546634878a9166c
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
@@ -0,0 +1,37 @@
1
+ # vim:fileencoding=utf-8
2
+ require File.expand_path('../lib/activerecord-hbase-adapter/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Jean Lescure"]
6
+ gem.email = ["jean@agilityfeat.com"]
7
+ gem.description = %q{HBase ActiveRecord adapter based on HipsterSqlToHbase}
8
+ gem.summary = %q{HBase ActiveRecord adapter based on HipsterSqlToHbase}
9
+ gem.homepage = %q{http://github.com/jeanlescure/activerecord-hbase-adapter}
10
+
11
+ gem.files = [ 'Gemfile',
12
+ 'activerecord-hbase-adapter.gemspec',
13
+ 'lib/activerecord-hbase-adapter/version.rb',
14
+ 'lib/active_record/connection_adapters/hbase_adapter.rb']
15
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
16
+ gem.name = "activerecord-hbase-adapter"
17
+ gem.require_paths = ["lib"]
18
+ gem.version = Activerecord::Hbase::Adapter::VERSION
19
+
20
+ if gem.respond_to? :specification_version then
21
+ gem.specification_version = 4
22
+
23
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
24
+ gem.add_runtime_dependency(%q<hipster_sql_to_hbase>, [">= 0"])
25
+ gem.add_runtime_dependency(%q<httparty>, [">= 0"])
26
+ gem.add_runtime_dependency(%q<msgpack>, [">= 0"])
27
+ else
28
+ gem.add_dependency(%q<hipster_sql_to_hbase>, [">= 0"])
29
+ gem.add_dependency(%q<httparty>, [">= 0"])
30
+ gem.add_dependency(%q<msgpack>, [">= 0"])
31
+ end
32
+ else
33
+ gem.add_dependency(%q<hipster_sql_to_hbase>, [">= 0"])
34
+ gem.add_dependency(%q<httparty>, [">= 0"])
35
+ gem.add_dependency(%q<msgpack>, [">= 0"])
36
+ end
37
+ end
@@ -0,0 +1,300 @@
1
+ require 'active_record/connection_adapters/abstract_mysql_adapter'
2
+ require 'active_record/connection_adapters/hbase/error'
3
+ require 'active_record/connection_adapters/hbase/result'
4
+ require 'active_record/connection_adapters/hbase/client'
5
+
6
+ ### FOR DEBUGGING ONLY ###
7
+ #$LOAD_PATH.unshift '/home/jean/adapter/lib/mysql2/lib'
8
+ #require 'mysql2'
9
+ ### FOR DEBUGGING ONLY ###
10
+
11
+ require 'hipster_sql_to_hbase'
12
+
13
+ module ActiveRecord
14
+ module ConnectionHandling # :nodoc:
15
+ # Establishes a connection to the database that's used by all Active Record objects.
16
+ def hbase_connection(config)
17
+ config = config.symbolize_keys
18
+
19
+ config[:username] = 'root' if config[:username].nil?
20
+
21
+ ### FOR DEBUGGING ONLY ###
22
+ #if Mysql2::Client.const_defined? :FOUND_ROWS
23
+ # config[:flags] = Mysql2::Client::FOUND_ROWS
24
+ #end
25
+ #config[:host] = config[:m2host]
26
+ #config[:port] = config[:m2port]
27
+ #client = Mysql2::Client.new(config)
28
+ ### FOR DEBUGGING ONLY ###
29
+
30
+ client = HbaseRestIface::Client.new(config)
31
+ options = [config[:host], config[:username], config[:password], config[:database], config[:port], config[:socket], 0]
32
+ ConnectionAdapters::HbaseAdapter.new(client, logger, options, config)
33
+ rescue Hbase::Error => error
34
+ if error.message.include?("Unknown database")
35
+ raise ActiveRecord::NoDatabaseError.new(error.message)
36
+ else
37
+ raise error
38
+ end
39
+ end
40
+ end
41
+
42
+ module ConnectionAdapters
43
+ class HbaseAdapter < AbstractMysqlAdapter
44
+
45
+
46
+ class Column < AbstractMysqlAdapter::Column # :nodoc:
47
+ def adapter
48
+ HbaseAdapter
49
+ end
50
+ end
51
+
52
+ ADAPTER_NAME = 'Hbase'
53
+
54
+ def initialize(connection, logger, connection_options, config)
55
+ super
56
+
57
+ @visitor = BindSubstitution.new self
58
+ configure_connection
59
+ end
60
+
61
+ MAX_INDEX_LENGTH_FOR_UTF8MB4 = 191
62
+ def initialize_schema_migrations_table
63
+ if @config[:encoding] == 'utf8mb4'
64
+ ActiveRecord::SchemaMigration.create_table(MAX_INDEX_LENGTH_FOR_UTF8MB4)
65
+ else
66
+ ActiveRecord::SchemaMigration.create_table
67
+ end
68
+ end
69
+
70
+ def supports_explain?
71
+ true
72
+ end
73
+
74
+ # HELPER METHODS ===========================================
75
+
76
+ def each_hash(result) # :nodoc:
77
+
78
+ if block_given?
79
+ result.each(:as => :hash, :symbolize_keys => true) do |row|
80
+ yield row
81
+ end
82
+ else
83
+ to_enum(:each_hash, result)
84
+ end
85
+ end
86
+
87
+ def new_column(field, default, type, null, collation, extra = "") # :nodoc:
88
+ Column.new(field, default, type, null, collation, strict_mode?, extra)
89
+ end
90
+
91
+ def error_number(exception)
92
+ exception.error_number if exception.respond_to?(:error_number)
93
+ end
94
+
95
+ # QUOTING ==================================================
96
+
97
+ def quote_string(string)
98
+ @connection.escape(string)
99
+ end
100
+
101
+ # CONNECTION MANAGEMENT ====================================
102
+
103
+ def active?
104
+ return false unless @connection
105
+ @connection.ping
106
+ end
107
+
108
+ def reconnect!
109
+ super
110
+ disconnect!
111
+ connect
112
+ end
113
+ alias :reset! :reconnect!
114
+
115
+ # Disconnects from the database if already connected.
116
+ # Otherwise, this method does nothing.
117
+ def disconnect!
118
+ super
119
+ unless @connection.nil?
120
+ @connection.close
121
+ @connection = nil
122
+ end
123
+ end
124
+
125
+ # DATABASE STATEMENTS ======================================
126
+
127
+ def explain(arel, binds = [])
128
+ sql = "EXPLAIN #{to_sql(arel, binds.dup)}"
129
+ start = Time.now
130
+ result = exec_query(sql, 'EXPLAIN', binds)
131
+ elapsed = Time.now - start
132
+
133
+ ExplainPrettyPrinter.new.pp(result, elapsed)
134
+ end
135
+
136
+ class ExplainPrettyPrinter # :nodoc:
137
+ # Pretty prints the result of a EXPLAIN in a way that resembles the output of the
138
+ # MySQL shell:
139
+ #
140
+ # +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+
141
+ # | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
142
+ # +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+
143
+ # | 1 | SIMPLE | users | const | PRIMARY | PRIMARY | 4 | const | 1 | |
144
+ # | 1 | SIMPLE | posts | ALL | NULL | NULL | NULL | NULL | 1 | Using where |
145
+ # +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+
146
+ # 2 rows in set (0.00 sec)
147
+ #
148
+ # This is an exercise in Ruby hyperrealism :).
149
+ def pp(result, elapsed)
150
+ widths = compute_column_widths(result)
151
+ separator = build_separator(widths)
152
+
153
+ pp = []
154
+
155
+ pp << separator
156
+ pp << build_cells(result.columns, widths)
157
+ pp << separator
158
+
159
+ result.rows.each do |row|
160
+ pp << build_cells(row, widths)
161
+ end
162
+
163
+ pp << separator
164
+ pp << build_footer(result.rows.length, elapsed)
165
+
166
+ pp.join("\n") + "\n"
167
+ end
168
+
169
+ private
170
+
171
+ def compute_column_widths(result)
172
+ [].tap do |widths|
173
+ result.columns.each_with_index do |column, i|
174
+ cells_in_column = [column] + result.rows.map {|r| r[i].nil? ? 'NULL' : r[i].to_s}
175
+ widths << cells_in_column.map(&:length).max
176
+ end
177
+ end
178
+ end
179
+
180
+ def build_separator(widths)
181
+ padding = 1
182
+ '+' + widths.map {|w| '-' * (w + (padding*2))}.join('+') + '+'
183
+ end
184
+
185
+ def build_cells(items, widths)
186
+ cells = []
187
+ items.each_with_index do |item, i|
188
+ item = 'NULL' if item.nil?
189
+ justifier = item.is_a?(Numeric) ? 'rjust' : 'ljust'
190
+ cells << item.to_s.send(justifier, widths[i])
191
+ end
192
+ '| ' + cells.join(' | ') + ' |'
193
+ end
194
+
195
+ def build_footer(nrows, elapsed)
196
+ rows_label = nrows == 1 ? 'row' : 'rows'
197
+ "#{nrows} #{rows_label} in set (%.2f sec)" % elapsed
198
+ end
199
+ end
200
+
201
+ # FIXME: re-enable the following once a "better" query_cache solution is in core
202
+ #
203
+ # The overrides below perform much better than the originals in AbstractAdapter
204
+ # because we're able to take advantage of hbase's lazy-loading capabilities
205
+ #
206
+ # # Returns a record hash with the column names as keys and column values
207
+ # # as values.
208
+ # def select_one(sql, name = nil)
209
+ # result = execute(sql, name)
210
+ # result.each(as: :hash) do |r|
211
+ # return r
212
+ # end
213
+ # end
214
+ #
215
+ # # Returns a single value from a record
216
+ # def select_value(sql, name = nil)
217
+ # result = execute(sql, name)
218
+ # if first = result.first
219
+ # first.first
220
+ # end
221
+ # end
222
+ #
223
+ # # Returns an array of the values of the first column in a select:
224
+ # # select_values("SELECT id FROM companies LIMIT 3") => [1,2,3]
225
+ # def select_values(sql, name = nil)
226
+ # execute(sql, name).map { |row| row.first }
227
+ # end
228
+
229
+ # Returns an array of arrays containing the field values.
230
+ # Order is the same as that returned by +columns+.
231
+ def select_rows(sql, name = nil, binds = [])
232
+ execute(sql, name).to_a
233
+ end
234
+
235
+ # Executes the SQL statement in the context of this connection.
236
+ def execute(sql, name = nil)
237
+ if @connection
238
+ # make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been
239
+ # made since we established the connection
240
+ @connection.query_options[:database_timezone] = ActiveRecord::Base.default_timezone
241
+ end
242
+
243
+ super
244
+ end
245
+
246
+ def exec_query(sql, name = 'SQL', binds = [])
247
+ result = execute(sql, name)
248
+ ActiveRecord::Result.new(result.fields, result.to_a)
249
+ end
250
+
251
+ alias exec_without_stmt exec_query
252
+
253
+ # Returns an ActiveRecord::Result instance.
254
+ def select(sql, name = nil, binds = [])
255
+ exec_query(sql, name)
256
+ end
257
+
258
+ def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
259
+ super
260
+ id_value || @connection.last_id
261
+ end
262
+ alias :create :insert_sql
263
+
264
+ def exec_insert(sql, name, binds, pk = nil, sequence_name = nil)
265
+ execute to_sql(sql, binds), name
266
+ end
267
+
268
+ def exec_delete(sql, name, binds)
269
+ execute to_sql(sql, binds), name
270
+ @connection.affected_rows
271
+ end
272
+ alias :exec_update :exec_delete
273
+
274
+ def last_inserted_id(result)
275
+ @connection.last_id
276
+ end
277
+
278
+ private
279
+
280
+ def connect
281
+ #@connection = Mysql2::Client.new(@config)
282
+ @connection = HbaseRestIface::Client.new(:host => @config[:hb_host], :port => @config[:hb_port])
283
+ configure_connection
284
+ end
285
+
286
+ def configure_connection
287
+ @connection.query_options.merge!(:as => :array)
288
+ super
289
+ end
290
+
291
+ def full_version
292
+ @full_version ||= @connection.info[:version]
293
+ end
294
+
295
+ def set_field_encoding field_name
296
+ field_name
297
+ end
298
+ end
299
+ end
300
+ end
@@ -0,0 +1,7 @@
1
+ module Activerecord
2
+ module Hbase
3
+ module Adapter
4
+ VERSION = "0.0.7"
5
+ end
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: activerecord-hbase-adapter
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.7
5
+ platform: ruby
6
+ authors:
7
+ - Jean Lescure
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-10-05 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: hipster_sql_to_hbase
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: httparty
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: msgpack
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: HBase ActiveRecord adapter based on HipsterSqlToHbase
56
+ email:
57
+ - jean@agilityfeat.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - Gemfile
63
+ - activerecord-hbase-adapter.gemspec
64
+ - lib/active_record/connection_adapters/hbase_adapter.rb
65
+ - lib/activerecord-hbase-adapter/version.rb
66
+ homepage: http://github.com/jeanlescure/activerecord-hbase-adapter
67
+ licenses: []
68
+ metadata: {}
69
+ post_install_message:
70
+ rdoc_options: []
71
+ require_paths:
72
+ - lib
73
+ required_ruby_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ required_rubygems_version: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ requirements: []
84
+ rubyforge_project:
85
+ rubygems_version: 2.2.2
86
+ signing_key:
87
+ specification_version: 4
88
+ summary: HBase ActiveRecord adapter based on HipsterSqlToHbase
89
+ test_files: []