Class: Mongoid::PersistenceContext
| Relationships & Source Files | |
| Super Chains via Extension / Inclusion / Inheritance | |
|
Class Chain:
self,
Forwardable
|
|
| Inherits: | Object |
| Defined in: | lib/mongoid/persistence_context.rb |
Overview
::Object encapsulating logic for setting/getting a collection and database name
and a client with particular options to use when persisting models.
Constant Summary
-
EXTRA_OPTIONS =
# File 'lib/mongoid/persistence_context.rb', line 25
Extra options in addition to driver client options that determine the persistence context.
%i[client collection collection_options].freeze
-
PERSISTENCE_CONTEXT_KEY =
# File 'lib/mongoid/persistence_context.rb', line 314
Key to store persistence contexts in the thread local storage.
:'[mongoid]:persistence_context'
-
VALID_OPTIONS =
# File 'lib/mongoid/persistence_context.rb', line 33
The full list of valid persistence context options.
(Mongo::Client::VALID_OPTIONS + EXTRA_OPTIONS).freeze
Class Method Summary
-
.clear(object, cluster = nil, original_context = nil)
Clear the persistence context for a particular class or model instance.
-
.get(object) ⇒ Mongoid::PersistenceContext
Get the persistence context for a particular class or model instance.
-
.new(object, opts = {}) ⇒ PersistenceContext
constructor
Initialize the persistence context object.
-
.set(object, options_or_context) ⇒ Mongoid::PersistenceContext
::Setthe persistence context for a particular class or model instance. - .context_store private
-
.get_context(object) ⇒ Mongoid::PersistenceContext | nil
private
Internal use only
Get the persistence context for a given object from the thread local.
-
.store_context(object, context)
private
Internal use only
Store persistence context for a given object in the thread local.
Instance Attribute Summary
-
#options ⇒ Hash
readonly
The options defining this persistence context.
-
#reusable_client? ⇒ true | false
readonly
Internal use only
Whether the client of the context can be reused later, and therefore should not be closed.
Instance Method Summary
-
#==(other) ⇒ true | false
Determine if this persistence context is equal to another.
-
#client ⇒ Mongo::Client
Get the client for this persistence context.
-
#client_name ⇒ Symbol
Get the client name for this persistence context.
-
#collection(parent = nil) ⇒ Mongo::Collection
Get the collection for this persistence context.
-
#collection_name ⇒ String
Get the collection name for this persistence context.
-
#database_name ⇒ String
Get the database name for this persistence context.
-
#for_child(document) ⇒ PersistenceContext
Internal use only
Returns a new persistence context that is consistent with the given child document, inheriting most appropriate settings.
-
#requested_storage_options ⇒ Hash | nil
Internal use only
The subset of provided options that may be used as storage options.
- #__evaluate__(name) private
- #client_options private
- #database_name_option private
- #set_options!(opts) private
-
#verify_encryption_schema!(client)
private
Refuse to use a client that would store a model's encrypted fields in plaintext.
Constructor Details
.new(object, opts = {}) ⇒ PersistenceContext
Initialize the persistence context object.
# File 'lib/mongoid/persistence_context.rb', line 43
def initialize(object, opts = {}) @object = object (opts) end
Class Method Details
.clear(object, cluster = nil, original_context = nil)
Clear the persistence context for a particular class or model instance.
# File 'lib/mongoid/persistence_context.rb', line 301
def clear(object, cluster = nil, original_context = nil) if (context = get(object)) && !(cluster.nil? || context.cluster.equal?(cluster)) && !context.reusable_client? context.client.close end ensure store_context(object, original_context) end
.context_store (private)
[ GitHub ]# File 'lib/mongoid/persistence_context.rb', line 316
def context_store Threaded.get(PERSISTENCE_CONTEXT_KEY) { {} } end
.get(object) ⇒ PersistenceContext
Get the persistence context for a particular class or model instance.
# File 'lib/mongoid/persistence_context.rb', line 288
def get(object) get_context(object) end
.get_context(object) ⇒ PersistenceContext | nil (private)
Get the persistence context for a given object from the thread local storage.
# File 'lib/mongoid/persistence_context.rb', line 329
def get_context(object) context_store[object.object_id] end
.set(object, options_or_context) ⇒ PersistenceContext
::Set the persistence context for a particular class or model instance.
If there already is a persistence context set, options in the existing context are combined with options given to the set call.
# File 'lib/mongoid/persistence_context.rb', line 267
def set(object, ) existing_context = get_context(object) = if existing_context existing_context. else {} end = . if .is_a?(PersistenceContext) = .merge() context = PersistenceContext.new(object, ) store_context(object, context) end
.store_context(object, context) (private)
Store persistence context for a given object in the thread local storage.
# File 'lib/mongoid/persistence_context.rb', line 340
def store_context(object, context) if context.nil? context_store.delete(object.object_id) else context_store[object.object_id] = context end end
Instance Attribute Details
#options ⇒ Hash (readonly)
The options defining this persistence context.
# File 'lib/mongoid/persistence_context.rb', line 18
attr_reader :
#reusable_client? ⇒ true | false (readonly)
Whether the client of the context can be reused later, and therefore should not be closed.
If the persistence context is requested with :client option only, it means
that the context should use a client configured in mongoid.yml.
Such clients should not be closed when the context is cleared since they
will be reused later.
# File 'lib/mongoid/persistence_context.rb', line 172
def reusable_client? @options.keys == [ :client ] end
Instance Method Details
#==(other) ⇒ true | false
Determine if this persistence context is equal to another.
# File 'lib/mongoid/persistence_context.rb', line 155
def ==(other) return false unless other.is_a?(PersistenceContext) == other. end
#__evaluate__(name) (private)
[ GitHub ]# File 'lib/mongoid/persistence_context.rb', line 198
def __evaluate__(name) return nil unless name name.respond_to?(:call) ? name.call.to_sym : name.to_sym end
#client ⇒ Mongo::Client
Get the client for this persistence context.
# File 'lib/mongoid/persistence_context.rb', line 116
def client @client ||= begin client = Clients.with_name(client_name) = if database_name_option client = client.use(database_name) = .except(:database, 'database') end client = client.with() unless .empty? verify_encryption_schema!(client) client end end
#client_name ⇒ Symbol
Get the client name for this persistence context.
# File 'lib/mongoid/persistence_context.rb', line 141
def client_name @client_name ||= __evaluate__([:client]) || Threaded.client_override || __evaluate__([:client]) end
#client_options (private)
[ GitHub ]# File 'lib/mongoid/persistence_context.rb', line 237
def @client_options ||= begin opts = .select do |k, _v| Mongo::Client::VALID_OPTIONS.include?(k.to_sym) end opts[:read] = { mode: opts[:read] } if opts[:read].is_a?(Symbol) opts end end
#collection(parent = nil) ⇒ Mongo::Collection
Get the collection for this persistence context.
# File 'lib/mongoid/persistence_context.rb', line 78
def collection(parent = nil) if parent parent.collection.with(.except(:database, 'database')) else client[collection_name.to_sym] end end
#collection_name ⇒ String
Get the collection name for this persistence context.
# File 'lib/mongoid/persistence_context.rb', line 93
def collection_name @collection_name ||= __evaluate__([:collection] || [:collection]) end
#database_name ⇒ String
Get the database name for this persistence context.
# File 'lib/mongoid/persistence_context.rb', line 105
def database_name __evaluate__(database_name_option) || client.database.name end
#database_name_option (private)
[ GitHub ]# File 'lib/mongoid/persistence_context.rb', line 247
def database_name_option @database_name_option ||= [:database] || Threaded.database_override || [:database] end
#for_child(document) ⇒ PersistenceContext
Returns a new persistence context that is consistent with the given child document, inheriting most appropriate settings.
# File 'lib/mongoid/persistence_context.rb', line 56
def for_child(document) if document.is_a?(Class) return self if document == (@object.is_a?(Class) ? @object : @object.class) elsif document.is_a?(Mongoid::Document) return self if document.class == (@object.is_a?(Class) ? @object : @object.class) else raise ArgumentError, 'must specify a class or a document instance' end PersistenceContext.new(document, .merge(document.)) end
#requested_storage_options ⇒ Hash | nil
The subset of provided options that may be used as storage options.
# File 'lib/mongoid/persistence_context.rb', line 183
def slice = @options.slice(*Mongoid::Clients::Validators::Storage::VALID_OPTIONS) slice.any? ? slice : nil end
#set_options!(opts) (private)
[ GitHub ]# File 'lib/mongoid/persistence_context.rb', line 190
def (opts) @options ||= opts.each.reduce({}) do |, (key, value)| raise Errors::InvalidPersistenceOption.new(key.to_sym, VALID_OPTIONS) unless VALID_OPTIONS.include?(key.to_sym) value ? .merge!(key => value) : end end
#verify_encryption_schema!(client) (private)
Refuse to use a client that would store a model's encrypted fields in plaintext.
The automatic encryption schema is keyed by namespace and is built once, when the client is created. The driver looks the target namespace up in that schema, and when it is absent it asks the server for a schema instead; a collection without a validator then yields no encryption at all, and no error. Checking the namespace here is what turns that silent downgrade into a failure.
# File 'lib/mongoid/persistence_context.rb', line 218
def verify_encryption_schema!(client) klass = @object.is_a?(Class) ? @object : @object.class # A model whose encrypted fields all live on embedded models declares no # encryption of its own, and still needs a schema for its collection. return unless klass.respond_to?(:requires_encryption_schema?) && klass.requires_encryption_schema? # An embedded document is persisted as part of its parent, so the # parent's context is what governs the namespace. return if klass. # Collection and index management sends no document data, so it does not # need an encryption-capable client. return if Threaded.managing_collection? schema_map = client..dig(:, :schema_map) namespace = "#{client.database.name}.#{collection_name}" return if schema_map&.key?(namespace) raise Errors::NoEncryptionSchema.new(klass, namespace, client_name) end