baza 0.0.14 → 0.0.15

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.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +58 -13
  3. data/VERSION +1 -1
  4. data/baza.gemspec +15 -3
  5. data/include/db.rb +871 -865
  6. data/include/drivers/mysql/mysql.rb +104 -297
  7. data/include/drivers/mysql/mysql_column.rb +133 -0
  8. data/include/drivers/mysql/mysql_columns.rb +4 -127
  9. data/include/drivers/mysql/mysql_index.rb +76 -0
  10. data/include/drivers/mysql/mysql_indexes.rb +0 -73
  11. data/include/drivers/mysql/mysql_result.rb +42 -0
  12. data/include/drivers/mysql/mysql_result_java.rb +61 -0
  13. data/include/drivers/mysql/mysql_result_mysql2.rb +26 -0
  14. data/include/drivers/mysql/mysql_result_unbuffered.rb +72 -0
  15. data/include/drivers/mysql/mysql_sqlspecs.rb +1 -1
  16. data/include/drivers/mysql/mysql_table.rb +361 -0
  17. data/include/drivers/mysql/mysql_tables.rb +23 -381
  18. data/include/drivers/sqlite3/libknjdb_java_sqlite3.rb +17 -22
  19. data/include/drivers/sqlite3/libknjdb_sqlite3_ironruby.rb +13 -13
  20. data/include/drivers/sqlite3/sqlite3.rb +39 -105
  21. data/include/drivers/sqlite3/sqlite3_column.rb +146 -0
  22. data/include/drivers/sqlite3/sqlite3_columns.rb +17 -149
  23. data/include/drivers/sqlite3/sqlite3_index.rb +55 -0
  24. data/include/drivers/sqlite3/sqlite3_indexes.rb +0 -52
  25. data/include/drivers/sqlite3/sqlite3_result.rb +35 -0
  26. data/include/drivers/sqlite3/sqlite3_result_java.rb +39 -0
  27. data/include/drivers/sqlite3/sqlite3_table.rb +399 -0
  28. data/include/drivers/sqlite3/sqlite3_tables.rb +7 -403
  29. data/include/idquery.rb +19 -19
  30. data/include/model.rb +139 -139
  31. data/include/model_handler_sqlhelper.rb +74 -74
  32. data/spec/support/driver_columns_collection.rb +17 -0
  33. metadata +14 -2
@@ -1,70 +1,82 @@
1
1
  class Baza::Driver::Mysql
2
+ autoload :Table, "#{File.dirname(__FILE__)}/mysql_table"
3
+ autoload :Tables, "#{File.dirname(__FILE__)}/mysql_tables"
4
+ autoload :Column, "#{File.dirname(__FILE__)}/mysql_column"
5
+ autoload :Columns, "#{File.dirname(__FILE__)}/mysql_columns"
6
+ autoload :Index, "#{File.dirname(__FILE__)}/mysql_index"
7
+ autoload :Indexes, "#{File.dirname(__FILE__)}/mysql_indexes"
8
+ autoload :Result, "#{File.dirname(__FILE__)}/mysql_result"
9
+ autoload :ResultJava, "#{File.dirname(__FILE__)}/mysql_result_java"
10
+ autoload :ResultMysql2, "#{File.dirname(__FILE__)}/mysql_result_mysql2"
11
+ autoload :ResultUnbuffered, "#{File.dirname(__FILE__)}/mysql_result_unbuffered"
12
+ autoload :Sqlspecs, "#{File.dirname(__FILE__)}/mysql_sqlspecs"
13
+
2
14
  attr_reader :baza, :conn, :conns, :sep_table, :sep_col, :sep_val
3
15
  attr_accessor :tables, :cols, :indexes
4
-
16
+
5
17
  #Helper to enable automatic registering of database using Baza::Db.from_object
6
18
  def self.from_object(args)
7
19
  if args[:object].class.name == "Mysql2::Client"
8
20
  return {
9
- :type => :success,
10
- :args => {
11
- :type => :mysql,
12
- :subtype => :mysql2,
13
- :conn => args[:object],
14
- :query_args => {
15
- :as => :hash,
16
- :symbolize_keys => true
21
+ type: :success,
22
+ args: {
23
+ type: :mysql,
24
+ subtype: :mysql2,
25
+ conn: args[:object],
26
+ query_args: {
27
+ as: :hash,
28
+ symbolize_keys: true
17
29
  }
18
30
  }
19
31
  }
20
32
  end
21
-
33
+
22
34
  return nil
23
35
  end
24
-
36
+
25
37
  def initialize(baza_db_obj)
26
38
  @baza_db = baza_db_obj
27
39
  @opts = @baza_db.opts
28
40
  @sep_table = "`"
29
41
  @sep_col = "`"
30
42
  @sep_val = "'"
31
-
43
+
32
44
  require "monitor"
33
45
  @mutex = Monitor.new
34
-
46
+
35
47
  if @opts[:encoding]
36
48
  @encoding = @opts[:encoding]
37
49
  else
38
50
  @encoding = "utf8"
39
51
  end
40
-
52
+
41
53
  if @baza_db.opts.key?(:port)
42
54
  @port = @baza_db.opts[:port].to_i
43
55
  else
44
56
  @port = 3306
45
57
  end
46
-
58
+
47
59
  @java_rs_data = {}
48
60
  @subtype = @baza_db.opts[:subtype]
49
61
  @subtype = :mysql if @subtype.to_s.empty?
50
62
  self.reconnect
51
63
  end
52
-
64
+
53
65
  #This method handels the closing of statements and results for the Java MySQL-mode.
54
66
  def java_mysql_resultset_killer(id)
55
67
  data = @java_rs_data[id]
56
68
  return nil if !data
57
-
69
+
58
70
  data[:res].close
59
71
  data[:stmt].close
60
72
  @java_rs_data.delete(id)
61
73
  end
62
-
74
+
63
75
  #Cleans the wref-map holding the tables.
64
76
  def clean
65
77
  self.tables.clean if self.tables
66
78
  end
67
-
79
+
68
80
  #Respawns the connection to the MySQL-database.
69
81
  def reconnect
70
82
  @mutex.synchronize do
@@ -74,28 +86,28 @@ class Baza::Driver::Mysql
74
86
  when :mysql2
75
87
  require "rubygems"
76
88
  require "mysql2"
77
-
89
+
78
90
  args = {
79
- :host => @baza_db.opts[:host],
80
- :username => @baza_db.opts[:user],
81
- :password => @baza_db.opts[:pass],
82
- :database => @baza_db.opts[:db],
83
- :port => @port,
84
- :symbolize_keys => true,
85
- :cache_rows => false
91
+ host: @baza_db.opts[:host],
92
+ username: @baza_db.opts[:user],
93
+ password: @baza_db.opts[:pass],
94
+ database: @baza_db.opts[:db],
95
+ port: @port,
96
+ symbolize_keys: true,
97
+ cache_rows: false
86
98
  }
87
-
99
+
88
100
  #Symbolize keys should also be given here, else table-data wont be symbolized for some reason - knj.
89
- @query_args = {:symbolize_keys => true}
101
+ @query_args = {symbolize_keys: true}
90
102
  @query_args.merge!(@baza_db.opts[:query_args]) if @baza_db.opts[:query_args]
91
-
103
+
92
104
  pos_args = [:as, :async, :cast_booleans, :database_timezone, :application_timezone, :cache_rows, :connect_flags, :cast]
93
105
  pos_args.each do |key|
94
106
  args[key] = @baza_db.opts[key] if @baza_db.opts.key?(key)
95
107
  end
96
-
108
+
97
109
  args[:as] = :array if @opts[:result] == "array"
98
-
110
+
99
111
  tries = 0
100
112
  begin
101
113
  tries += 1
@@ -112,33 +124,33 @@ class Baza::Driver::Mysql
112
124
  retry
113
125
  end
114
126
  end
115
-
127
+
116
128
  raise e
117
129
  end
118
130
  when :java
119
- if !@jdbc_loaded
131
+ unless @jdbc_loaded
120
132
  require "java"
121
133
  require "/usr/share/java/mysql-connector-java.jar" if File.exists?("/usr/share/java/mysql-connector-java.jar")
122
134
  import "com.mysql.jdbc.Driver"
123
135
  @jdbc_loaded = true
124
136
  end
125
-
137
+
126
138
  @conn = java.sql::DriverManager.getConnection("jdbc:mysql://#{@baza_db.opts[:host]}:#{@port}/#{@baza_db.opts[:db]}?user=#{@baza_db.opts[:user]}&password=#{@baza_db.opts[:pass]}&populateInsertRowWithDefaultValues=true&zeroDateTimeBehavior=round&characterEncoding=#{@encoding}&holdResultsOpenOverStatementClose=true")
127
- self.query("SET SQL_MODE = ''")
139
+ query("SET SQL_MODE = ''")
128
140
  else
129
141
  raise "Unknown subtype: #{@subtype} (#{@subtype.class.name})"
130
142
  end
131
-
132
- self.query("SET NAMES '#{self.esc(@encoding)}'") if @encoding
143
+
144
+ query("SET NAMES '#{self.esc(@encoding)}'") if @encoding
133
145
  end
134
146
  end
135
-
147
+
136
148
  #Executes a query and returns the result.
137
149
  def query(str)
138
150
  str = str.to_s
139
151
  str = str.force_encoding("UTF-8") if @encoding == "utf8" and str.respond_to?(:force_encoding)
140
152
  tries = 0
141
-
153
+
142
154
  begin
143
155
  tries += 1
144
156
  @mutex.synchronize do
@@ -146,33 +158,33 @@ class Baza::Driver::Mysql
146
158
  when :mysql
147
159
  return Baza::Driver::Mysql::Result.new(self, @conn.query(str))
148
160
  when :mysql2
149
- return Baza::Driver::Mysql::ResultMySQL2.new(@conn.query(str, @query_args))
161
+ return Baza::Driver::Mysql::ResultMysql2.new(@conn.query(str, @query_args))
150
162
  when :java
151
163
  stmt = conn.create_statement
152
-
164
+
153
165
  if str.match(/^\s*(delete|update|create|drop|insert\s+into|alter)\s+/i)
154
166
  begin
155
167
  stmt.execute(str)
156
168
  ensure
157
169
  stmt.close
158
170
  end
159
-
171
+
160
172
  return nil
161
173
  else
162
174
  id = nil
163
-
175
+
164
176
  begin
165
177
  res = stmt.execute_query(str)
166
178
  ret = Baza::Driver::Mysql::ResultJava.new(@baza_db, @opts, res)
167
179
  id = ret.__id__
168
-
180
+
169
181
  #If ID is being reused we have to free the result.
170
182
  self.java_mysql_resultset_killer(id) if @java_rs_data.key?(id)
171
-
183
+
172
184
  #Save reference to result and statement, so we can close them when they are garbage collected.
173
- @java_rs_data[id] = {:res => res, :stmt => stmt}
174
- ObjectSpace.define_finalizer(ret, self.method(:java_mysql_resultset_killer))
175
-
185
+ @java_rs_data[id] = {res: res, stmt: stmt}
186
+ ObjectSpace.define_finalizer(ret, method(:java_mysql_resultset_killer))
187
+
176
188
  return ret
177
189
  rescue => e
178
190
  res.close if res
@@ -187,20 +199,20 @@ class Baza::Driver::Mysql
187
199
  end
188
200
  rescue => e
189
201
  if tries <= 3
190
- if e.message == "MySQL server has gone away" or e.message == "closed MySQL connection" or e.message == "Can't connect to local MySQL server through socket"
202
+ if e.message == "MySQL server has gone away" || e.message == "closed MySQL connection" or e.message == "Can't connect to local MySQL server through socket"
191
203
  sleep 0.5
192
- self.reconnect
204
+ reconnect
193
205
  retry
194
206
  elsif e.message.include?("No operations allowed after connection closed") or e.message == "This connection is still waiting for a result, try again once you have the result" or e.message == "Lock wait timeout exceeded; try restarting transaction"
195
- self.reconnect
207
+ reconnect
196
208
  retry
197
209
  end
198
210
  end
199
-
211
+
200
212
  raise e
201
213
  end
202
214
  end
203
-
215
+
204
216
  #Executes an unbuffered query and returns the result that can be used to access the data.
205
217
  def query_ubuf(str)
206
218
  @mutex.synchronize do
@@ -213,26 +225,26 @@ class Baza::Driver::Mysql
213
225
  when :java
214
226
  if str.match(/^\s*(delete|update|create|drop|insert\s+into)\s+/i)
215
227
  stmt = @conn.createStatement
216
-
228
+
217
229
  begin
218
230
  stmt.execute(str)
219
231
  ensure
220
232
  stmt.close
221
233
  end
222
-
234
+
223
235
  return nil
224
236
  else
225
237
  stmt = @conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY, java.sql.ResultSet.CONCUR_READ_ONLY)
226
238
  stmt.setFetchSize(java.lang.Integer::MIN_VALUE)
227
-
239
+
228
240
  begin
229
241
  res = stmt.executeQuery(str)
230
242
  ret = Baza::Driver::Mysql::ResultJava.new(@baza_db, @opts, res)
231
-
243
+
232
244
  #Save reference to result and statement, so we can close them when they are garbage collected.
233
- @java_rs_data[ret.__id__] = {:res => res, :stmt => stmt}
234
- ObjectSpace.define_finalizer(ret, self.method("java_mysql_resultset_killer"))
235
-
245
+ @java_rs_data[ret.__id__] = {res: res, stmt: stmt}
246
+ ObjectSpace.define_finalizer(ret, method("java_mysql_resultset_killer"))
247
+
236
248
  return ret
237
249
  rescue => e
238
250
  res.close if res
@@ -245,7 +257,7 @@ class Baza::Driver::Mysql
245
257
  end
246
258
  end
247
259
  end
248
-
260
+
249
261
  #Escapes a string to be safe to use in a query.
250
262
  def escape_alternative(string)
251
263
  case @subtype
@@ -254,12 +266,12 @@ class Baza::Driver::Mysql
254
266
  when :mysql2
255
267
  return @conn.escape(string.to_s)
256
268
  when :java
257
- return self.escape(string)
269
+ return escape(string)
258
270
  else
259
271
  raise "Unknown subtype: '#{@subtype}'."
260
272
  end
261
273
  end
262
-
274
+
263
275
  #An alternative to the MySQL framework's escape. This is copied from the Ruby/MySQL framework at: http://www.tmtm.org/en/ruby/mysql/
264
276
  def escape(string)
265
277
  return string.to_s.gsub(/([\0\n\r\032\'\"\\])/) do
@@ -272,19 +284,19 @@ class Baza::Driver::Mysql
272
284
  end
273
285
  end
274
286
  end
275
-
287
+
276
288
  #Escapes a string to be safe to use as a column in a query.
277
289
  def esc_col(string)
278
290
  string = string.to_s
279
291
  raise "Invalid column-string: #{string}" if string.include?(@sep_col)
280
292
  return string
281
293
  end
282
-
294
+
283
295
  alias :esc_table :esc_col
284
296
  alias :esc :escape
285
-
297
+
286
298
  #Returns the last inserted ID for the connection.
287
- def lastID
299
+ def last_id
288
300
  case @subtype
289
301
  when :mysql
290
302
  @mutex.synchronize do
@@ -300,14 +312,14 @@ class Baza::Driver::Mysql
300
312
  raise "Could not figure out last inserted ID."
301
313
  end
302
314
  end
303
-
315
+
304
316
  #Closes the connection threadsafe.
305
317
  def close
306
318
  @mutex.synchronize do
307
319
  @conn.close
308
320
  end
309
321
  end
310
-
322
+
311
323
  #Destroyes the connection.
312
324
  def destroy
313
325
  @conn = nil
@@ -318,28 +330,28 @@ class Baza::Driver::Mysql
318
330
  @query_args = nil
319
331
  @port = nil
320
332
  end
321
-
333
+
322
334
  #Inserts multiple rows in a table. Can return the inserted IDs if asked to in arguments.
323
335
  def insert_multi(tablename, arr_hashes, args = nil)
324
336
  sql = "INSERT INTO `#{tablename}` ("
325
-
337
+
326
338
  first = true
327
- if args and args[:keys]
339
+ if args && args[:keys]
328
340
  keys = args[:keys]
329
341
  elsif arr_hashes.first.is_a?(Hash)
330
342
  keys = arr_hashes.first.keys
331
343
  else
332
344
  raise "Could not figure out keys."
333
345
  end
334
-
346
+
335
347
  keys.each do |col_name|
336
- sql << "," if !first
348
+ sql << "," unless first
337
349
  first = false if first
338
350
  sql << "`#{self.esc_col(col_name)}`"
339
351
  end
340
-
352
+
341
353
  sql << ") VALUES ("
342
-
354
+
343
355
  first = true
344
356
  arr_hashes.each do |hash|
345
357
  if first
@@ -347,7 +359,7 @@ class Baza::Driver::Mysql
347
359
  else
348
360
  sql << "),("
349
361
  end
350
-
362
+
351
363
  first_key = true
352
364
  if hash.is_a?(Array)
353
365
  hash.each do |val|
@@ -356,7 +368,7 @@ class Baza::Driver::Mysql
356
368
  else
357
369
  sql << ","
358
370
  end
359
-
371
+
360
372
  sql << @baza_db.sqlval(val)
361
373
  end
362
374
  else
@@ -366,42 +378,42 @@ class Baza::Driver::Mysql
366
378
  else
367
379
  sql << ","
368
380
  end
369
-
381
+
370
382
  sql << @baza_db.sqlval(val)
371
383
  end
372
384
  end
373
385
  end
374
-
386
+
375
387
  sql << ")"
376
-
377
- return sql if args and args[:return_sql]
378
-
388
+
389
+ return sql if args && args[:return_sql]
390
+
379
391
  self.query(sql)
380
-
381
- if args and args[:return_id]
382
- first_id = self.lastID
392
+
393
+ if args && args[:return_id]
394
+ first_id = self.last_id
383
395
  raise "Invalid ID: #{first_id}" if first_id.to_i <= 0
384
396
  ids = [first_id]
385
397
  1.upto(arr_hashes.length - 1) do |count|
386
398
  ids << first_id + count
387
399
  end
388
-
400
+
389
401
  ids_length = ids.length
390
402
  arr_hashes_length = arr_hashes.length
391
403
  raise "Invalid length (#{ids_length}, #{arr_hashes_length})." if ids_length != arr_hashes_length
392
-
404
+
393
405
  return ids
394
406
  else
395
407
  return nil
396
408
  end
397
409
  end
398
-
410
+
399
411
  #Starts a transaction, yields the database and commits at the end.
400
412
  def transaction
401
413
  @baza_db.q("START TRANSACTION")
402
-
414
+
403
415
  begin
404
- yield(@baza_db)
416
+ yield @baza_db
405
417
  @baza_db.q("COMMIT")
406
418
  rescue
407
419
  @baza_db.q("ROLLBACK")
@@ -409,208 +421,3 @@ class Baza::Driver::Mysql
409
421
  end
410
422
  end
411
423
  end
412
-
413
- #This class controls the results for the normal MySQL-driver.
414
- class Baza::Driver::Mysql::Result
415
- #Constructor. This should not be called manually.
416
- def initialize(driver, result)
417
- @driver = driver
418
- @result = result
419
- @mutex = Mutex.new
420
-
421
- if @result
422
- @keys = []
423
- @result.fetch_fields.each do |key|
424
- @keys << key.name.to_sym
425
- end
426
- end
427
- end
428
-
429
- #Returns a single result as a hash with symbols as keys.
430
- def fetch
431
- fetched = nil
432
- @mutex.synchronize do
433
- fetched = @result.fetch_row
434
- end
435
-
436
- return false if !fetched
437
-
438
- ret = {}
439
- count = 0
440
- @keys.each do |key|
441
- ret[key] = fetched[count]
442
- count += 1
443
- end
444
-
445
- return ret
446
- end
447
-
448
- #Loops over every result yielding it.
449
- def each
450
- while data = self.fetch
451
- yield(data)
452
- end
453
- end
454
- end
455
-
456
- #This class controls the unbuffered result for the normal MySQL-driver.
457
- class Baza::Driver::Mysql::ResultUnbuffered
458
- #Constructor. This should not be called manually.
459
- def initialize(conn, opts, result)
460
- @conn = conn
461
- @result = result
462
-
463
- if !opts.key?(:result) or opts[:result] == "hash"
464
- @as_hash = true
465
- elsif opts[:result] == "array"
466
- @as_hash = false
467
- else
468
- raise "Unknown type of result: '#{opts[:result]}'."
469
- end
470
- end
471
-
472
- #Lods the keys for the object.
473
- def load_keys
474
- @keys = []
475
- keys = @res.fetch_fields
476
- keys.each do |key|
477
- @keys << key.name.to_sym
478
- end
479
- end
480
-
481
- #Returns a single result.
482
- def fetch
483
- if @enum
484
- begin
485
- ret = @enum.next
486
- rescue StopIteration
487
- @enum = nil
488
- @res = nil
489
- end
490
- end
491
-
492
- if !ret and !@res and !@enum
493
- begin
494
- @res = @conn.use_result
495
- @enum = @res.to_enum
496
- ret = @enum.next
497
- rescue Mysql::Error
498
- #Reset it to run non-unbuffered again and then return false.
499
- @conn.query_with_result = true
500
- return false
501
- rescue StopIteration
502
- sleep 0.1
503
- retry
504
- end
505
- end
506
-
507
- if !@as_hash
508
- return ret
509
- else
510
- self.load_keys if !@keys
511
-
512
- ret_h = {}
513
- @keys.each_index do |key_no|
514
- ret_h[@keys[key_no]] = ret[key_no]
515
- end
516
-
517
- return ret_h
518
- end
519
- end
520
-
521
- #Loops over every single result yielding it.
522
- def each
523
- while data = self.fetch
524
- yield(data)
525
- end
526
- end
527
- end
528
-
529
- #This class controls the result for the MySQL2 driver.
530
- class Baza::Driver::Mysql::ResultMySQL2
531
- #Constructor. This should not be called manually.
532
- def initialize(result)
533
- @result = result
534
- end
535
-
536
- #Returns a single result.
537
- def fetch
538
- @enum = @result.to_enum if !@enum
539
-
540
- begin
541
- return @enum.next
542
- rescue StopIteration
543
- return false
544
- end
545
- end
546
-
547
- #Loops over every single result yielding it.
548
- def each
549
- @result.each do |res|
550
- next if !res #This sometimes happens when streaming results...
551
- yield(res)
552
- end
553
- end
554
- end
555
-
556
- #This class controls the result for the Java-MySQL-driver.
557
- class Baza::Driver::Mysql::ResultJava
558
- #Constructor. This should not be called manually.
559
- def initialize(knjdb, opts, result)
560
- @baza_db = knjdb
561
- @result = result
562
-
563
- if !opts.key?(:result) or opts[:result] == "hash"
564
- @as_hash = true
565
- elsif opts[:result] == "array"
566
- @as_hash = false
567
- else
568
- raise "Unknown type of result: '#{opts[:result]}'."
569
- end
570
- end
571
-
572
- #Reads meta-data about the query like keys and count.
573
- def read_meta
574
- @result.before_first
575
- meta = @result.meta_data
576
- @count = meta.column_count
577
-
578
- @keys = []
579
- 1.upto(@count) do |count|
580
- @keys << meta.column_label(count).to_sym
581
- end
582
- end
583
-
584
- def fetch
585
- return false if !@result
586
- self.read_meta if !@keys
587
- status = @result.next
588
-
589
- if !status
590
- @result = nil
591
- @keys = nil
592
- @count = nil
593
- return false
594
- end
595
-
596
- if @as_hash
597
- ret = {}
598
- 1.upto(@count) do |count|
599
- ret[@keys[count - 1]] = @result.object(count)
600
- end
601
- else
602
- ret = []
603
- 1.upto(@count) do |count|
604
- ret << @result.object(count)
605
- end
606
- end
607
-
608
- return ret
609
- end
610
-
611
- def each
612
- while data = self.fetch
613
- yield(data)
614
- end
615
- end
616
- end