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



598
599
600
# File 'lib/blackstack-deployer.rb', line 598

def self.checkpoint
  @@checkpoint
end

.connect(s) ⇒ Object



615
616
617
# File 'lib/blackstack-deployer.rb', line 615

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.



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

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.



650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
# File 'lib/blackstack-deployer.rb', line 650

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.



642
643
644
# File 'lib/blackstack-deployer.rb', line 642

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)


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

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)


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

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

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



606
607
608
609
610
611
612
613
# File 'lib/blackstack-deployer.rb', line 606

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



602
603
604
# File 'lib/blackstack-deployer.rb', line 602

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

.set_checkpoint(s) ⇒ Object



594
595
596
# File 'lib/blackstack-deployer.rb', line 594

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

.set_folder(s) ⇒ Object

def



619
620
621
# File 'lib/blackstack-deployer.rb', line 619

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