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



640
641
642
# File 'lib/blackstack-deployer.rb', line 640

def self.checkpoint
  @@checkpoint
end

.connect(s) ⇒ Object



657
658
659
# File 'lib/blackstack-deployer.rb', line 657

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.



735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
# File 'lib/blackstack-deployer.rb', line 735

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.



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
722
723
724
725
726
727
728
729
730
731
# File 'lib/blackstack-deployer.rb', line 692

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.



684
685
686
# File 'lib/blackstack-deployer.rb', line 684

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)


676
677
678
# File 'lib/blackstack-deployer.rb', line 676

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)


669
670
671
# File 'lib/blackstack-deployer.rb', line 669

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

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



648
649
650
651
652
653
654
655
# File 'lib/blackstack-deployer.rb', line 648

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



644
645
646
# File 'lib/blackstack-deployer.rb', line 644

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

.set_checkpoint(s) ⇒ Object



636
637
638
# File 'lib/blackstack-deployer.rb', line 636

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

.set_folder(s) ⇒ Object

def



661
662
663
# File 'lib/blackstack-deployer.rb', line 661

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