class Baza::SqlQueries::SqliteUpsertDuplicateKey

Public Class Methods

new(args) click to toggle source
# File lib/baza/sql_queries/sqlite_upsert_duplicate_key.rb, line 2
def initialize(args)
  @db = args.fetch(:db)
  @table_name = args.fetch(:table_name)
  @updates = StringCases.stringify_keys(args.fetch(:updates))
  @terms = StringCases.stringify_keys(args.fetch(:terms))
  @return_id = args[:return_id]
end

Public Instance Methods

execute() click to toggle source
# File lib/baza/sql_queries/sqlite_upsert_duplicate_key.rb, line 10
def execute
  return insert_or_handle_duplicate if @terms.empty?

  @db.transaction do
    @db.query(insert_sql)
    @db.query(update_sql)

    if @return_id
      data = @db.single(@table_name, @terms)
      raise "Couldn't find the updated data" unless data
      return data.fetch(primary_column).to_i
    end
  end
end

Private Instance Methods

insert_or_handle_duplicate() click to toggle source
# File lib/baza/sql_queries/sqlite_upsert_duplicate_key.rb, line 31
def insert_or_handle_duplicate
  @db.insert(@table_name, @updates)
  return @db.last_id if @return_id
rescue => e
  if (match = e.message.match(/UNIQUE constraint failed: #{Regexp.escape(@table_name)}\.(.+?)(:|\Z|\))/))
    column_name = match[1]
  elsif (match = e.message.match(/column (.+?) is not unique/))
    column_name = match[1]
  else
    raise e
  end

  conflicting_value = @updates.fetch(column_name)
  @db.update(@table_name, @updates, column_name => conflicting_value)

  if @return_id
    data = @db.single(@table_name, column_name => conflicting_value)
    raise "Couldn't find the updated data" unless data
    return data.fetch(primary_column).to_i
  end
end
insert_sql() click to toggle source
# File lib/baza/sql_queries/sqlite_upsert_duplicate_key.rb, line 53
def insert_sql
  sql = "INSERT OR IGNORE INTO #{@db.quote_table(@table_name)} ("

  combined_data = @updates.merge(@terms)

  first = true
  combined_data.each_key do |column_name|
    sql << ", " unless first
    first = false if first
    sql << @db.quote_column(column_name)
  end

  sql << ") VALUES ("

  first = true
  combined_data.each_value do |value|
    sql << ", " unless first
    first = false if first
    sql << @db.quote_value(value).to_s
  end

  sql << ")"
  sql
end
primary_column() click to toggle source
# File lib/baza/sql_queries/sqlite_upsert_duplicate_key.rb, line 27
def primary_column
  @primary_column ||= @db.tables[@table_name.to_s].columns.find(&:primarykey?).name.to_sym
end
update_sql() click to toggle source
# File lib/baza/sql_queries/sqlite_upsert_duplicate_key.rb, line 78
def update_sql
  sql = "UPDATE OR IGNORE #{@db.quote_table(@table_name)} SET "

  first = true
  @updates.each do |key, value|
    sql << ", " unless first
    first = false if first
    sql << "#{@db.quote_column(key)} = #{@db.quote_value(value)}"
  end

  sql << " WHERE "

  first = true
  @terms.each do |key, value|
    sql << " AND " unless first
    first = false if first
    sql << "#{@db.quote_column(key)} = #{@db.quote_value(value)}"
  end

  sql
end