class Pupa::Processor::Connection::MongoDBAdapter

A proxy class to save plain old Ruby objects to MongoDB.

Attributes

raw_connection[R]

Public Class Methods

new(database_url) click to toggle source

@param [String] database_url the database URL

# File lib/pupa/processor/connection_adapters/mongodb_adapter.rb, line 11
def initialize(database_url)
  uri = URI.parse(database_url)
  @raw_connection = Mongo::Client.new(["#{uri.host}:#{uri.port}"], database: uri.path[1..-1])
  @raw_connection = @raw_connection.with(user: uri.user, password: uri.password) if uri.user && uri.password
end

Public Instance Methods

find(selector) click to toggle source

Finds a document matching the selection criteria.

The selection criteria must set a ‘_type` key in order to determine the collection to query.

@param [Hash] selector the selection criteria @return [Hash,nil] the matched document, or nil @raises [Pupa::Errors::TooManyMatches] if multiple documents are found

# File lib/pupa/processor/connection_adapters/mongodb_adapter.rb, line 25
def find(selector)
  collection_name = collection_name_from_class_name(selector[:_type].camelize)
  if selector.except(:_type).empty?
    raise Errors::EmptySelectorError, "selector is empty during find in collection #{collection_name}"
  end
  collection = raw_connection[collection_name]
  query = collection.find(selector)

  case query.count
  when 0
    nil
  when 1
    query.first
  else
    raise Errors::TooManyMatches, "selector matches multiple documents during find in collection #{collection_name}: #{JSON.dump(selector)}"
  end
end
save(object) click to toggle source

Inserts or replaces a document in MongoDB.

@param [Object] object an object @return [Array] whether the object was inserted and the object’s database ID @raises [Pupa::Errors::TooManyMatches] if multiple documents would be updated

# File lib/pupa/processor/connection_adapters/mongodb_adapter.rb, line 48
def save(object)
  selector = object.fingerprint

  collection_name = collection_name_from_class_name(object.class.to_s)
  if selector.empty?
    raise Errors::EmptySelectorError, "selector is empty during save in collection #{collection_name} for #{object._id}"
  end
  collection = raw_connection[collection_name]
  query = collection.find(selector)

  # Run query before callbacks to avoid e.g. timestamps in the selector.
  case query.count
  when 0
    object.run_callbacks(:save) do
      object.run_callbacks(:create) do
        collection.insert_one(object.to_h(persist: true))
        [true, object._id.to_s]
      end
    end
  when 1
    # Make the document available to the callbacks.
    # @see https://github.com/jpmckinney/pupa-ruby/issues/17
    object.document = query.first
    object.run_callbacks(:save) do
      query.update_one(object.to_h(persist: true).except(:_id))
      [false, object.document['_id'].to_s]
    end
  else
    raise Errors::TooManyMatches, "selector matches multiple documents during save in collection #{collection_name} for #{object._id}: #{JSON.dump(selector)}"
  end
end

Private Instance Methods

collection_name_from_class_name(class_name) click to toggle source

Returns the name of the collection in which to save the object.

@param [String] class_name the name of the object’s class @return [String] the name of the collection in which to save the object

# File lib/pupa/processor/connection_adapters/mongodb_adapter.rb, line 86
def collection_name_from_class_name(class_name)
  class_name.demodulize.underscore.pluralize.to_sym
end