Class: Baza::Db

Inherits:
Object
  • Object
show all
Includes:
SimpleDelegate
Defined in:
lib/baza/db.rb

Overview

A wrapper of several possible database-types.

Examples

db = Baza::Db.new(type: :mysql2, db: “mysql”, user: “user”, pass: “password”) mysql_table = db.tables name = mysql_table.name cols = mysql_table.columns

db = Baza::Db.new(type: :sqlite3, path: “some_db.sqlite3”)

db.q(“SELECT * FROM users”) do |data|

print data[:name]

end

Constant Summary collapse

COPY_TO_ALLOWED_ARGS =
[:tables, :debug].freeze
DRIVER_PARTS =

Defines all the driver methods: tables, columns and so on

[:databases, :tables, :commands, :columns, :indexes, :users, :sqlspecs].freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts) ⇒ Db

Returns a new instance of Db.



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/baza/db.rb', line 69

def initialize(opts)
  @driver = opts.delete(:driver) if opts[:driver]
  Baza.load_driver(opts.fetch(:type))
  self.opts = opts unless opts.nil?
  @int_types = [:int, :bigint, :tinyint, :smallint, :mediumint]

  @debug = @opts[:debug]
  @driver = spawn
  @sep_database = @driver.sep_database
  @sep_table = @driver.sep_table
  @sep_col = @driver.sep_col
  @sep_index = @driver.sep_index
  @sep_val = @driver.sep_val

  return unless block_given?

  begin
    yield self
  ensure
    close
  end
end

Instance Attribute Details

#driverObject (readonly)

Returns the value of attribute driver.



21
22
23
# File 'lib/baza/db.rb', line 21

def driver
  @driver
end

#int_typesObject (readonly)

Returns the value of attribute int_types.



21
22
23
# File 'lib/baza/db.rb', line 21

def int_types
  @int_types
end

#optsObject

Returns the value of attribute opts.



21
22
23
# File 'lib/baza/db.rb', line 21

def opts
  @opts
end

#sep_colObject (readonly)

Returns the value of attribute sep_col.



21
22
23
# File 'lib/baza/db.rb', line 21

def sep_col
  @sep_col
end

#sep_databaseObject (readonly)

Returns the value of attribute sep_database.



21
22
23
# File 'lib/baza/db.rb', line 21

def sep_database
  @sep_database
end

#sep_indexObject (readonly)

Returns the value of attribute sep_index.



21
22
23
# File 'lib/baza/db.rb', line 21

def sep_index
  @sep_index
end

#sep_tableObject (readonly)

Returns the value of attribute sep_table.



21
22
23
# File 'lib/baza/db.rb', line 21

def sep_table
  @sep_table
end

#sep_valObject (readonly)

Returns the value of attribute sep_val.



21
22
23
# File 'lib/baza/db.rb', line 21

def sep_val
  @sep_val
end

Class Method Details

.driversObject

Returns an array containing hashes of information about each registered driver.



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/baza/db.rb', line 24

def self.drivers
  path = "#{File.dirname(__FILE__)}/driver"
  drivers = []

  Dir.foreach(path) do |file|
    next if file.to_s.slice(0, 1) == "."
    fp = "#{path}/#{file}"
    next unless File.directory?(fp)

    driver_file = "#{fp}/#{file}.rb"
    class_name = StringCases.snake_to_camel(file).to_sym

    drivers << {
      name: file,
      driver_path: driver_file,
      class_name: class_name
    }
  end

  drivers
end

.from_object(args) ⇒ Object

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).



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/baza/db.rb', line 47

def self.from_object(args)
  args = {object: args} unless args.is_a?(Hash)
  raise "No :object was given." unless args[:object]

  Baza::Db.drivers.each do |driver|
    const = Baza::Driver.const_get(driver[:class_name])
    next unless const.respond_to?(:from_object)

    obj = const.from_object(args)
    next unless obj.is_a?(Hash) && obj[:type] == :success
    if obj[:args]
      new_args = obj[:args]
      new_args = new_args.merge(args[:new_args]) if args[:new_args]
      return Baza::Db.new(new_args)
    else
      raise "Didnt know what to do."
    end
  end

  raise "Could not figure out what to do what object of type: '#{args[:object].class.name}'."
end

Instance Method Details

#add_sql_to_error(error, sql) ⇒ Object



230
231
232
# File 'lib/baza/db.rb', line 230

def add_sql_to_error(error, sql)
  error.message << " (SQL: #{sql})"
end

#argsObject



92
93
94
# File 'lib/baza/db.rb', line 92

def args
  @opts
end

#clone_conn(args = {}) ⇒ Object

Clones the current database-connection with possible extra arguments.



157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/baza/db.rb', line 157

def clone_conn(args = {})
  conn = Baza::Db.new(@opts.merge(args))

  if block_given?
    begin
      yield(conn)
    ensure
      conn.close
    end

    return nil
  else
    return conn
  end
end

#cloned_conn(args = nil, &_block) ⇒ Object

Clones the connection, executes the given block and closes the connection again.

Examples

db.cloned_conn do |conn|

conn.q('SELCET * FROM users') do |data|
  print data[:name]
end

end



359
360
361
362
363
364
365
366
367
368
# File 'lib/baza/db.rb', line 359

def cloned_conn(args = nil, &_block)
  clone_conn_args = args[:clone_args] || {}
  dbconn = clone_conn(clone_conn_args)

  begin
    yield(dbconn)
  ensure
    dbconn.close
  end
end

#closeObject

The all driver-database-connections.



146
147
148
149
150
# File 'lib/baza/db.rb', line 146

def close
  @driver.close if @driver
  @driver = nil
  @closed = true
end

#closed?Boolean

Returns:

  • (Boolean)


152
153
154
# File 'lib/baza/db.rb', line 152

def closed?
  @closed
end

#copy_to(db, args = {}) ⇒ Object

Copies the content of the current database to another instance of Baza::Db.



175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
# File 'lib/baza/db.rb', line 175

def copy_to(db, args = {})
  debug = args[:debug]
  raise "No tables given." unless data[:tables]

  data[:tables].each do |table|
    table_args = nil
    table_args = args[:tables][table[:name]] if args && args[:tables] && args[:tables][table[:name].to_sym]
    next if table_args && table_args[:skip]
    table.delete(:indexes) if table.key?(:indexes) && args[:skip_indexes]

    table_name = table.delete(:name)
    puts "Creating table: '#{table_name}'." if debug
    db.tables.create(table_name, table)

    limit_from = 0
    limit_incr = 1000

    loop do
      puts "Copying rows (#{limit_from}, #{limit_incr})." if debug
      ins_arr = []
      select(table_name, {}, limit_from: limit_from, limit_to: limit_incr) do |d_rows|
        col_args = nil

        if table_args && table_args[:columns]
          d_rows.each do |col_name, _col_data|
            col_args = table_args[:columns][col_name] if table_args && table_args[:columns]
            d_rows[col_name] = "" if col_args && col_args[:empty]
          end
        end

        ins_arr << d_rows
      end

      break if ins_arr.empty?

      puts "Insertering #{ins_arr.length} rows." if debug
      db.insert_multi(table_name, ins_arr)
      limit_from += limit_incr
    end
  end
end

#dataObject

Returns the data of this database in a hash.

Examples

data = db.data tables_hash = data



221
222
223
224
225
226
227
228
# File 'lib/baza/db.rb', line 221

def data
  tables_ret = []
  tables.list do |table|
    tables_ret << table.data
  end

  {tables: tables_ret}
end

#date_in(date_obj) ⇒ Object

Takes a valid date-db-string and converts it into a Datet.

Examples

db.date_in(‘2012-05-20 22:06:09’) #=> 2012-05-20 22:06:09 +0200



387
388
389
390
# File 'lib/baza/db.rb', line 387

def date_in(date_obj)
  return @driver.date_in(date_obj) if @driver.respond_to?(:date_in)
  Datet.in(date_obj)
end

#date_out(date_obj = Datet.new, args = {}) ⇒ Object

Returns a string which can be used in SQL with the current driver.

Examples

str = db.date_out(Time.now) #=> “2012-05-20 22:06:09”



379
380
381
382
# File 'lib/baza/db.rb', line 379

def date_out(date_obj = Datet.new, args = {})
  return @driver.date_out(date_obj, args) if @driver.respond_to?(:date_out)
  Datet.in(date_obj).dbstr(args)
end

#in_transaction?Boolean

Returns:

  • (Boolean)


288
289
290
# File 'lib/baza/db.rb', line 288

def in_transaction?
  @in_transaction
end

#insert_multi(tablename, arr_hashes, args = {}) ⇒ Object

Simply and optimal insert multiple rows into a table in a single query. Uses the drivers functionality if supported or inserts each row manually.

Examples

db.insert_multi(:users, [

{name: "John", lastname: "Doe"},
{name: "Kasper", lastname: "Johansen"}

])



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
# File 'lib/baza/db.rb', line 241

def insert_multi(tablename, arr_hashes, args = {})
  return false if arr_hashes.empty?

  if @driver.respond_to?(:insert_multi)
    if args && args[:return_sql]
      res = @driver.insert_multi(tablename, arr_hashes, args)
      if res.is_a?(String)
        return [res]
      elsif res.is_a?(Array)
        return res
      else
        raise "Unknown result: '#{res.class.name}'."
      end
    end

    @driver.insert_multi(tablename, arr_hashes, args)
  else
    transaction do
      arr_hashes.each do |hash|
        insert(tablename, hash, args)
      end
    end

    return nil
  end
end

#inspectObject



457
458
459
# File 'lib/baza/db.rb', line 457

def inspect
  to_s
end

#mysql?Boolean

Returns:

  • (Boolean)


469
470
471
# File 'lib/baza/db.rb', line 469

def mysql?
  @mysql ||= @driver.class.name.downcase.include?("mysql")
end

#new_queryObject



461
462
463
# File 'lib/baza/db.rb', line 461

def new_query
  Baza::SqlQueries::Select.new(db: self)
end

#optimize(args = nil) ⇒ Object

Optimizes all tables in the database.



443
444
445
446
447
448
449
450
451
# File 'lib/baza/db.rb', line 443

def optimize(args = nil)
  STDOUT.puts "Beginning optimization of database." if @debug || (args && args[:debug])
  tables.list do |table|
    STDOUT.puts "Optimizing table: '#{table.name}'." if @debug || (args && args[:debug])
    table.optimize
  end

  self
end

#postgres?Boolean

Returns:

  • (Boolean)


473
474
475
# File 'lib/baza/db.rb', line 473

def postgres?
  @postgres ||= @driver.class.name.downcase.include?("pg")
end

#q_buffer(args = {}, &block) ⇒ Object

Yields a query-buffer and flushes at the end of the block given.



371
372
373
374
# File 'lib/baza/db.rb', line 371

def q_buffer(args = {}, &block)
  Baza::QueryBuffer.new(args.merge(db: self), &block)
  nil
end

#query(string, args = nil, &block) ⇒ Object Also known as: q

Executes a query and returns the result.

Examples

res = db.query(‘SELECT * FROM users’) while data = res.fetch

print data[:name]

end



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
# File 'lib/baza/db.rb', line 299

def query(string, args = nil, &block)
  if @debug
    print "SQL: #{string}\n"

    if @debug.is_a?(Fixnum) && @debug >= 2
      print caller.join("\n")
      print "\n"
    end
  end

  # If the query should be executed in a new connection unbuffered.
  if args && args[:cloned_ubuf]
    raise "No block given." unless block

    cloned_conn(clone_args: args[:clone_args]) do |cloned_conn|
      return cloned_conn.query_ubuf(string, args, &block)
    end

    return nil
  end

  return query_ubuf(string, args, &block) if args && args[:type] == :unbuffered

  ret = @driver.query(string)

  if block && ret
    ret.each(&block)
    return nil
  end

  ret
end

#query_ubuf(string, _args = nil, &block) ⇒ Object

Execute an ubuffered query and returns the result.

Examples

db.query_ubuf(‘SELECT * FROM users’) do |data|

print data[:name]

end



340
341
342
343
344
345
346
347
348
349
# File 'lib/baza/db.rb', line 340

def query_ubuf(string, _args = nil, &block)
  ret = @driver.query_ubuf(string)

  if block
    ret.each(&block)
    return nil
  end

  ret
end

#register_threadObject

Registers a driver to the current thread.



121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/baza/db.rb', line 121

def register_thread
  raise "Baza-object is not in threadding mode" unless @conns

  thread_cur = Thread.current
  tid = __id__
  thread_cur[:baza] = {} unless thread_cur[:baza]

  if thread_cur[:baza][tid]
    # An object has already been spawned - free that first to avoid endless "used" objects.
    free_thread
  end

  thread_cur[:baza][tid] = @conns.get_and_lock unless thread_cur[:baza][tid]

  # If block given then be ensure to free thread after yielding.
  return unless block_given?

  begin
    yield
  ensure
    free_thread
  end
end

#spawnObject

Spawns a new driver (useally done automatically).

Examples

driver_instance = db.spawn



113
114
115
116
117
118
# File 'lib/baza/db.rb', line 113

def spawn
  raise "No type given (#{@opts.keys.join(",")})." unless @opts[:type]
  rpath = "#{File.dirname(__FILE__)}/driver/#{@opts.fetch(:type)}.rb"
  require rpath if File.exist?(rpath)
  Baza::Driver.const_get(@type_cc).new(self)
end

#sqlite?Boolean

Returns:

  • (Boolean)


465
466
467
# File 'lib/baza/db.rb', line 465

def sqlite?
  @sqlite ||= @driver.class.name.downcase.include?("sqlite")
end

#supports_multiple_databases?Boolean

Returns:

  • (Boolean)


408
409
410
411
412
413
414
# File 'lib/baza/db.rb', line 408

def supports_multiple_databases?
  if @driver.respond_to?(:supports_multiple_databases?)
    @driver.supports_multiple_databases?
  else
    false
  end
end

#supports_type_translation?Boolean

Returns:

  • (Boolean)


416
417
418
419
420
421
422
# File 'lib/baza/db.rb', line 416

def supports_type_translation?
  if @driver.respond_to?(:supports_type_translation?)
    @driver.supports_multiple_databases?
  else
    false
  end
end

#to_sObject



453
454
455
# File 'lib/baza/db.rb', line 453

def to_s
  "#<Baza::Db driver=\"#{@opts.fetch(:type)}\">"
end

#transaction(&block) ⇒ Object

Beings a transaction and commits when the block ends.

Examples

db.transaction do |db|

db.insert(:users, name: "John")
db.insert(:users, name: "Kasper")

end



431
432
433
434
435
436
437
438
439
440
# File 'lib/baza/db.rb', line 431

def transaction(&block)
  @in_transaction = true
  begin
    @driver.transaction(&block)
  ensure
    @in_transaction = false
  end

  self
end

#update(table_name, data, terms = {}, args = {}) ⇒ Object

Simple updates rows.

Examples

db.update(:users, “John”, “Doe”)



272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
# File 'lib/baza/db.rb', line 272

def update(table_name, data, terms = {}, args = {})
  command = Baza::SqlQueries::GenericUpdate.new(
    db: self,
    table_name: table_name,
    data: data,
    terms: terms,
    buffer: args[:buffer]
  )

  if args[:return_sql]
    command.to_sql
  else
    command.execute
  end
end