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

#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



368
369
370
371
# File 'lib/baza/db.rb', line 368

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”



360
361
362
363
# File 'lib/baza/db.rb', line 360

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



438
439
440
# File 'lib/baza/db.rb', line 438

def inspect
  to_s
end

#mysql?Boolean

Returns:

  • (Boolean)


450
451
452
# File 'lib/baza/db.rb', line 450

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

#new_queryObject



442
443
444
# File 'lib/baza/db.rb', line 442

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

#optimize(args = nil) ⇒ Object

Optimizes all tables in the database.



424
425
426
427
428
429
430
431
432
# File 'lib/baza/db.rb', line 424

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)


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

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.



352
353
354
355
# File 'lib/baza/db.rb', line 352

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)


446
447
448
# File 'lib/baza/db.rb', line 446

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

#supports_multiple_databases?Boolean

Returns:

  • (Boolean)


389
390
391
392
393
394
395
# File 'lib/baza/db.rb', line 389

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)


397
398
399
400
401
402
403
# File 'lib/baza/db.rb', line 397

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

#to_sObject



434
435
436
# File 'lib/baza/db.rb', line 434

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



412
413
414
415
416
417
418
419
420
421
# File 'lib/baza/db.rb', line 412

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