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



630
631
632
# File 'lib/blackstack-deployer.rb', line 630

def self.checkpoint
  @@checkpoint
end

.connect(s) ⇒ Object



647
648
649
# File 'lib/blackstack-deployer.rb', line 647

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.



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

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.



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

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.



674
675
676
# File 'lib/blackstack-deployer.rb', line 674

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)


666
667
668
# File 'lib/blackstack-deployer.rb', line 666

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)


659
660
661
# File 'lib/blackstack-deployer.rb', line 659

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

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



638
639
640
641
642
643
644
645
# File 'lib/blackstack-deployer.rb', line 638

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



634
635
636
# File 'lib/blackstack-deployer.rb', line 634

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

.set_checkpoint(s) ⇒ Object



626
627
628
# File 'lib/blackstack-deployer.rb', line 626

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

.set_folder(s) ⇒ Object

def



651
652
653
# File 'lib/blackstack-deployer.rb', line 651

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