Module: BlackStack::Deployer::DB

Defined in:
lib/blackstack-deployer.rb

Overview

def

Constant Summary collapse

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

Class Method Summary collapse

Class Method Details

.checkpointObject



535
536
537
# File 'lib/blackstack-deployer.rb', line 535

def self.checkpoint
  @@checkpoint
end

.connect(s) ⇒ Object



552
553
554
# File 'lib/blackstack-deployer.rb', line 552

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

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

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



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
# File 'lib/blackstack-deployer.rb', line 630

def self.deploy(save_checkpoints=false, lockfilename=BlackStack::Deployer::DB::LOCKFILE)
  tlogger = BlackStack::Deployer::logger
  # 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}"

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

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

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

.execute_sentences(sql, chunk_size = 200) ⇒ 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.



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
# File 'lib/blackstack-deployer.rb', line 587

def self.execute_sentences(sql, chunk_size=200)      
  tlogger = BlackStack::Deployer::logger

  # 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
  tlogger.logs "Splitting the sql sentences... "
  sentences = sql.split(/;/i) 
  tlogger.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
  tlogger.logs "Bunlding the array of sentences into chunks of #{chunk_size} each... "
  chunks = sentences.each_slice(chunk_size).to_a
  tlogger.logf "done (#{chunks.size})"

  chunk_number = -1
  chunks.each { |chunk|
    chunk_number += 1
    statement = chunk.join(";\n").to_s.strip
    tlogger.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
      tlogger.done
    rescue => e
      tlogger.logf e.to_s 
      raise "Error executing statement: #{statement}\n#{e.message}"
    end
  }
  tlogger.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.



579
580
581
# File 'lib/blackstack-deployer.rb', line 579

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)


571
572
573
# File 'lib/blackstack-deployer.rb', line 571

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)


564
565
566
# File 'lib/blackstack-deployer.rb', line 564

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

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



543
544
545
546
547
548
549
550
# File 'lib/blackstack-deployer.rb', line 543

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



539
540
541
# File 'lib/blackstack-deployer.rb', line 539

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

.set_checkpoint(s) ⇒ Object



531
532
533
# File 'lib/blackstack-deployer.rb', line 531

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

.set_folder(s) ⇒ Object

def



556
557
558
# File 'lib/blackstack-deployer.rb', line 556

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