class Terrestrial::Adapters::SequelPostgresAdapter

Attributes

database[R]

Public Class Methods

new(database) click to toggle source
# File lib/terrestrial/adapters/sequel_postgres_adapter.rb, line 31
def initialize(database)
  @database = database
end

Public Instance Methods

[](table_name) click to toggle source
# File lib/terrestrial/adapters/sequel_postgres_adapter.rb, line 43
def [](table_name)
  Dataset.new(database[table_name])
end
changes_sql(record) click to toggle source
# File lib/terrestrial/adapters/sequel_postgres_adapter.rb, line 59
def changes_sql(record)
  generate_upsert_sql(record)
rescue Object => e
  raise UpsertError.new(record.namespace, record.to_h, e)
end
conflict_fields(table_name) click to toggle source
# File lib/terrestrial/adapters/sequel_postgres_adapter.rb, line 65
def conflict_fields(table_name)
  primary_key(table_name)
end
delete(record) click to toggle source
# File lib/terrestrial/adapters/sequel_postgres_adapter.rb, line 55
def delete(record)
  database[record.namespace].where(record.identity).delete
end
primary_key(table_name) click to toggle source
# File lib/terrestrial/adapters/sequel_postgres_adapter.rb, line 69
def primary_key(table_name)
  [database.primary_key(table_name)]
    .compact
    .map(&:to_sym)
end
relation_fields(relation_name) click to toggle source
# File lib/terrestrial/adapters/sequel_postgres_adapter.rb, line 85
def relation_fields(relation_name)
  database[relation_name].columns
end
relations() click to toggle source
# File lib/terrestrial/adapters/sequel_postgres_adapter.rb, line 81
def relations
  database.tables - [:schema_migrations]
end
schema(relation_name) click to toggle source
# File lib/terrestrial/adapters/sequel_postgres_adapter.rb, line 89
def schema(relation_name)
  database.schema(relation_name)
end
unique_indexes(table_name) click to toggle source
# File lib/terrestrial/adapters/sequel_postgres_adapter.rb, line 75
def unique_indexes(table_name)
  database.indexes(table_name).map { |_name, data|
    data.fetch(:columns)
  }
end
upsert(record) click to toggle source
# File lib/terrestrial/adapters/sequel_postgres_adapter.rb, line 47
def upsert(record)
  row = perform_upsert_returning_row(record)
  record.on_upsert(row)
  nil
rescue Object => e
  raise UpsertError.new(record.namespace, record.to_h, e)
end

Private Instance Methods

generate_upsert_sql(record) click to toggle source
# File lib/terrestrial/adapters/sequel_postgres_adapter.rb, line 102
def generate_upsert_sql(record)
  table_name = record.namespace
  update_attributes = record.updatable? && record.updatable_attributes

  primary_key_fields = primary_key(table_name)

  missing_not_null_fields = database.schema(table_name)
    .reject { |field_name, _| record.attributes.keys.include?(field_name) }
    .select { |_field_name, properties|
      allow_null = properties.fetch(:allow_null, true)
      not_null = !allow_null
      default = properties.fetch(:default, nil)
      no_default = !default

      not_null && no_default
    }
    .map(&:first)
    .reject { |field_name| record.identity_fields.include?(field_name) }

  missing_not_null_attrs = missing_not_null_fields
    .map { |field_name| [field_name, database[table_name].select(field_name).where(record.identity)] }
    .to_h

  # TODO: investigate if failing to find a private key results in extra schema queries
  if primary_key_fields.any?
    if record.id?
      conflict_fields = primary_key_fields
    else
      return database[table_name]
        .returning(Sequel.lit("*"))
        .insert_sql(record.insertable.merge(missing_not_null_attrs))
    end
  else
    u_idxs = unique_indexes(table_name)
    if u_idxs.any?
      conflict_fields = u_idxs.first
    end
  end

  upsert_args = { update: update_attributes }

  if conflict_fields && conflict_fields.any?
    upsert_args.merge!(target: conflict_fields)
  end

  # TODO: Use specific field list instead of Sequel.lit("*")
  database[table_name]
    .insert_conflict(**upsert_args)
    .returning(Sequel.lit("*"))
    .insert_sql(record.insertable.merge(missing_not_null_attrs))
end
perform_upsert_returning_row(record) click to toggle source
# File lib/terrestrial/adapters/sequel_postgres_adapter.rb, line 95
def perform_upsert_returning_row(record)
  sql = generate_upsert_sql(record)
  result = database[sql]
    .to_a
    .fetch(0) { {} }
end