Module: BlackStack::Deployer::DB

Defined in:
lib/my-ruby-deployer.rb

Overview

def self.run_routine

Constant Summary collapse

LOCKFILE =
'./my-ruby-deployer.lock'
@@checkpoint =
nil
@@superhuser =
nil
@@ndb =
nil
@@folder =
nil

Class Method Summary collapse

Class Method Details

.checkpointObject



371
372
373
# File 'lib/my-ruby-deployer.rb', line 371

def self.checkpoint
  @@checkpoint
end

.connect(s) ⇒ Object



388
389
390
# File 'lib/my-ruby-deployer.rb', line 388

def self.connect(s)
  @@db = Sequel::connect(s)
end

.deploy(save_checkpoints = false, lockfilename = BlackStack::Deployer::DB::LOCKFILE, l = nil) ⇒ Object

Run a series of ‘.sql` files with updates to the database.



466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
# File 'lib/my-ruby-deployer.rb', line 466

def self.deploy(save_checkpoints=false, lockfilename=BlackStack::Deployer::DB::LOCKFILE, l=nil)
  l = BlackStack::DummyLogger.new(nil) if l.nil?
  # get list of `.sql` files in the directory `sql_path`, with a name higher than `last_filename`, sorted by name.

  Dir.entries(@@folder).select { 
    |filename| filename =~ /\.sql$/ && filename > @@checkpoint.to_s
  }.uniq.sort.each { |filename|
    fullfilename = "#{@@folder}/#{filename}"

    l.logs "#{fullfilename}... "
    BlackStack::Deployer::DB::execute_sentences( File.open(fullfilename).read )
    l.done

    l.logs "Updating checkpoint... "
    BlackStack::Deployer::DB::set_checkpoint filename
    l.done

    l.logs 'Saving checkpoint... '
    if save_checkpoints
      BlackStack::Deployer::DB::save_checkpoint(lockfilename)
      l.done
    else
      l.logf 'disabled'
    end
  }
end

.execute_sentences(sql, chunk_size = 200, l = nil) ⇒ Object

Method to process an ‘.sql` file with one sql sentence by line. Reference: stackoverflow.com/questions/64066344/import-large-sql-files-with-ruby-sequel-gem This method is called by `BlackStack::Deployer::db_execute_file` if the filename matches with `/.sentences./`. This method should not be called directly by user code.



423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
# File 'lib/my-ruby-deployer.rb', line 423

def self.execute_sentences(sql, chunk_size=200, l=nil)      
  l = BlackStack::DummyLogger.new(nil) if l.nil?
  
  # Fix issue: Ruby `split': invalid byte sequence in UTF-8 (ArgumentError)
  # Reference: https://stackoverflow.com/questions/11065962/ruby-split-invalid-byte-sequence-in-utf-8-argumenterror
  #
  # Fix issue: `PG::SyntaxError: ERROR:  at or near "��truncate": syntax error`
  #
  sql.encode!('UTF-8', :invalid => :replace, :replace => '')

  # Remove null bytes to avoid error: `String contains null byte`
  # Reference: https://stackoverflow.com/questions/29320369/coping-with-string-contains-null-byte-sent-from-users
  sql.gsub!("\u0000", "")

  # Get the array of sentences
  l.logs "Splitting the sql sentences... "
  sentences = sql.split(/;/i) 
  l.logf "done (#{sentences.size})"

  # Chunk the array into parts of chunk_size elements
  # Reference: https://stackoverflow.com/questions/2699584/how-to-split-chunk-a-ruby-array-into-parts-of-x-elements
  l.logs "Bunlding the array of sentences into chunks of #{chunk_size} each... "
  chunks = sentences.each_slice(chunk_size).to_a
  l.logf "done (#{chunks.size})"

  chunk_number = -1
  chunks.each { |chunk|
    chunk_number += 1
    statement = chunk.join(";\n").to_s.strip
    l.logs "lines #{chunk_size*chunk_number+1} to #{chunk_size*chunk_number+chunk.size} of #{sentences.size}... "
    begin
      @@db.execute(statement) #if statement.to_s.strip.size > 0
      l.done
    rescue => e
      l.logf e.to_s 
      raise "Error executing statement: #{statement}\n#{e.message}"
    end
  }
  l.done
end

.execute_transactions(sql) ⇒ Object

Method to process an ‘.sql` file with transactions code, separated by `BEGIN;` and `COMMIT;` statements. Reference: stackoverflow.com/questions/64066344/import-large-sql-files-with-ruby-sequel-gem This method is called by `BlackStack::Deployer::db_execute_file` if the filename matches with `/.tsql./`. This method should not be called directly by user code.



415
416
417
# File 'lib/my-ruby-deployer.rb', line 415

def self.execute_transactions(sql)  
  # TODO: Code Me!
end

.is_sentences_file?(filename) ⇒ Boolean

Return ‘true` if the name of the file matches with `/.sentences./`, and it doesn’t match with ‘/.transactions./`, and the matches with `/.sentences./` are no more than one. Otherwise({, return `false`. This method should not be called directly by user code.

Returns:

  • (Boolean)


407
408
409
# File 'lib/my-ruby-deployer.rb', line 407

def self.is_sentences_file?(filename)
  filename =~ /\.sentences\./ && filename !~ /\.transactions\./ && filename.scan(/\.sentences\./).size == 1
end

.is_transactions_file?(filename) ⇒ Boolean

Return ‘true` if the name of the file matches with `/.transactions./`, and it doesn’t match with ‘/.sentences./`, and the matches with `/.transactions./` are no more than one. Otherwise, return `false`. This method should not be called directly by user code.

Returns:

  • (Boolean)


400
401
402
# File 'lib/my-ruby-deployer.rb', line 400

def self.is_transactions_file?(filename)
  filename =~ /\.transactions\./ && filename !~ /\.sentences\./ && filename.scan(/\.transactions\./).size == 1
end

.load_checkpoint(lockfilename = BlackStack::Deployer::DB::LOCKFILE) ⇒ Object



379
380
381
382
383
384
385
386
# File 'lib/my-ruby-deployer.rb', line 379

def self.load_checkpoint(lockfilename=BlackStack::Deployer::DB::LOCKFILE)
  if File.exists?(lockfilename)
    @@checkpoint = File.new(lockfilename, "r").read
  else
    @@checkpoint = nil
  end
  @@checkpoint
end

.save_checkpoint(lockfilename = BlackStack::Deployer::DB::LOCKFILE) ⇒ Object



375
376
377
# File 'lib/my-ruby-deployer.rb', line 375

def self.save_checkpoint(lockfilename=BlackStack::Deployer::DB::LOCKFILE)
  File.new(lockfilename, "w").write(@@checkpoint)
end

.set_checkpoint(s) ⇒ Object



367
368
369
# File 'lib/my-ruby-deployer.rb', line 367

def self.set_checkpoint(s)
  @@checkpoint = s
end

.set_folder(s) ⇒ Object

def



392
393
394
# File 'lib/my-ruby-deployer.rb', line 392

def self.set_folder(s)
  @@folder = s
end