Module: Mongoid::Threaded

Extended by:
Threaded
Included in:
Threaded
Defined in:
lib/mongoid/threaded.rb,
lib/mongoid/threaded/lifecycle.rb

Overview

This module contains logic for easy access to objects that have a lifecycle on the current thread.

Defined Under Namespace

Modules: Lifecycle

Constant Summary collapse

DATABASE_OVERRIDE_KEY =
'[mongoid]:db-override'
CLIENTS_KEY =

Constant for the key to store clients.

'[mongoid]:clients'
CLIENT_OVERRIDE_KEY =

The key to override the client.

'[mongoid]:client-override'
CURRENT_SCOPE_KEY =

The key for the current thread’s scope stack.

'[mongoid]:current-scope'
AUTOSAVES_KEY =
'[mongoid]:autosaves'
VALIDATIONS_KEY =
'[mongoid]:validations'
STACK_KEYS =
Hash.new do |hash, key| hash[key] = "[mongoid]:#{key}-stack" end
SESSIONS_KEY =

The key for the current thread’s sessions.

'[mongoid]:sessions'
MODIFIED_DOCUMENTS_KEY =

The key for storing documents modified inside transactions.

'[mongoid]:modified-documents'
EXECUTE_CALLBACKS =

The key storing the default value for whether or not callbacks are executed on documents.

'[mongoid]:execute-callbacks'
BIND =
'bind'.freeze
ASSIGN =
'assign'.freeze
BUILD =
'build'.freeze
LOAD =
'load'.freeze
CREATE =
'create'.freeze

Instance Method Summary collapse

Instance Method Details

#add_modified_document(session, document) ⇒ Object

Store a reference to the document that was modified inside a transaction associated with the session.

Parameters:

  • session (Mongo::Session)

    Session in scope of which the document was modified.

  • document (Mongoid::Document)

    Mongoid document that was modified.

 435 436 437 438 439
# File 'lib/mongoid/threaded.rb', line 435 def add_modified_document(session, document) return unless session&.in_transaction? modified_documents[session] << document end

#autosaved?(document) ⇒ true | false

Is the document autosaved on the current thread?

Examples:

Is the document autosaved?

Threaded.autosaved?(doc)

Parameters:

  • document (Document)

    The document to check.

Returns:

  • (true | false)

    If the document is autosaved.

 334 335 336
# File 'lib/mongoid/threaded.rb', line 334 def autosaved?(document) autosaves_for(document.class).include?(document._id) end

#autosavesHash

Get all autosaves on the current thread.

Examples:

Get all autosaves.

Threaded.autosaves

Returns:

  • (Hash)

    The current autosaves.

 356 357 358
# File 'lib/mongoid/threaded.rb', line 356 def autosaves get(AUTOSAVES_KEY) { {} } end

#autosaves_for(klass) ⇒ Array

Get all autosaves on the current thread for the class.

Examples:

Get all autosaves.

Threaded.autosaves_for(Person)

Parameters:

  • klass (Class)

    The class to check.

Returns:

  • (Array)

    The current autosaves.

 378 379 380
# File 'lib/mongoid/threaded.rb', line 378 def autosaves_for(klass) autosaves[klass] ||= [] end

#begin_autosave(document) ⇒ Object

Begin autosaving a document on the current thread.

Examples:

Begin autosave.

Threaded.begin_autosave(doc)

Parameters:

  • document (Document)

    The document to autosave.

 185 186 187
# File 'lib/mongoid/threaded.rb', line 185 def begin_autosave(document) autosaves_for(document.class).push(document._id) end

#begin_execution(name) ⇒ true

Begin entry into a named thread local stack.

Examples:

Begin entry into the stack.

Threaded.begin_execution(:create)

Parameters:

  • name (String)

    The name of the stack

Returns:

  • (true)

    True.

 117 118 119
# File 'lib/mongoid/threaded.rb', line 117 def begin_execution(name) stack(name).push(true) end

#begin_validate(document) ⇒ Object

Begin validating a document on the current thread.

Examples:

Begin validation.

Threaded.begin_validate(doc)

Parameters:

  • document (Document)

    The document to validate.

 195 196 197
# File 'lib/mongoid/threaded.rb', line 195 def begin_validate(document) validations_for(document.class).push(document._id) end

#begin_without_default_scope(klass) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Begin suppressing default scopes for given model on the current thread.

Examples:

Begin without default scope stack.

Threaded.begin_without_default_scope(klass)

Parameters:

  • klass (Class)

    The model to suppress default scoping on.

 227 228 229
# File 'lib/mongoid/threaded.rb', line 227 def begin_without_default_scope(klass) stack(:without_default_scope).push(klass) end

#clear_modified_documents(session) ⇒ Set<Mongoid::Document>

Clears the set of modified documents for the given session, and return the content of the set before the clearance.

Parameters:

  • session (Mongo::Session)

    Session for which the modified documents set should be cleared.

Returns:

  • (Set<Mongoid::Document>)

    Collection of modified documents before it was cleared.

 448 449 450
# File 'lib/mongoid/threaded.rb', line 448 def clear_modified_documents(session) modified_documents.delete(session) || [] end

#clear_session(client: nil) ⇒ nil

Note:

For backward compatibility it is allowed to call this method without

Clear the cached session for this thread for a client.

specifying ‘client` parameter.

Parameters:

  • client (Mongo::Client | nil) (defaults to: nil)

    The client to clear the session for.

Returns:

  • (nil)
 425 426 427
# File 'lib/mongoid/threaded.rb', line 425 def clear_session(client: nil) sessions.delete(client)&.end_session end

#client_overrideString | Symbol

Get the global client override.

Examples:

Get the global client override.

Threaded.client_override

Returns:

  • (String | Symbol)

    The override.

 249 250 251
# File 'lib/mongoid/threaded.rb', line 249 def client_override get(CLIENT_OVERRIDE_KEY) end

#client_override=(name) ⇒ String | Symbol

Set the global client override.

Examples:

Set the global client override.

Threaded.client_override = :testing

Parameters:

  • name (String | Symbol)

    The global override name.

Returns:

  • (String | Symbol)

    The override.

 261 262 263
# File 'lib/mongoid/threaded.rb', line 261 def client_override=(name) set(CLIENT_OVERRIDE_KEY, name) end

#current_scope(klass = nil) ⇒ Criteria

Get the current Mongoid scope.

Examples:

Get the scope.

Threaded.current_scope(klass) Threaded.current_scope

Parameters:

  • klass (Klass) (defaults to: nil)

    The class type of the scope.

Returns:

 274 275 276 277 278 279 280 281 282
# File 'lib/mongoid/threaded.rb', line 274 def current_scope(klass = nil) current_scope = get(CURRENT_SCOPE_KEY) if klass && current_scope.respond_to?(:keys) current_scope[current_scope.keys.find { |k| k <= klass }] else current_scope end end

#current_scope=(scope) ⇒ Criteria

Set the current Mongoid scope.

Examples:

Set the scope.

Threaded.current_scope = scope

Parameters:

  • scope (Criteria)

    The current scope.

Returns:

 292 293 294
# File 'lib/mongoid/threaded.rb', line 292 def current_scope=(scope) set(CURRENT_SCOPE_KEY, scope) end

#database_overrideString | Symbol

Get the global database override.

Examples:

Get the global database override.

Threaded.database_override

Returns:

  • (String | Symbol)

    The override.

 127 128 129
# File 'lib/mongoid/threaded.rb', line 127 def database_override get(DATABASE_OVERRIDE_KEY) end

#database_override=(name) ⇒ String | Symbol

Set the global database override.

Examples:

Set the global database override.

Threaded.database_override = :testing

Parameters:

  • name (String | Symbol)

    The global override name.

Returns:

  • (String | Symbol)

    The override.

 139 140 141
# File 'lib/mongoid/threaded.rb', line 139 def database_override=(name) set(DATABASE_OVERRIDE_KEY, name) end

#delete(key) ⇒ Object

Removes the named variable from thread-local storage.

Parameters:

  • key (String | Symbol)

    the name of the variable to remove.

 84 85 86
# File 'lib/mongoid/threaded.rb', line 84 def delete(key) set(key, nil) end

#execute_callbacks=(flag) ⇒ Object

Indicates whether document callbacks should be invoked by default for the current thread. Individual documents may further override the callback behavior, but this will be used for the default behavior.

Parameters:

  • flag (true | false)

    Whether or not document callbacks should be executed by default.

 474 475 476
# File 'lib/mongoid/threaded.rb', line 474 def execute_callbacks=(flag) set(EXECUTE_CALLBACKS, flag) end

#execute_callbacks?true | false

Queries whether document callbacks should be executed by default for the current thread.

Unless otherwise indicated (by #execute_callbacks=), this will return true.

Returns:

  • (true | false)

    Whether or not document callbacks should be executed by default.

 460 461 462 463 464 465 466
# File 'lib/mongoid/threaded.rb', line 460 def execute_callbacks? if has?(EXECUTE_CALLBACKS) get(EXECUTE_CALLBACKS) else true end end

#executing?(name) ⇒ true

Are in the middle of executing the named stack

Examples:

Are we in the stack execution?

Threaded.executing?(:create)

Parameters:

  • name (Symbol)

    The name of the stack

Returns:

  • (true)

    If the stack is being executed.

 151 152 153
# File 'lib/mongoid/threaded.rb', line 151 def executing?(name) !stack(name).empty? end

#exit_autosave(document) ⇒ Object

Exit autosaving a document on the current thread.

Examples:

Exit autosave.

Threaded.exit_autosave(doc)

Parameters:

  • document (Document)

    The document to autosave.

 205 206 207
# File 'lib/mongoid/threaded.rb', line 205 def exit_autosave(document) autosaves_for(document.class).delete_one(document._id) end

#exit_execution(name) ⇒ true

Exit from a named thread local stack.

Examples:

Exit from the stack.

Threaded.exit_execution(:create)

Parameters:

  • name (Symbol)

    The name of the stack

Returns:

  • (true)

    True.

 163 164 165
# File 'lib/mongoid/threaded.rb', line 163 def exit_execution(name) stack(name).pop end

#exit_validate(document) ⇒ Object

Exit validating a document on the current thread.

Examples:

Exit validation.

Threaded.exit_validate(doc)

Parameters:

  • document (Document)

    The document to validate.

 215 216 217
# File 'lib/mongoid/threaded.rb', line 215 def exit_validate(document) validations_for(document.class).delete_one(document._id) end

#exit_without_default_scope(klass) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Exit suppressing default scopes for given model on the current thread.

Examples:

Exit without default scope stack.

Threaded.exit_without_default_scope(klass)

Parameters:

  • klass (Class)

    The model to unsuppress default scoping on.

 239 240 241
# File 'lib/mongoid/threaded.rb', line 239 def exit_without_default_scope(klass) stack(:without_default_scope).delete(klass) end

#get(key, &default) ⇒ Object | nil

Queries the thread-local variable with the given name. If a block is given, and the variable does not already exist, the return value of the block will be set as the value of the variable before returning it.

It is very important that applications (and especially Mongoid) use this method instead of Thread#[], since Thread#[] is actually for fiber-local variables, and Mongoid uses Fibers as an implementation detail in some callbacks. Putting thread-local state in a fiber-local store will result in the state being invisible when relevant callbacks are run in a different fiber.

Affected callbacks are cascading callbacks on embedded children.

Parameters:

  • key (String | Symbol)

    the name of the variable to query

  • default (Proc)

    an optional block that must return the default (initial) value of this variable.

Returns:

  • (Object | nil)

    the value of the queried variable, or nil if it is not set and no default was given.

 59 60 61 62 63 64 65 66 67 68
# File 'lib/mongoid/threaded.rb', line 59 def get(key, &default) result = Thread.current.thread_variable_get(key) if result.nil? && default result = yield set(key, result) end result end

#get_session(client: nil) ⇒ Mongo::Session | nil

Note:

For backward compatibility it is allowed to call this method without

Get the cached session for this thread for a client.

specifying ‘client` parameter.

Parameters:

  • client (Mongo::Client | nil) (defaults to: nil)

    The client to cache the session for.

Returns:

  • (Mongo::Session | nil)

    The session cached on this thread or nil.

 413 414 415
# File 'lib/mongoid/threaded.rb', line 413 def get_session(client: nil) sessions[client] end

#has?(key) ⇒ true | false

Queries the presence of a named variable in thread-local storage.

Parameters:

  • key (String | Symbol)

    the name of the variable to query.

Returns:

  • (true | false)

    whether the given variable is present or not.

 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
# File 'lib/mongoid/threaded.rb', line 93 def has?(key) # Here we have a classic example of JRuby not behaving like MRI. In  # MRI, if you set a thread variable to nil, it removes it from the list  # and subsequent calls to thread_variable?(key) will return false. Not  # so with JRuby. Once set, you cannot unset the thread variable.  #  # However, because setting a variable to nil is supposed to remove it,  # we can assume a nil-valued variable doesn't actually exist.  # So, instead of this:  # Thread.current.thread_variable?(key)  # We have to do this:  !get(key).nil? end

#modified_documentsHash<Mongo::Session, Set<Mongoid::Document>>

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns the thread store of modified documents.

Returns:

  • (Hash<Mongo::Session, Set<Mongoid::Document>>)

    The modified documents indexed by session.

 493 494 495
# File 'lib/mongoid/threaded.rb', line 493 def modified_documents get(MODIFIED_DOCUMENTS_KEY) { Hash.new { |h, k| h[k] = Set.new } } end

#sessionsHash<Integer, Set>

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns the thread store of sessions.

Returns:

  • (Hash<Integer, Set>)

    The sessions indexed by client object ID.

 483 484 485
# File 'lib/mongoid/threaded.rb', line 483 def sessions get(SESSIONS_KEY) { {}.compare_by_identity } end

#set(key, value) ⇒ Object

Sets a thread-local variable with the given name to the given value. See #get for a discussion of why this method is necessary, and why Thread#[]= should be avoided in cascading callbacks on embedded children.

Parameters:

  • key (String | Symbol)

    the name of the variable to set.

  • value (Object | nil)

    the value of the variable to set (or ‘nil` if you wish to unset the variable)

 77 78 79
# File 'lib/mongoid/threaded.rb', line 77 def set(key, value) Thread.current.thread_variable_set(key, value) end

#set_current_scope(scope, klass) ⇒ Criteria

Set the current Mongoid scope. Safe for multi-model scope chaining.

Examples:

Set the scope.

Threaded.current_scope(scope, klass)

Parameters:

  • scope (Criteria)

    The current scope.

  • klass (Class)

    The current model class.

Returns:

 305 306 307 308 309 310 311 312
# File 'lib/mongoid/threaded.rb', line 305 def set_current_scope(scope, klass) if scope.nil? unset_current_scope(klass) else current_scope = get(CURRENT_SCOPE_KEY) { {} } current_scope[klass] = scope end end

#set_session(session, client: nil) ⇒ Object

Note:

For backward compatibility it is allowed to call this method without

Cache a session for this thread for a client.

specifying ‘client` parameter.

Parameters:

  • session (Mongo::Session)

    The session to save.

  • client (Mongo::Client | nil) (defaults to: nil)

    The client to cache the session for.

 401 402 403
# File 'lib/mongoid/threaded.rb', line 401 def set_session(session, client: nil) sessions[client] = session end

#stack(name) ⇒ Array

Get the named stack.

Examples:

Get a stack by name

Threaded.stack(:create)

Parameters:

  • name (Symbol)

    The name of the stack

Returns:

  • (Array)

    The stack.

 175 176 177
# File 'lib/mongoid/threaded.rb', line 175 def stack(name) get(STACK_KEYS[name]) { [] } end

#validated?(document) ⇒ true | false

Is the document validated on the current thread?

Examples:

Is the document validated?

Threaded.validated?(doc)

Parameters:

  • document (Document)

    The document to check.

Returns:

  • (true | false)

    If the document is validated.

 346 347 348
# File 'lib/mongoid/threaded.rb', line 346 def validated?(document) validations_for(document.class).include?(document._id) end

#validationsHash

Get all validations on the current thread.

Examples:

Get all validations.

Threaded.validations

Returns:

  • (Hash)

    The current validations.

 366 367 368
# File 'lib/mongoid/threaded.rb', line 366 def validations get(VALIDATIONS_KEY) { {} } end

#validations_for(klass) ⇒ Array

Get all validations on the current thread for the class.

Examples:

Get all validations.

Threaded.validations_for(Person)

Parameters:

  • klass (Class)

    The class to check.

Returns:

  • (Array)

    The current validations.

 390 391 392
# File 'lib/mongoid/threaded.rb', line 390 def validations_for(klass) validations[klass] ||= [] end

#without_default_scope?(klass) ⇒ Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Is the given klass’ default scope suppressed on the current thread?

Examples:

Is the given klass’ default scope suppressed?

Threaded.without_default_scope?(klass)

Parameters:

  • klass (Class)

    The model to check for default scope suppression.

Returns:

 322 323 324
# File 'lib/mongoid/threaded.rb', line 322 def without_default_scope?(klass) stack(:without_default_scope).include?(klass) end