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.
- checksums.yaml +4 -4
- data/README.md +58 -13
- data/VERSION +1 -1
- data/baza.gemspec +15 -3
- data/include/db.rb +871 -865
- data/include/drivers/mysql/mysql.rb +104 -297
- data/include/drivers/mysql/mysql_column.rb +133 -0
- data/include/drivers/mysql/mysql_columns.rb +4 -127
- data/include/drivers/mysql/mysql_index.rb +76 -0
- data/include/drivers/mysql/mysql_indexes.rb +0 -73
- data/include/drivers/mysql/mysql_result.rb +42 -0
- data/include/drivers/mysql/mysql_result_java.rb +61 -0
- data/include/drivers/mysql/mysql_result_mysql2.rb +26 -0
- data/include/drivers/mysql/mysql_result_unbuffered.rb +72 -0
- data/include/drivers/mysql/mysql_sqlspecs.rb +1 -1
- data/include/drivers/mysql/mysql_table.rb +361 -0
- data/include/drivers/mysql/mysql_tables.rb +23 -381
- data/include/drivers/sqlite3/libknjdb_java_sqlite3.rb +17 -22
- data/include/drivers/sqlite3/libknjdb_sqlite3_ironruby.rb +13 -13
- data/include/drivers/sqlite3/sqlite3.rb +39 -105
- data/include/drivers/sqlite3/sqlite3_column.rb +146 -0
- data/include/drivers/sqlite3/sqlite3_columns.rb +17 -149
- data/include/drivers/sqlite3/sqlite3_index.rb +55 -0
- data/include/drivers/sqlite3/sqlite3_indexes.rb +0 -52
- data/include/drivers/sqlite3/sqlite3_result.rb +35 -0
- data/include/drivers/sqlite3/sqlite3_result_java.rb +39 -0
- data/include/drivers/sqlite3/sqlite3_table.rb +399 -0
- data/include/drivers/sqlite3/sqlite3_tables.rb +7 -403
- data/include/idquery.rb +19 -19
- data/include/model.rb +139 -139
- data/include/model_handler_sqlhelper.rb +74 -74
- data/spec/support/driver_columns_collection.rb +17 -0
- metadata +14 -2
data/include/db.rb
CHANGED
@@ -1,865 +1,871 @@
|
|
1
|
-
require "knjrbfw"
|
2
|
-
Knj.gem_require([:wref, :datet])
|
3
|
-
|
4
|
-
#A wrapper of several possible database-types.
|
5
|
-
#
|
6
|
-
#===Examples
|
7
|
-
# db = Baza::Db.new(:
|
8
|
-
# mysql_table = db.tables['mysql']
|
9
|
-
# name = mysql_table.name
|
10
|
-
# cols = mysql_table.columns
|
11
|
-
#
|
12
|
-
# db = Baza::Db.new(:
|
13
|
-
#
|
14
|
-
# db.q("SELECT * FROM users") do |data|
|
15
|
-
# print data[:name]
|
16
|
-
# end
|
17
|
-
class Baza::Db
|
18
|
-
attr_reader :sep_col, :sep_table, :sep_val, :opts, :conn, :conns, :int_types
|
19
|
-
|
20
|
-
#Returns an array containing hashes of information about each registered driver.
|
21
|
-
def self.drivers
|
22
|
-
path = "#{File.dirname(__FILE__)}/drivers"
|
23
|
-
drivers = []
|
24
|
-
|
25
|
-
Dir.foreach(path) do |file|
|
26
|
-
next if file.to_s.slice(0, 1) == "."
|
27
|
-
fp = "#{path}/#{file}"
|
28
|
-
next unless File.directory?(fp)
|
29
|
-
|
30
|
-
driver_file = "#{fp}/#{file}.rb"
|
31
|
-
class_name = StringCases.snake_to_camel(file).to_sym
|
32
|
-
|
33
|
-
drivers << {
|
34
|
-
:
|
35
|
-
:
|
36
|
-
:
|
37
|
-
}
|
38
|
-
end
|
39
|
-
|
40
|
-
return drivers
|
41
|
-
end
|
42
|
-
|
43
|
-
#Tries to create a database-object based on the given object which could be a SQLite3 object or a MySQL 2 object (or other supported).
|
44
|
-
def self.from_object(args)
|
45
|
-
args = {:
|
46
|
-
raise "No :object was given."
|
47
|
-
|
48
|
-
Baza::Db.drivers.each do |driver|
|
49
|
-
require driver[:driver_path]
|
50
|
-
|
51
|
-
const = Baza::Driver.const_get(driver[:class_name])
|
52
|
-
next unless const.respond_to?(:from_object)
|
53
|
-
|
54
|
-
obj = const.from_object(args)
|
55
|
-
if obj.is_a?(Hash)
|
56
|
-
if obj[:args]
|
57
|
-
new_args = obj[:args]
|
58
|
-
new_args = new_args.merge(args[:new_args]) if args[:new_args]
|
59
|
-
return Baza::Db.new(new_args)
|
60
|
-
else
|
61
|
-
raise "Didnt know what to do."
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
raise "Could not figure out what to do what object of type: '#{args[:object].class.name}'."
|
67
|
-
end
|
68
|
-
|
69
|
-
def initialize(opts)
|
70
|
-
@conn = opts.delete(:driver) if opts[:driver]
|
71
|
-
self.opts = opts if opts != nil
|
72
|
-
@int_types = [:int, :bigint, :tinyint, :smallint, :mediumint]
|
73
|
-
|
74
|
-
if !@opts[:threadsafe]
|
75
|
-
require "monitor"
|
76
|
-
@mutex = Monitor.new
|
77
|
-
end
|
78
|
-
|
79
|
-
@debug = @opts[:debug]
|
80
|
-
|
81
|
-
self.conn_exec do |driver|
|
82
|
-
@sep_table = driver.sep_table
|
83
|
-
@sep_col = driver.sep_col
|
84
|
-
@sep_val = driver.sep_val
|
85
|
-
@esc_driver = driver
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
def args
|
90
|
-
return @opts
|
91
|
-
end
|
92
|
-
|
93
|
-
def opts=(arr_opts)
|
94
|
-
@opts = {}
|
95
|
-
arr_opts.each do |key, val|
|
96
|
-
@opts[key.to_sym] = val
|
97
|
-
end
|
98
|
-
|
99
|
-
if RUBY_PLATFORM == "java"
|
100
|
-
@opts[:subtype] = "java"
|
101
|
-
elsif @opts[:type] == "sqlite3"
|
102
|
-
@opts[:subtype] = "ironruby"
|
103
|
-
end
|
104
|
-
|
105
|
-
@type_cc = StringCases.snake_to_camel(@opts[:type])
|
106
|
-
self.connect
|
107
|
-
end
|
108
|
-
|
109
|
-
#Actually connects to the database. This is useually done automatically.
|
110
|
-
def connect
|
111
|
-
if @opts[:threadsafe]
|
112
|
-
require "#{$knjpath}threadhandler"
|
113
|
-
@conns = Knj::Threadhandler.new
|
114
|
-
|
115
|
-
@conns.on_spawn_new do
|
116
|
-
self.spawn
|
117
|
-
end
|
118
|
-
|
119
|
-
@conns.on_inactive do |data|
|
120
|
-
data[:obj].close
|
121
|
-
end
|
122
|
-
|
123
|
-
@conns.on_activate do |data|
|
124
|
-
data[:obj].reconnect
|
125
|
-
end
|
126
|
-
else
|
127
|
-
@conn = self.spawn
|
128
|
-
end
|
129
|
-
end
|
130
|
-
|
131
|
-
#Spawns a new driver (useally done automatically).
|
132
|
-
#===Examples
|
133
|
-
# driver_instance = db.spawn
|
134
|
-
def spawn
|
135
|
-
raise "No type given (#{@opts.keys.join(",")})."
|
136
|
-
rpath = "#{File.dirname(__FILE__)}/#{"drivers/#{@opts[:type]}/#{@opts[:type]}.rb"}"
|
137
|
-
require rpath if (!@opts.key?(:require)
|
138
|
-
return Baza::Driver.const_get(@type_cc).new(self)
|
139
|
-
end
|
140
|
-
|
141
|
-
#Registers a driver to the current thread.
|
142
|
-
def get_and_register_thread
|
143
|
-
raise "KnjDB-object is not in threadding mode."
|
144
|
-
|
145
|
-
thread_cur = Thread.current
|
146
|
-
tid = self.__id__
|
147
|
-
thread_cur[:baza] = {} if !thread_cur[:baza]
|
148
|
-
|
149
|
-
if thread_cur[:baza][tid]
|
150
|
-
#An object has already been spawned - free that first to avoid endless "used" objects.
|
151
|
-
self.free_thread
|
152
|
-
end
|
153
|
-
|
154
|
-
thread_cur[:baza][tid] = @conns.get_and_lock
|
155
|
-
|
156
|
-
#If block given then be ensure to free thread after yielding.
|
157
|
-
if block_given?
|
158
|
-
begin
|
159
|
-
yield
|
160
|
-
ensure
|
161
|
-
self.free_thread
|
162
|
-
end
|
163
|
-
end
|
164
|
-
end
|
165
|
-
|
166
|
-
#Frees the current driver from the current thread.
|
167
|
-
def free_thread
|
168
|
-
thread_cur = Thread.current
|
169
|
-
tid = self.__id__
|
170
|
-
|
171
|
-
if thread_cur[:baza]
|
172
|
-
db = thread_cur[:baza][tid]
|
173
|
-
thread_cur[:baza].delete(tid)
|
174
|
-
@conns.free(db) if @conns
|
175
|
-
end
|
176
|
-
end
|
177
|
-
|
178
|
-
#Clean up various memory-stuff if possible.
|
179
|
-
def clean
|
180
|
-
if @conns
|
181
|
-
@conns.objects.each do |data|
|
182
|
-
data[:object].clean if data[:object].respond_to?("clean")
|
183
|
-
end
|
184
|
-
elsif @conn
|
185
|
-
@conn.clean if @conn.respond_to?("clean")
|
186
|
-
end
|
187
|
-
end
|
188
|
-
|
189
|
-
#The all driver-database-connections.
|
190
|
-
def close
|
191
|
-
@conn.close if @conn
|
192
|
-
@conns.destroy if @conns
|
193
|
-
|
194
|
-
@conn = nil
|
195
|
-
@conns = nil
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
return
|
354
|
-
|
355
|
-
return "
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
#
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
end
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
end
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
if
|
443
|
-
obj
|
444
|
-
else
|
445
|
-
obj
|
446
|
-
end
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
end
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
sql << " LIMIT #{args[:
|
492
|
-
end
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
end
|
543
|
-
|
544
|
-
return
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
if
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
|
763
|
-
|
764
|
-
|
765
|
-
|
766
|
-
|
767
|
-
|
768
|
-
|
769
|
-
|
770
|
-
|
771
|
-
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
)
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
#
|
826
|
-
|
827
|
-
#
|
828
|
-
#
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
|
835
|
-
|
836
|
-
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
|
841
|
-
|
842
|
-
|
843
|
-
|
844
|
-
|
845
|
-
|
846
|
-
|
847
|
-
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
#
|
852
|
-
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
|
865
|
-
|
1
|
+
require "knjrbfw"
|
2
|
+
Knj.gem_require([:wref, :datet])
|
3
|
+
|
4
|
+
#A wrapper of several possible database-types.
|
5
|
+
#
|
6
|
+
#===Examples
|
7
|
+
# db = Baza::Db.new(type: "mysql", subtype: "mysql2", db: "mysql", user: "user", pass: "password")
|
8
|
+
# mysql_table = db.tables['mysql']
|
9
|
+
# name = mysql_table.name
|
10
|
+
# cols = mysql_table.columns
|
11
|
+
#
|
12
|
+
# db = Baza::Db.new(type: "sqlite3", path: "some_db.sqlite3")
|
13
|
+
#
|
14
|
+
# db.q("SELECT * FROM users") do |data|
|
15
|
+
# print data[:name]
|
16
|
+
# end
|
17
|
+
class Baza::Db
|
18
|
+
attr_reader :sep_col, :sep_table, :sep_val, :opts, :conn, :conns, :int_types
|
19
|
+
|
20
|
+
#Returns an array containing hashes of information about each registered driver.
|
21
|
+
def self.drivers
|
22
|
+
path = "#{File.dirname(__FILE__)}/drivers"
|
23
|
+
drivers = []
|
24
|
+
|
25
|
+
Dir.foreach(path) do |file|
|
26
|
+
next if file.to_s.slice(0, 1) == "."
|
27
|
+
fp = "#{path}/#{file}"
|
28
|
+
next unless File.directory?(fp)
|
29
|
+
|
30
|
+
driver_file = "#{fp}/#{file}.rb"
|
31
|
+
class_name = StringCases.snake_to_camel(file).to_sym
|
32
|
+
|
33
|
+
drivers << {
|
34
|
+
name: file,
|
35
|
+
driver_path: driver_file,
|
36
|
+
class_name: class_name
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
return drivers
|
41
|
+
end
|
42
|
+
|
43
|
+
#Tries to create a database-object based on the given object which could be a SQLite3 object or a MySQL 2 object (or other supported).
|
44
|
+
def self.from_object(args)
|
45
|
+
args = {object: args} unless args.is_a?(Hash)
|
46
|
+
raise "No :object was given." unless args[:object]
|
47
|
+
|
48
|
+
Baza::Db.drivers.each do |driver|
|
49
|
+
require driver[:driver_path]
|
50
|
+
|
51
|
+
const = Baza::Driver.const_get(driver[:class_name])
|
52
|
+
next unless const.respond_to?(:from_object)
|
53
|
+
|
54
|
+
obj = const.from_object(args)
|
55
|
+
if obj.is_a?(Hash) && obj[:type] == :success
|
56
|
+
if obj[:args]
|
57
|
+
new_args = obj[:args]
|
58
|
+
new_args = new_args.merge(args[:new_args]) if args[:new_args]
|
59
|
+
return Baza::Db.new(new_args)
|
60
|
+
else
|
61
|
+
raise "Didnt know what to do."
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
raise "Could not figure out what to do what object of type: '#{args[:object].class.name}'."
|
67
|
+
end
|
68
|
+
|
69
|
+
def initialize(opts)
|
70
|
+
@conn = opts.delete(:driver) if opts[:driver]
|
71
|
+
self.opts = opts if opts != nil
|
72
|
+
@int_types = [:int, :bigint, :tinyint, :smallint, :mediumint]
|
73
|
+
|
74
|
+
if !@opts[:threadsafe]
|
75
|
+
require "monitor"
|
76
|
+
@mutex = Monitor.new
|
77
|
+
end
|
78
|
+
|
79
|
+
@debug = @opts[:debug]
|
80
|
+
|
81
|
+
self.conn_exec do |driver|
|
82
|
+
@sep_table = driver.sep_table
|
83
|
+
@sep_col = driver.sep_col
|
84
|
+
@sep_val = driver.sep_val
|
85
|
+
@esc_driver = driver
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def args
|
90
|
+
return @opts
|
91
|
+
end
|
92
|
+
|
93
|
+
def opts=(arr_opts)
|
94
|
+
@opts = {}
|
95
|
+
arr_opts.each do |key, val|
|
96
|
+
@opts[key.to_sym] = val
|
97
|
+
end
|
98
|
+
|
99
|
+
if RUBY_PLATFORM == "java"
|
100
|
+
@opts[:subtype] = "java"
|
101
|
+
elsif @opts[:type] == "sqlite3" && RUBY_PLATFORM.index("mswin32") != nil
|
102
|
+
@opts[:subtype] = "ironruby"
|
103
|
+
end
|
104
|
+
|
105
|
+
@type_cc = StringCases.snake_to_camel(@opts[:type])
|
106
|
+
self.connect
|
107
|
+
end
|
108
|
+
|
109
|
+
#Actually connects to the database. This is useually done automatically.
|
110
|
+
def connect
|
111
|
+
if @opts[:threadsafe]
|
112
|
+
require "#{$knjpath}threadhandler"
|
113
|
+
@conns = Knj::Threadhandler.new
|
114
|
+
|
115
|
+
@conns.on_spawn_new do
|
116
|
+
self.spawn
|
117
|
+
end
|
118
|
+
|
119
|
+
@conns.on_inactive do |data|
|
120
|
+
data[:obj].close
|
121
|
+
end
|
122
|
+
|
123
|
+
@conns.on_activate do |data|
|
124
|
+
data[:obj].reconnect
|
125
|
+
end
|
126
|
+
else
|
127
|
+
@conn = self.spawn
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
#Spawns a new driver (useally done automatically).
|
132
|
+
#===Examples
|
133
|
+
# driver_instance = db.spawn
|
134
|
+
def spawn
|
135
|
+
raise "No type given (#{@opts.keys.join(",")})." unless @opts[:type]
|
136
|
+
rpath = "#{File.dirname(__FILE__)}/#{"drivers/#{@opts[:type]}/#{@opts[:type]}.rb"}"
|
137
|
+
require rpath if (!@opts.key?(:require) || @opts[:require]) && File.exists?(rpath)
|
138
|
+
return Baza::Driver.const_get(@type_cc).new(self)
|
139
|
+
end
|
140
|
+
|
141
|
+
#Registers a driver to the current thread.
|
142
|
+
def get_and_register_thread
|
143
|
+
raise "KnjDB-object is not in threadding mode." unless @conns
|
144
|
+
|
145
|
+
thread_cur = Thread.current
|
146
|
+
tid = self.__id__
|
147
|
+
thread_cur[:baza] = {} if !thread_cur[:baza]
|
148
|
+
|
149
|
+
if thread_cur[:baza][tid]
|
150
|
+
#An object has already been spawned - free that first to avoid endless "used" objects.
|
151
|
+
self.free_thread
|
152
|
+
end
|
153
|
+
|
154
|
+
thread_cur[:baza][tid] = @conns.get_and_lock unless thread_cur[:baza][tid]
|
155
|
+
|
156
|
+
#If block given then be ensure to free thread after yielding.
|
157
|
+
if block_given?
|
158
|
+
begin
|
159
|
+
yield
|
160
|
+
ensure
|
161
|
+
self.free_thread
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
#Frees the current driver from the current thread.
|
167
|
+
def free_thread
|
168
|
+
thread_cur = Thread.current
|
169
|
+
tid = self.__id__
|
170
|
+
|
171
|
+
if thread_cur[:baza] && thread_cur[:baza].key?(tid)
|
172
|
+
db = thread_cur[:baza][tid]
|
173
|
+
thread_cur[:baza].delete(tid)
|
174
|
+
@conns.free(db) if @conns
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
#Clean up various memory-stuff if possible.
|
179
|
+
def clean
|
180
|
+
if @conns
|
181
|
+
@conns.objects.each do |data|
|
182
|
+
data[:object].clean if data[:object].respond_to?("clean")
|
183
|
+
end
|
184
|
+
elsif @conn
|
185
|
+
@conn.clean if @conn.respond_to?("clean")
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
#The all driver-database-connections.
|
190
|
+
def close
|
191
|
+
@conn.close if @conn
|
192
|
+
@conns.destroy if @conns
|
193
|
+
|
194
|
+
@conn = nil
|
195
|
+
@conns = nil
|
196
|
+
|
197
|
+
@closed = true
|
198
|
+
end
|
199
|
+
|
200
|
+
def closed?
|
201
|
+
@closed
|
202
|
+
end
|
203
|
+
|
204
|
+
#Clones the current database-connection with possible extra arguments.
|
205
|
+
def clone_conn(args = {})
|
206
|
+
conn = Baza::Db.new(opts = @opts.clone.merge(args))
|
207
|
+
|
208
|
+
if block_given?
|
209
|
+
begin
|
210
|
+
yield(conn)
|
211
|
+
ensure
|
212
|
+
conn.close
|
213
|
+
end
|
214
|
+
|
215
|
+
return nil
|
216
|
+
else
|
217
|
+
return conn
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
COPY_TO_ALLOWED_ARGS = [:tables, :debug]
|
222
|
+
#Copies the content of the current database to another instance of Baza::Db.
|
223
|
+
def copy_to(db, args = {})
|
224
|
+
debug = args[:debug]
|
225
|
+
raise "No tables given." if !data[:tables]
|
226
|
+
|
227
|
+
data[:tables].each do |table|
|
228
|
+
table_args = nil
|
229
|
+
table_args = args[:tables][table[:name.to_sym]] if args && args[:tables] && args[:tables][table[:name].to_sym]
|
230
|
+
next if table_args && table_args[:skip]
|
231
|
+
table.delete(:indexes) if table.key?(:indexes) && args[:skip_indexes]
|
232
|
+
|
233
|
+
table_name = table.delete(:name)
|
234
|
+
puts "Creating table: '#{table_name}'." if debug
|
235
|
+
db.tables.create(table_name, table)
|
236
|
+
|
237
|
+
limit_from = 0
|
238
|
+
limit_incr = 1000
|
239
|
+
|
240
|
+
loop do
|
241
|
+
puts "Copying rows (#{limit_from}, #{limit_incr})." if debug
|
242
|
+
ins_arr = []
|
243
|
+
q_rows = self.select(table_name, {}, {limit_from: limit_from, limit_to: limit_incr})
|
244
|
+
while d_rows = q_rows.fetch
|
245
|
+
col_args = nil
|
246
|
+
|
247
|
+
if table_args && table_args[:columns]
|
248
|
+
d_rows.each do |col_name, col_data|
|
249
|
+
col_args = table_args[:columns][col_name.to_sym] if table_args && table_args[:columns]
|
250
|
+
d_rows[col_name] = "" if col_args && col_args[:empty]
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
ins_arr << d_rows
|
255
|
+
end
|
256
|
+
|
257
|
+
break if ins_arr.empty?
|
258
|
+
|
259
|
+
puts "Insertering #{ins_arr.length} rows." if debug
|
260
|
+
db.insert_multi(table_name, ins_arr)
|
261
|
+
limit_from += limit_incr
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
#Returns the data of this database in a hash.
|
267
|
+
#===Examples
|
268
|
+
# data = db.data
|
269
|
+
# tables_hash = data['tables']
|
270
|
+
def data
|
271
|
+
tables_ret = []
|
272
|
+
tables.list.each do |name, table|
|
273
|
+
tables_ret << table.data
|
274
|
+
end
|
275
|
+
|
276
|
+
return {
|
277
|
+
tables: tables_ret
|
278
|
+
}
|
279
|
+
end
|
280
|
+
|
281
|
+
#Simply inserts data into a table.
|
282
|
+
#
|
283
|
+
#===Examples
|
284
|
+
# db.insert(:users, name: "John", lastname: "Doe")
|
285
|
+
# id = db.insert(:users, {name: "John", lastname: "Doe"}, return_id: true)
|
286
|
+
# sql = db.insert(:users, {name: "John", lastname: "Doe"}, return_sql: true) #=> "INSERT INTO `users` (`name`, `lastname`) VALUES ('John', 'Doe')"
|
287
|
+
def insert(tablename, arr_insert, args = nil)
|
288
|
+
sql = "INSERT INTO #{@sep_table}#{self.esc_table(tablename)}#{@sep_table}"
|
289
|
+
|
290
|
+
if !arr_insert || arr_insert.empty?
|
291
|
+
#This is the correct syntax for inserting a blank row in MySQL.
|
292
|
+
if @opts[:type].to_s == "mysql"
|
293
|
+
sql << " VALUES ()"
|
294
|
+
elsif @opts[:type].to_s == "sqlite3"
|
295
|
+
sql << " DEFAULT VALUES"
|
296
|
+
else
|
297
|
+
raise "Unknown database-type: '#{@opts[:type]}'."
|
298
|
+
end
|
299
|
+
else
|
300
|
+
sql << " ("
|
301
|
+
|
302
|
+
first = true
|
303
|
+
arr_insert.each do |key, value|
|
304
|
+
if first
|
305
|
+
first = false
|
306
|
+
else
|
307
|
+
sql << ", "
|
308
|
+
end
|
309
|
+
|
310
|
+
sql << "#{@sep_col}#{self.esc_col(key)}#{@sep_col}"
|
311
|
+
end
|
312
|
+
|
313
|
+
sql << ") VALUES ("
|
314
|
+
|
315
|
+
first = true
|
316
|
+
arr_insert.each do |key, value|
|
317
|
+
if first
|
318
|
+
first = false
|
319
|
+
else
|
320
|
+
sql << ", "
|
321
|
+
end
|
322
|
+
|
323
|
+
sql << self.sqlval(value)
|
324
|
+
end
|
325
|
+
|
326
|
+
sql << ")"
|
327
|
+
end
|
328
|
+
|
329
|
+
return sql if args && args[:return_sql]
|
330
|
+
|
331
|
+
self.conn_exec do |driver|
|
332
|
+
begin
|
333
|
+
driver.query(sql)
|
334
|
+
rescue => e
|
335
|
+
self.add_sql_to_error(e, sql) if @opts[:sql_to_error]
|
336
|
+
raise e
|
337
|
+
end
|
338
|
+
|
339
|
+
return driver.last_id if args && args[:return_id]
|
340
|
+
return nil
|
341
|
+
end
|
342
|
+
end
|
343
|
+
|
344
|
+
def add_sql_to_error(error, sql)
|
345
|
+
error.message << " (SQL: #{sql})"
|
346
|
+
end
|
347
|
+
|
348
|
+
#Returns the correct SQL-value for the given value. If it is a number, then just the raw number as a string will be returned. nil's will be NULL and strings will have quotes and will be escaped.
|
349
|
+
def sqlval(val)
|
350
|
+
return @conn.sqlval(val) if @conn.respond_to?(:sqlval)
|
351
|
+
|
352
|
+
if val.is_a?(Fixnum) || val.is_a?(Integer)
|
353
|
+
return val.to_s
|
354
|
+
elsif val == nil
|
355
|
+
return "NULL"
|
356
|
+
elsif val.is_a?(Date)
|
357
|
+
return "#{@sep_val}#{Datet.in(val).dbstr(time: false)}#{@sep_val}"
|
358
|
+
elsif val.is_a?(Time) || val.is_a?(DateTime)
|
359
|
+
return "#{@sep_val}#{Datet.in(val).dbstr}#{@sep_val}"
|
360
|
+
else
|
361
|
+
return "#{@sep_val}#{self.escape(val)}#{@sep_val}"
|
362
|
+
end
|
363
|
+
end
|
364
|
+
|
365
|
+
#Simply and optimal insert multiple rows into a table in a single query. Uses the drivers functionality if supported or inserts each row manually.
|
366
|
+
#
|
367
|
+
#===Examples
|
368
|
+
# db.insert_multi(:users, [
|
369
|
+
# {name: "John", lastname: "Doe"},
|
370
|
+
# {name: "Kasper", lastname: "Johansen"}
|
371
|
+
# ])
|
372
|
+
def insert_multi(tablename, arr_hashes, args = nil)
|
373
|
+
return false if arr_hashes.empty?
|
374
|
+
|
375
|
+
if @esc_driver.respond_to?(:insert_multi)
|
376
|
+
if args && args[:return_sql]
|
377
|
+
res = @esc_driver.insert_multi(tablename, arr_hashes, args)
|
378
|
+
if res.is_a?(String)
|
379
|
+
return [res]
|
380
|
+
elsif res.is_a?(Array)
|
381
|
+
return res
|
382
|
+
else
|
383
|
+
raise "Unknown result: '#{res.class.name}'."
|
384
|
+
end
|
385
|
+
end
|
386
|
+
|
387
|
+
self.conn_exec do |driver|
|
388
|
+
return driver.insert_multi(tablename, arr_hashes, args)
|
389
|
+
end
|
390
|
+
else
|
391
|
+
transaction do
|
392
|
+
arr_hashes.each do |hash|
|
393
|
+
self.insert(tablename, hash, args)
|
394
|
+
end
|
395
|
+
end
|
396
|
+
|
397
|
+
return nil
|
398
|
+
end
|
399
|
+
end
|
400
|
+
|
401
|
+
#Simple updates rows.
|
402
|
+
#
|
403
|
+
#===Examples
|
404
|
+
# db.update(:users, {name: "John"}, {lastname: "Doe"})
|
405
|
+
def update(tablename, hash_update, arr_terms = {}, args = nil)
|
406
|
+
raise "'hash_update' was not a hash: '#{hash_update.class.name}'." if !hash_update.is_a?(Hash)
|
407
|
+
return false if hash_update.empty?
|
408
|
+
|
409
|
+
sql = ""
|
410
|
+
sql << "UPDATE #{@sep_col}#{tablename}#{@sep_col} SET "
|
411
|
+
|
412
|
+
first = true
|
413
|
+
hash_update.each do |key, value|
|
414
|
+
if first
|
415
|
+
first = false
|
416
|
+
else
|
417
|
+
sql << ", "
|
418
|
+
end
|
419
|
+
|
420
|
+
#Convert dates to valid dbstr.
|
421
|
+
value = self.date_out(value) if value.is_a?(Datet) || value.is_a?(Time)
|
422
|
+
|
423
|
+
sql << "#{@sep_col}#{self.esc_col(key)}#{@sep_col} = "
|
424
|
+
sql << self.sqlval(value)
|
425
|
+
end
|
426
|
+
|
427
|
+
if arr_terms && arr_terms.length > 0
|
428
|
+
sql << " WHERE #{self.makeWhere(arr_terms)}"
|
429
|
+
end
|
430
|
+
|
431
|
+
return sql if args && args[:return_sql]
|
432
|
+
|
433
|
+
self.conn_exec do |driver|
|
434
|
+
driver.query(sql)
|
435
|
+
end
|
436
|
+
end
|
437
|
+
|
438
|
+
#Checks if a given terms exists. If it does, updates it to match data. If not inserts the row.
|
439
|
+
def upsert(table, data, terms, args = nil)
|
440
|
+
row = self.select(table, terms, "limit" => 1).fetch
|
441
|
+
|
442
|
+
if args && args[:buffer]
|
443
|
+
obj = args[:buffer]
|
444
|
+
else
|
445
|
+
obj = self
|
446
|
+
end
|
447
|
+
|
448
|
+
if row
|
449
|
+
obj.update(table, data, terms)
|
450
|
+
else
|
451
|
+
obj.insert(table, terms.merge(data))
|
452
|
+
end
|
453
|
+
end
|
454
|
+
|
455
|
+
SELECT_ARGS_ALLOWED_KEYS = [:limit, :limit_from, :limit_to]
|
456
|
+
#Makes a select from the given arguments: table-name, where-terms and other arguments as limits and orders. Also takes a block to avoid raping of memory.
|
457
|
+
def select(tablename, arr_terms = nil, args = nil, &block)
|
458
|
+
#Set up vars.
|
459
|
+
sql = ""
|
460
|
+
args_q = nil
|
461
|
+
select_sql = "*"
|
462
|
+
|
463
|
+
#Give 'cloned_ubuf' argument to 'q'-method.
|
464
|
+
if args && args[:cloned_ubuf]
|
465
|
+
args_q = {cloned_ubuf: true}
|
466
|
+
end
|
467
|
+
|
468
|
+
#Set up IDQuery-stuff if that is given in arguments.
|
469
|
+
if args && args[:idquery]
|
470
|
+
if args[:idquery] == true
|
471
|
+
select_sql = "`id`"
|
472
|
+
col = :id
|
473
|
+
else
|
474
|
+
select_sql = "`#{self.esc_col(args[:idquery])}`"
|
475
|
+
col = args[:idquery]
|
476
|
+
end
|
477
|
+
end
|
478
|
+
|
479
|
+
sql = "SELECT #{select_sql} FROM #{@sep_table}#{tablename}#{@sep_table}"
|
480
|
+
|
481
|
+
if arr_terms != nil && !arr_terms.empty?
|
482
|
+
sql << " WHERE #{self.makeWhere(arr_terms)}"
|
483
|
+
end
|
484
|
+
|
485
|
+
if args != nil
|
486
|
+
if args[:orderby]
|
487
|
+
sql << " ORDER BY #{args[:orderby]}"
|
488
|
+
end
|
489
|
+
|
490
|
+
if args[:limit]
|
491
|
+
sql << " LIMIT #{args[:limit]}"
|
492
|
+
end
|
493
|
+
|
494
|
+
if args[:limit_from] && args[:limit_to]
|
495
|
+
raise "'limit_from' was not numeric: '#{args[:limit_from]}'." if !(Float(args[:limit_from]) rescue false)
|
496
|
+
raise "'limit_to' was not numeric: '#{args[:limit_to]}'." if !(Float(args[:limit_to]) rescue false)
|
497
|
+
sql << " LIMIT #{args[:limit_from]}, #{args[:limit_to]}"
|
498
|
+
end
|
499
|
+
end
|
500
|
+
|
501
|
+
#Do IDQuery if given in arguments.
|
502
|
+
if args && args[:idquery]
|
503
|
+
res = Baza::Idquery.new(db: self, table: tablename, query: sql, col: col, &block)
|
504
|
+
else
|
505
|
+
res = q(sql, args_q, &block)
|
506
|
+
end
|
507
|
+
|
508
|
+
#Return result if a block wasnt given.
|
509
|
+
if block
|
510
|
+
return nil
|
511
|
+
else
|
512
|
+
return res
|
513
|
+
end
|
514
|
+
end
|
515
|
+
|
516
|
+
#Returns a single row from a database.
|
517
|
+
#
|
518
|
+
#===Examples
|
519
|
+
# row = db.single(:users, lastname: "Doe")
|
520
|
+
def single(tablename, arr_terms = nil, args = {})
|
521
|
+
args[:limit] = 1
|
522
|
+
|
523
|
+
#Experienced very weird memory leak if this was not done by block. Maybe bug in Ruby 1.9.2? - knj
|
524
|
+
self.select(tablename, arr_terms, args) do |data|
|
525
|
+
return data
|
526
|
+
end
|
527
|
+
|
528
|
+
return false
|
529
|
+
end
|
530
|
+
|
531
|
+
alias :selectsingle :single
|
532
|
+
|
533
|
+
#Deletes rows from the database.
|
534
|
+
#
|
535
|
+
#===Examples
|
536
|
+
# db.delete(:users, {lastname: "Doe"})
|
537
|
+
def delete(tablename, arr_terms, args = nil)
|
538
|
+
sql = "DELETE FROM #{@sep_table}#{tablename}#{@sep_table}"
|
539
|
+
|
540
|
+
if arr_terms != nil && !arr_terms.empty?
|
541
|
+
sql << " WHERE #{self.makeWhere(arr_terms)}"
|
542
|
+
end
|
543
|
+
|
544
|
+
return sql if args && args[:return_sql]
|
545
|
+
|
546
|
+
self.conn_exec do |driver|
|
547
|
+
driver.query(sql)
|
548
|
+
end
|
549
|
+
|
550
|
+
return nil
|
551
|
+
end
|
552
|
+
|
553
|
+
#Internally used to generate SQL.
|
554
|
+
#
|
555
|
+
#===Examples
|
556
|
+
# sql = db.makeWhere({lastname: "Doe"}, driver_obj)
|
557
|
+
def makeWhere(arr_terms, driver = nil)
|
558
|
+
sql = ""
|
559
|
+
|
560
|
+
first = true
|
561
|
+
arr_terms.each do |key, value|
|
562
|
+
if first
|
563
|
+
first = false
|
564
|
+
else
|
565
|
+
sql << " AND "
|
566
|
+
end
|
567
|
+
|
568
|
+
if value.is_a?(Array)
|
569
|
+
raise "Array for column '#{key}' was empty." if value.empty?
|
570
|
+
sql << "#{@sep_col}#{key}#{@sep_col} IN (#{Knj::ArrayExt.join(arr: value, sep: ",", surr: "'", callback: proc{|ele| self.esc(ele)})})"
|
571
|
+
elsif value.is_a?(Hash)
|
572
|
+
raise "Dont know how to handle hash."
|
573
|
+
else
|
574
|
+
sql << "#{@sep_col}#{key}#{@sep_col} = #{self.sqlval(value)}"
|
575
|
+
end
|
576
|
+
end
|
577
|
+
|
578
|
+
return sql
|
579
|
+
end
|
580
|
+
|
581
|
+
#Returns a driver-object based on the current thread and free driver-objects.
|
582
|
+
#
|
583
|
+
#===Examples
|
584
|
+
# db.conn_exec do |driver|
|
585
|
+
# str = driver.escape('something̈́')
|
586
|
+
# end
|
587
|
+
def conn_exec
|
588
|
+
raise "Call to closed database" if @closed
|
589
|
+
|
590
|
+
if tcur = Thread.current && Thread.current[:baza]
|
591
|
+
tid = self.__id__
|
592
|
+
|
593
|
+
if tcur[:baza].key?(tid)
|
594
|
+
yield(tcur[:baza][tid])
|
595
|
+
return nil
|
596
|
+
end
|
597
|
+
end
|
598
|
+
|
599
|
+
if @conns
|
600
|
+
conn = @conns.get_and_lock
|
601
|
+
|
602
|
+
begin
|
603
|
+
yield(conn)
|
604
|
+
return nil
|
605
|
+
ensure
|
606
|
+
@conns.free(conn)
|
607
|
+
end
|
608
|
+
elsif @conn
|
609
|
+
@mutex.synchronize do
|
610
|
+
yield(@conn)
|
611
|
+
return nil
|
612
|
+
end
|
613
|
+
end
|
614
|
+
|
615
|
+
raise "Could not figure out which driver to use?"
|
616
|
+
end
|
617
|
+
|
618
|
+
#Executes a query and returns the result.
|
619
|
+
#
|
620
|
+
#===Examples
|
621
|
+
# res = db.query('SELECT * FROM users')
|
622
|
+
# while data = res.fetch
|
623
|
+
# print data[:name]
|
624
|
+
# end
|
625
|
+
def query(string)
|
626
|
+
if @debug
|
627
|
+
print "SQL: #{string}\n"
|
628
|
+
|
629
|
+
if @debug.is_a?(Fixnum) && @debug >= 2
|
630
|
+
print caller.join("\n")
|
631
|
+
print "\n"
|
632
|
+
end
|
633
|
+
end
|
634
|
+
|
635
|
+
begin
|
636
|
+
self.conn_exec do |driver|
|
637
|
+
return driver.query(string)
|
638
|
+
end
|
639
|
+
rescue => e
|
640
|
+
e.message << " (SQL: #{string})" if @opts[:sql_to_error]
|
641
|
+
raise e
|
642
|
+
end
|
643
|
+
end
|
644
|
+
|
645
|
+
#Execute an ubuffered query and returns the result.
|
646
|
+
#
|
647
|
+
#===Examples
|
648
|
+
# db.query_ubuf('SELECT * FROM users') do |data|
|
649
|
+
# print data[:name]
|
650
|
+
# end
|
651
|
+
def query_ubuf(string, &block)
|
652
|
+
ret = nil
|
653
|
+
|
654
|
+
self.conn_exec do |driver|
|
655
|
+
ret = driver.query_ubuf(string, &block)
|
656
|
+
end
|
657
|
+
|
658
|
+
if block
|
659
|
+
ret.each(&block)
|
660
|
+
return nil
|
661
|
+
end
|
662
|
+
|
663
|
+
return ret
|
664
|
+
end
|
665
|
+
|
666
|
+
#Clones the connection, executes the given block and closes the connection again.
|
667
|
+
#
|
668
|
+
#===Examples
|
669
|
+
# db.cloned_conn do |conn|
|
670
|
+
# conn.q('SELCET * FROM users') do |data|
|
671
|
+
# print data[:name]
|
672
|
+
# end
|
673
|
+
# end
|
674
|
+
def cloned_conn(args = nil, &block)
|
675
|
+
clone_conn_args = {
|
676
|
+
threadsafe: false
|
677
|
+
}
|
678
|
+
|
679
|
+
clone_conn_args.merge!(args[:clone_args]) if args && args[:clone_args]
|
680
|
+
dbconn = self.clone_conn(clone_conn_args)
|
681
|
+
|
682
|
+
begin
|
683
|
+
yield(dbconn)
|
684
|
+
ensure
|
685
|
+
dbconn.close
|
686
|
+
end
|
687
|
+
end
|
688
|
+
|
689
|
+
#Executes a query and returns the result. If a block is given the result is iterated over that block instead and it returns nil.
|
690
|
+
#
|
691
|
+
#===Examples
|
692
|
+
# db.q('SELECT * FROM users') do |data|
|
693
|
+
# print data[:name]
|
694
|
+
# end
|
695
|
+
def q(str, args = nil, &block)
|
696
|
+
#If the query should be executed in a new connection unbuffered.
|
697
|
+
if args
|
698
|
+
if args[:cloned_ubuf]
|
699
|
+
raise "No block given." unless block
|
700
|
+
|
701
|
+
self.cloned_conn(clone_args: args[:clone_args]) do |cloned_conn|
|
702
|
+
ret = cloned_conn.query_ubuf(str)
|
703
|
+
ret.each(&block)
|
704
|
+
end
|
705
|
+
|
706
|
+
return nil
|
707
|
+
else
|
708
|
+
raise "Invalid arguments given: '#{args}'."
|
709
|
+
end
|
710
|
+
end
|
711
|
+
|
712
|
+
ret = self.query(str)
|
713
|
+
|
714
|
+
if block
|
715
|
+
ret.each(&block)
|
716
|
+
return nil
|
717
|
+
end
|
718
|
+
|
719
|
+
return ret
|
720
|
+
end
|
721
|
+
|
722
|
+
#Yields a query-buffer and flushes at the end of the block given.
|
723
|
+
def q_buffer(args = {}, &block)
|
724
|
+
Baza::QueryBuffer.new(args.merge(db: self), &block)
|
725
|
+
return nil
|
726
|
+
end
|
727
|
+
|
728
|
+
#Returns the last inserted ID.
|
729
|
+
#
|
730
|
+
#===Examples
|
731
|
+
# id = db.last_id
|
732
|
+
def last_id
|
733
|
+
self.conn_exec do |driver|
|
734
|
+
return driver.last_id
|
735
|
+
end
|
736
|
+
end
|
737
|
+
|
738
|
+
#Escapes a string to be safe-to-use in a query-string.
|
739
|
+
#
|
740
|
+
#===Examples
|
741
|
+
# db.q("INSERT INTO users (name) VALUES ('#{db.esc('John')}')")
|
742
|
+
def escape(string)
|
743
|
+
return @esc_driver.escape(string)
|
744
|
+
end
|
745
|
+
|
746
|
+
alias :esc :escape
|
747
|
+
|
748
|
+
#Escapes the given string to be used as a column.
|
749
|
+
def esc_col(str)
|
750
|
+
return @esc_driver.esc_col(str)
|
751
|
+
end
|
752
|
+
|
753
|
+
#Escapes the given string to be used as a table.
|
754
|
+
def esc_table(str)
|
755
|
+
return @esc_driver.esc_table(str)
|
756
|
+
end
|
757
|
+
|
758
|
+
#Returns a string which can be used in SQL with the current driver.
|
759
|
+
#===Examples
|
760
|
+
# str = db.date_out(Time.now) #=> "2012-05-20 22:06:09"
|
761
|
+
def date_out(date_obj = Datet.new, args = {})
|
762
|
+
if @esc_driver.respond_to?(:date_out)
|
763
|
+
return @esc_driver.date_out(date_obj, args)
|
764
|
+
end
|
765
|
+
|
766
|
+
return Datet.in(date_obj).dbstr(args)
|
767
|
+
end
|
768
|
+
|
769
|
+
#Takes a valid date-db-string and converts it into a Datet.
|
770
|
+
#===Examples
|
771
|
+
# db.date_in('2012-05-20 22:06:09') #=> 2012-05-20 22:06:09 +0200
|
772
|
+
def date_in(date_obj)
|
773
|
+
if @esc_driver.respond_to?(:date_in)
|
774
|
+
return @esc_driver.date_in(date_obj)
|
775
|
+
end
|
776
|
+
|
777
|
+
return Datet.in(date_obj)
|
778
|
+
end
|
779
|
+
|
780
|
+
#Returns the table-module and spawns it if it isnt already spawned.
|
781
|
+
def tables
|
782
|
+
unless @tables
|
783
|
+
@tables = Baza::Driver.const_get(@type_cc).const_get(:Tables).new(
|
784
|
+
db: self
|
785
|
+
)
|
786
|
+
end
|
787
|
+
|
788
|
+
return @tables
|
789
|
+
end
|
790
|
+
|
791
|
+
#Returns the columns-module and spawns it if it isnt already spawned.
|
792
|
+
def cols
|
793
|
+
unless @cols
|
794
|
+
@cols = Baza::Driver.const_get(@type_cc).const_get(:Columns).new(
|
795
|
+
db: self
|
796
|
+
)
|
797
|
+
end
|
798
|
+
|
799
|
+
return @cols
|
800
|
+
end
|
801
|
+
|
802
|
+
#Returns the index-module and spawns it if it isnt already spawned.
|
803
|
+
def indexes
|
804
|
+
unless @indexes
|
805
|
+
@indexes = Baza::Driver.const_get(@type_cc).const_get(:Indexes).new(
|
806
|
+
db: self
|
807
|
+
)
|
808
|
+
end
|
809
|
+
|
810
|
+
return @indexes
|
811
|
+
end
|
812
|
+
|
813
|
+
#Returns the SQLSpec-module and spawns it if it isnt already spawned.
|
814
|
+
def sqlspecs
|
815
|
+
unless @sqlspecs
|
816
|
+
@sqlspecs = Baza::Driver.const_get(@type_cc).const_get(:Sqlspecs).new(
|
817
|
+
db: self
|
818
|
+
)
|
819
|
+
end
|
820
|
+
|
821
|
+
return @sqlspecs
|
822
|
+
end
|
823
|
+
|
824
|
+
#Beings a transaction and commits when the block ends.
|
825
|
+
#
|
826
|
+
#===Examples
|
827
|
+
# db.transaction do |db|
|
828
|
+
# db.insert(:users, name: "John")
|
829
|
+
# db.insert(:users, name: "Kasper")
|
830
|
+
# end
|
831
|
+
def transaction(&block)
|
832
|
+
conn_exec do |driver|
|
833
|
+
driver.transaction(&block)
|
834
|
+
end
|
835
|
+
|
836
|
+
return nil
|
837
|
+
end
|
838
|
+
|
839
|
+
#Optimizes all tables in the database.
|
840
|
+
def optimize(args = nil)
|
841
|
+
STDOUT.puts "Beginning optimization of database." if @debug || (args && args[:debug])
|
842
|
+
tables.list do |table|
|
843
|
+
STDOUT.puts "Optimizing table: '#{table.name}'." if @debug || (args && args[:debug])
|
844
|
+
table.optimize
|
845
|
+
end
|
846
|
+
|
847
|
+
return nil
|
848
|
+
end
|
849
|
+
|
850
|
+
#Proxies the method to the driver.
|
851
|
+
#
|
852
|
+
#===Examples
|
853
|
+
# db.method_on_driver
|
854
|
+
def method_missing(method_name, *args)
|
855
|
+
self.conn_exec do |driver|
|
856
|
+
if driver.respond_to?(method_name.to_sym)
|
857
|
+
return driver.send(method_name, *args)
|
858
|
+
end
|
859
|
+
end
|
860
|
+
|
861
|
+
raise "Method not found: '#{method_name}'."
|
862
|
+
end
|
863
|
+
|
864
|
+
def to_s
|
865
|
+
"#<Baza::Db driver \"#{@opts[:type]}\">"
|
866
|
+
end
|
867
|
+
|
868
|
+
def inspect
|
869
|
+
to_s
|
870
|
+
end
|
871
|
+
end
|