class Vorpal::Engine

Public Class Methods

new(db_driver, main_config) click to toggle source

@private

# File lib/vorpal/engine.rb, line 10
def initialize(db_driver, main_config)
  @db_driver = db_driver
  @configs = main_config
end

Public Instance Methods

class_config(domain_class) click to toggle source

@private

# File lib/vorpal/engine.rb, line 101
def class_config(domain_class)
  @configs.config_for(domain_class)
end
db_class(domain_class) click to toggle source

Try to use {AggregateMapper#db_class} instead.

# File lib/vorpal/engine.rb, line 91
def db_class(domain_class)
  @configs.config_for(domain_class).db_class
end
destroy(roots) click to toggle source

Try to use {AggregateMapper#destroy} instead.

# File lib/vorpal/engine.rb, line 69
def destroy(roots)
  roots = wrap(roots)
  return roots if roots.empty?
  raise InvalidAggregateRoot, 'Nil aggregate roots are not allowed.' if roots.any?(&:nil?)

  destroy_by_id(roots.map(&:id), roots.first.class)
  roots
end
destroy_by_id(ids, domain_class) click to toggle source

Try to use {AggregateMapper#destroy_by_id} instead.

# File lib/vorpal/engine.rb, line 79
def destroy_by_id(ids, domain_class)
  ids = wrap(ids)
  raise InvalidPrimaryKeyValue, 'Nil primary key values are not allowed.' if ids.any?(&:nil?)

  loaded_db_objects = load_owned_from_db(ids, domain_class)
  loaded_db_objects.each do |config, db_objects|
    @db_driver.destroy(config.db_class, db_objects.map(&:id))
  end
  ids
end
load_many(db_roots, domain_class, identity_map) click to toggle source

Try to use {AggregateMapper#load_many} instead.

# File lib/vorpal/engine.rb, line 58
def load_many(db_roots, domain_class, identity_map)
  raise InvalidAggregateRoot, 'Nil aggregate roots are not allowed.' if db_roots.any?(&:nil?)

  loaded_db_objects = DbLoader.new(false, @db_driver).load_from_db_objects(db_roots, @configs.config_for(domain_class))
  deserialize(loaded_db_objects, identity_map)
  set_associations(loaded_db_objects, identity_map)

  db_roots.map { |db_object| identity_map.get(db_object) }
end
load_one(db_root, domain_class, identity_map) click to toggle source

Try to use {AggregateMapper#load_one} instead.

# File lib/vorpal/engine.rb, line 53
def load_one(db_root, domain_class, identity_map)
  load_many(Array(db_root), domain_class, identity_map).first
end
mapper_for(domain_class) click to toggle source

Creates a mapper for saving/updating/loading/destroying an aggregate to/from the DB. It is possible to use the methods directly on the {Engine}.

@param domain_class [Class] Class of the root of the aggregate. @return [AggregateMapper] Mapper suitable for mapping a single aggregate.

# File lib/vorpal/engine.rb, line 20
def mapper_for(domain_class)
  AggregateMapper.new(domain_class, self)
end
persist(roots) click to toggle source

Try to use {AggregateMapper#persist} instead.

# File lib/vorpal/engine.rb, line 25
def persist(roots)
  roots = wrap(roots)
  return roots if roots.empty?
  raise InvalidAggregateRoot, 'Nil aggregate roots are not allowed.' if roots.any?(&:nil?)

  all_owned_objects = all_owned_objects(roots)
  mapping = {}
  loaded_db_objects = load_owned_from_db(roots.map(&:id).compact, roots.first.class)

  serialize(all_owned_objects, mapping, loaded_db_objects)
  new_objects = get_unsaved_objects(mapping.keys)
  begin
    # Primary keys are set eagerly (instead of waiting for them to be set by ActiveRecord upon create)
    # because we want to support non-null FK constraints without needing to figure the correct
    # order to save entities in.
    set_primary_keys(all_owned_objects, mapping)
    set_foreign_keys(all_owned_objects, mapping)
    remove_orphans(mapping, loaded_db_objects)
    save(all_owned_objects, new_objects, mapping)

    return roots
  rescue Exception
    nil_out_object_ids(new_objects)
    raise
  end
end
query(domain_class) click to toggle source

Try to use {AggregateMapper#query} instead.

# File lib/vorpal/engine.rb, line 96
def query(domain_class)
  @db_driver.query(@configs.config_for(domain_class).db_class, mapper_for(domain_class))
end

Private Instance Methods

all_owned_objects(roots) click to toggle source
# File lib/vorpal/engine.rb, line 115
def all_owned_objects(roots)
  AggregateUtils.group_by_type(roots, @configs)
end
deserialize(loaded_db_objects, identity_map) click to toggle source
# File lib/vorpal/engine.rb, line 127
def deserialize(loaded_db_objects, identity_map)
  loaded_db_objects.flat_map do |config, db_objects|
    db_objects.map do |db_object|
      # TODO: There is a bug here when you have something in the IdentityMap that is stale and needs to be updated.
      identity_map.get_and_set(db_object) { config.deserialize(db_object) }
    end
  end
end
get_unsaved_objects(objects) click to toggle source
# File lib/vorpal/engine.rb, line 241
def get_unsaved_objects(objects)
  objects.find_all { |object| object.id.nil? }
end
load_from_db(ids, domain_class, only_owned=false) click to toggle source
# File lib/vorpal/engine.rb, line 119
def load_from_db(ids, domain_class, only_owned=false)
  DbLoader.new(only_owned, @db_driver).load_from_db(ids, @configs.config_for(domain_class))
end
load_owned_from_db(ids, domain_class) click to toggle source
# File lib/vorpal/engine.rb, line 123
def load_owned_from_db(ids, domain_class)
  load_from_db(ids, domain_class, true)
end
nil_out_object_ids(objects) click to toggle source
# File lib/vorpal/engine.rb, line 245
def nil_out_object_ids(objects)
  objects ||= []
  objects.each { |object| object.id = nil }
end
remove_orphans(mapping, loaded_db_objects) click to toggle source
# File lib/vorpal/engine.rb, line 231
def remove_orphans(mapping, loaded_db_objects)
  db_objects_in_aggregate = mapping.values
  db_objects_in_db = loaded_db_objects.all_objects
  all_orphans = db_objects_in_db - db_objects_in_aggregate
  grouped_orphans = all_orphans.group_by { |o| @configs.config_for_db_object(o) }
  grouped_orphans.each do |config, orphans|
    @db_driver.destroy(config.db_class, orphans)
  end
end
save(owned_objects, new_objects, mapping) click to toggle source
# File lib/vorpal/engine.rb, line 218
def save(owned_objects, new_objects, mapping)
  grouped_new_objects = new_objects.group_by { |obj| @configs.config_for(obj.class) }
  owned_objects.each do |config, objects|
    objects_to_insert = grouped_new_objects[config] || []
    db_objects_to_insert = objects_to_insert.map { |obj| mapping[obj] }
    @db_driver.insert(config.db_class, db_objects_to_insert)

    objects_to_update = objects - objects_to_insert
    db_objects_to_update = objects_to_update.map { |obj| mapping[obj] }
    @db_driver.update(config.db_class, db_objects_to_update)
  end
end
serialize(owned_objects, mapping, loaded_db_objects) click to toggle source
# File lib/vorpal/engine.rb, line 151
def serialize(owned_objects, mapping, loaded_db_objects)
  owned_objects.each do |config, objects|
    objects.each do |object|
      db_object = serialize_object(object, config, loaded_db_objects)
      mapping[object] = db_object
    end
  end
end
serialize_object(object, config, loaded_db_objects) click to toggle source
# File lib/vorpal/engine.rb, line 160
def serialize_object(object, config, loaded_db_objects)
  if config.serialization_required?
    attributes = config.serialize(object)
    db_object = loaded_db_objects.find_by_primary_key(config, object)
    if object.id.nil? || db_object.nil? # object doesn't exist in the DB
      config.build_db_object(attributes)
    else
      config.set_db_object_attributes(db_object, attributes)
      db_object
    end
  else
    object
  end
end
set_associations(loaded_db_objects, identity_map) click to toggle source
# File lib/vorpal/engine.rb, line 136
def set_associations(loaded_db_objects, identity_map)
  loaded_db_objects.each do |config, db_objects|
    db_objects.each do |db_object|
      config.local_association_configs.each do |association_config|
        db_remote = loaded_db_objects.find_by_unique_key(
          association_config.remote_class_config(db_object),
          association_config.unique_key_name,
          association_config.fk_value(db_object)
        )
        association_config.associate(identity_map.get(db_object), identity_map.get(db_remote))
      end
    end
  end
end
set_foreign_keys(owned_objects, mapping) click to toggle source
# File lib/vorpal/engine.rb, line 191
def set_foreign_keys(owned_objects, mapping)
  owned_objects.each do |config, objects|
    objects.each do |object|
      config.has_manys.each do |has_many_config|
        if has_many_config.owned
          associates = has_many_config.get_associated(object)
          associates.each do |associate|
            has_many_config.set_foreign_key(mapping[associate], object)
          end
        end
      end

      config.has_ones.each do |has_one_config|
        if has_one_config.owned
          associate = has_one_config.get_associated(object)
          has_one_config.set_foreign_key(mapping[associate], object) if associate
        end
      end

      config.belongs_tos.each do |belongs_to_config|
        associate = belongs_to_config.get_associated(object)
        belongs_to_config.set_foreign_key(mapping[object], associate)
      end
    end
  end
end
set_primary_keys(owned_objects, mapping) click to toggle source
# File lib/vorpal/engine.rb, line 175
def set_primary_keys(owned_objects, mapping)
  owned_objects.each do |config, objects|
    in_need_of_primary_keys = objects.find_all { |obj| obj.id.nil? }
    if config.primary_key_type == :uuid
      primary_keys = Array.new(in_need_of_primary_keys.length) { SecureRandom.uuid }
    elsif config.primary_key_type == :serial
      primary_keys = @db_driver.get_primary_keys(config.db_class, in_need_of_primary_keys.length)
    end
    in_need_of_primary_keys.zip(primary_keys).each do |object, primary_key|
      mapping[object].id = primary_key
      object.id = primary_key
    end
  end
  mapping.rehash # needs to happen because setting the id on an AR::Base model changes its hash value
end
wrap(collection_or_not) click to toggle source
# File lib/vorpal/engine.rb, line 107
def wrap(collection_or_not)
  if collection_or_not.is_a?(Array)
    collection_or_not
  else
    [collection_or_not]
  end
end