activerecord-hbase-adapter 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: []