class FactoryBro
Public Class Methods
close(name)
click to toggle source
# File lib/factory_bro.rb, line 37 def self.close(name) $conns[name].finish $conns[name] = '' $dbs[name] = '' end
close_all()
click to toggle source
# File lib/factory_bro.rb, line 43 def self.close_all $conns.each do |key, conn| if conn.class == PG::Connection conn.finish end end $conns = nil $dbs = nil end
connect(name, db)
click to toggle source
# File lib/factory_bro.rb, line 6 def self.connect(name, db) unless $conns $conns = {} else $conns.each do |key, conn| if conn&.finished? $conns[key] = '' end end end unless $dbs $dbs = {} end $dbs[name] = db if db.include? 'postgres://' dbData = parse_url(db) $conns[name] = safe_connect(name) do PG.connect( user: dbData[:user], password: dbData[:pw], host: dbData[:host], port: dbData[:port], dbname: dbData[:dbname] ) end else # take arguments of user and pw $conns[name] = safe_connect { PG.connect(dbname: db) } end end
create_bases(name)
click to toggle source
# File lib/factory_bro.rb, line 59 def self.create_bases(name) tables = parse_tables(name) system 'mkdir', '-p', 'factories' unless File.directory?(Dir.pwd+"/factories") tables.each do |table| path = File.join(Dir.pwd, 'factories', "#{table}.rb") unless File.exists?(path) File.open(path, 'w') {|file| file.write(base_factory_content(name, table)) } # puts "#{table} factory created at: #{path}" end end end
exec(name, statement)
click to toggle source
# File lib/factory_bro.rb, line 53 def self.exec(name, statement) run = safe_connect(name) { $conns[name].exec(statement) } $try = 0 run.values end
generate_data(name, table, data)
click to toggle source
# File lib/factory_bro.rb, line 72 def self.generate_data(name, table, data) helperData = generate_helper(data[:factoryData]) res = $conns[name].exec("INSERT INTO #{table} (#{helperData[:columns]}) VALUES (#{helperData[:values]});") data[:meta] end
Private Class Methods
auto_faker_assignment(column)
click to toggle source
# File lib/factory_bro.rb, line 132 def self.auto_faker_assignment(column) type = column[1] # hash this name = column.first if type == "character varying" if name.include? 'sign_in_ip' return "Faker::Internet.ip_v4_address" elsif name == 'email' return "test#{rand(99999)}@example.com" else return "Faker::Lorem.characters(32)" end elsif type == "text" return "# password and password salt? don't know what to return" elsif type == "integer" return "rand(0...1000)" elsif type == "boolean" return "Faker::Boolean.boolean" elsif type == "timestamp with time zone" return "Faker::Time.between(DateTime.now - 1, DateTime.now)" else "# could not determine type: #{type}" end end
base_factory_content(name, table)
click to toggle source
# File lib/factory_bro.rb, line 110 def self.base_factory_content(name, table) "module Factory class #{table.split('_').map { |word| word.capitalize }.join} def self.base # remember: # to return any needed metadata (i.e. ID) # run other required bases before running method below FactoryBro.generate_data('#{name}', '#{table}' , #{base_method_helper(name, table)}) end end end " end
base_method_helper(name, table)
click to toggle source
# File lib/factory_bro.rb, line 124 def self.base_method_helper(name, table) data = {} parse_columns(name, table).each do |column| data.merge!(column.first => auto_faker_assignment(column)) # idk if auto faker assignment is helping or a burden? end JSON.pretty_generate({ "factoryData" => data, "meta"=> {}}) end
generate_helper(data)
click to toggle source
# File lib/factory_bro.rb, line 156 def self.generate_helper(data) formatted = data.to_a columns = "#{formatted.first.first.to_s}" values = "'#{formatted.first.last}'" formatted.shift formatted.each do |column| columns += ", #{column.first.to_s}" values += ", '#{column.last}'" end { columns: columns, values: values} end
parse_columns(name, table)
click to toggle source
# File lib/factory_bro.rb, line 102 def self.parse_columns(name, table) # hash this res = $conns[name].exec("SELECT COLUMN_NAME, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '#{table}';") res.values # as tuple end
parse_tables(name)
click to toggle source
# File lib/factory_bro.rb, line 94 def self.parse_tables(name) res = $conns[name].exec("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_SCHEMA='public' ORDER BY TABLE_NAME;") res.values.flatten # as array of column names end
parse_url(url)
click to toggle source
# File lib/factory_bro.rb, line 81 def self.parse_url(url) pwData = url.scan(/:[A-Za-z0-9]+@/).first hostData = url.scan(/(?<=@)(.*)(?=:)/).first user = (url.scan(/postgres:..[A-Za-z0-9]+/).first.split('//') - ['localhost', 'postgres:']).first { :user => user, :port => url.scan(/:[0-9]+./).first.split('/').first.gsub(/[^a-zA-Z0-9\-]/,""), :dbname => url.scan(/.[A-Za-z0-9]+$/).first.gsub(/[^a-zA-Z0-9\-]/,""), :host => hostData ? hostData.first : 'localhost', :pw => pwData ? pwData.gsub(/[^a-zA-Z0-9\-]/,"") : nil } end
safe_connect(name) { || ... }
click to toggle source
# File lib/factory_bro.rb, line 168 def self.safe_connect(name) $try ||= 0 max_tries = 4 wait = 10 success = false result = nil until success begin result = yield success = true result rescue PG::UnableToSend, PG::ConnectionBad => error $try += 1 raise error if $try > max_tries puts "FactoryBro error: Failed to connect to #{name}, try ##{$try} to reconnect in #{wait}s" sleep wait connect(name, $dbs[name]) end end result end