Skip to content

Commit

Permalink
Merge remote-tracking branch 'remotes/origin/master' into docs-full-n…
Browse files Browse the repository at this point in the history
…amespaces
  • Loading branch information
johnnyshields committed Mar 5, 2023
2 parents 1eaabc2 + 9892a68 commit 009e104
Show file tree
Hide file tree
Showing 27 changed files with 863 additions and 246 deletions.
25 changes: 12 additions & 13 deletions .evergreen/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -763,16 +763,15 @@ buildvariants:
tasks:
- name: "test"

# https://jira.mongodb.org/browse/MONGOID-5549
# - matrix_name: app-tests-jruby
# matrix_spec:
# jruby: ["jruby-9.3"]
# driver: ["current"]
# mongodb-version: '5.0'
# topology: standalone
# app-tests: yes
# rails: ['6.0']
# os: ubuntu-18.04
# display_name: "app tests ${driver}, ${jruby}"
# tasks:
# - name: "test"
- matrix_name: app-tests-jruby
matrix_spec:
jruby: ["jruby-9.3"]
driver: ["current"]
mongodb-version: '5.0'
topology: standalone
app-tests: yes
rails: ['6.0']
os: ubuntu-18.04
display_name: "app tests ${driver}, ${jruby}"
tasks:
- name: "test"
6 changes: 2 additions & 4 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,6 @@ jobs:
i18n:
gemfile: gemfiles/rails-6.0.gemfile
experimental: false

- mongodb: '5.0'
ruby: ruby-3.1
topology: replica_set
Expand All @@ -162,7 +161,7 @@ jobs:
- mongodb: '4.0'
ruby: ruby-2.7
topology: replica_set
os: ubuntu-18.04
os: ubuntu-20.04
task: test
driver: current
rails:
Expand All @@ -172,15 +171,14 @@ jobs:
- mongodb: '3.6'
ruby: ruby-2.7
topology: replica_set
os: ubuntu-18.04
os: ubuntu-20.04
task: test
driver: current
rails:
i18n:
gemfile: Gemfile
experimental: false


steps:
- name: repo checkout
uses: actions/checkout@v2
Expand Down
19 changes: 19 additions & 0 deletions docs/reference/indexes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,25 @@ Indexes can be scoped to a specific database:
index({ ssn: 1 }, { database: "users", unique: true, background: true })
end

You may use aliased field names in index definitions. Field aliases
will also be resolved on the following options: ``partial_filter_expression``,
``weights``, ``wildcard_projection``.

.. code-block:: ruby

class Person
include Mongoid::Document
field :a, as: :age
index({ age: 1 }, { partial_filter_expression: { age: { '$gte' => 20 } })
end

.. note::

The expansion of field name aliases in index options such as
``partial_filter_expression`` is performed according to the behavior of MongoDB
server 6.0. Future server versions may change how they interpret these options,
and Mongoid's functionality may not support such changes.

Mongoid can define indexes on "foreign key" fields for associations.
This only works on the association macro that the foreign key is stored on:

Expand Down
23 changes: 23 additions & 0 deletions docs/release-notes/mongoid-9.0.txt
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,29 @@ defaults to ``true``.
When set to false, the older, inconsistent behavior is restored.


Support Field Aliases on Index Options
--------------------------------------

Support has been added to use aliased field names in the following options
of the ``index`` macro: ``partial_filter_expression``, ``weights``,
``wildcard_projection``.

.. code-block:: ruby

class Person
include Mongoid::Document
field :a, as: :age
index({ age: 1 }, { partial_filter_expression: { age: { '$gte' => 20 } })
end

.. note::

The expansion of field name aliases in index options such as
``partial_filter_expression`` is performed according to the behavior of MongoDB
server 6.0. Future server versions may change how they interpret these options,
and Mongoid's functionality may not support such changes.


Bug Fixes and Improvements
--------------------------

Expand Down
159 changes: 159 additions & 0 deletions lib/mongoid/association/eager.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
# frozen_string_literal: true

module Mongoid
module Association

# Base class for eager load preload functions.
class Eager
# Instantiate the eager load class.
#
# @example Create the new belongs to eager load preloader.
# BelongsTo.new(association, parent_docs)
#
# @param [ Array<Mongoid::Association::Relatable> ] associations
# Associations to eager load
# @param [ Array<Document> ] docs Documents to preload the associations
#
# @return [ Base ] The eager load preloader
def initialize(associations, docs)
@associations = associations
@docs = docs
@grouped_docs = {}
end

# Run the preloader.
#
# @example Preload the associations into the documents.
# loader.run
#
# @return [ Array ] The list of documents given.
def run
@loaded = []
while shift_association
preload
@loaded << @docs.collect { |d| d.send(@association.name) if d.respond_to?(@association.name) }
end
@loaded.flatten
end

protected

# Preload the current association.
#
# This method should be implemented in the subclass
#
# @example Preload the current association into the documents.
# loader.preload
def preload
raise NotImplementedError
end

# Retrieves the documents referenced by the association, and
# yields each one sequentially to the provided block. If the
# association is not polymorphic, all documents are retrieved in
# a single query. If the association is polymorphic, one query is
# issued per association target class.
def each_loaded_document(&block)
each_loaded_document_of_class(@association.klass, keys_from_docs, &block)
end

# Retrieves the documents of the specified class, that have the
# foreign key included in the specified list of keys.
#
# When the documents are retrieved, the set of inclusions applied
# is the set of inclusions applied to the host document minus the
# association that is being eagerly loaded.
private def each_loaded_document_of_class(cls, keys)
# Note: keys should not include nil elements.
# Upstream code is responsible for eliminating nils from keys.
return cls.none if keys.empty?

criteria = cls.criteria
criteria = criteria.apply_scope(@association.scope)
criteria = criteria.any_in(key => keys)
criteria.inclusions = criteria.inclusions - [@association]
criteria.each do |doc|
yield doc
end
end

# Set the pre-loaded document into its parent.
#
# @example Set docs into parent with pk = "foo"
# loader.set_on_parent("foo", docs)
#
# @param [ ObjectId ] id parent`s id
# @param [ Document | Array ] element to push into the parent
def set_on_parent(id, element)
grouped_docs[id].each do |d|
set_relation(d, element)
end
end

# Return a hash with the current documents grouped by key.
#
# Documents that do not have a value for the association being loaded
# are not returned.
#
# @example Return a hash with the current documents grouped by key.
# loader.grouped_docs
#
# @return [ Hash ] hash with grouped documents.
def grouped_docs
@grouped_docs[@association.name] ||= @docs.group_by do |doc|
doc.send(group_by_key) if doc.respond_to?(group_by_key)
end.reject do |k, v|
k.nil?
end
end

# Group the documents and return the keys.
#
# This method omits nil keys (i.e. keys from documents that do not
# have a value for the association being loaded).
#
# @example
# loader.keys_from_docs
#
# @return [ Array ] keys, ids
def keys_from_docs
grouped_docs.keys
end

# Return the key to group the current documents.
#
# This method should be implemented in the subclass
#
# @example Return the key for group
# loader.group_by_key
#
# @return [ Symbol ] Key to group by the current documents.
def group_by_key
raise NotImplementedError
end

# Set the pre-loaded document into its parent.
#
# @example Set docs into parent using the current association name.
# loader.set_relation(doc, docs)
#
# @param [ Document ] doc The object to set the association on
# @param [ Document | Array ] element to set into the parent
def set_relation(doc, element)
doc.set_relation(@association.name, element) unless doc.blank?
end

private

# Shift the current association metadata
#
# @example Shift the current association.
# loader.shift_association
#
# @return [ Mongoid::Association::Relatable ] The association object.
def shift_association
@association = @associations.shift
end
end
end
end
2 changes: 1 addition & 1 deletion lib/mongoid/association/eager_loadable.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true

require "mongoid/association/referenced/eager"
require "mongoid/association/eager"

module Mongoid
module Association
Expand Down
1 change: 1 addition & 0 deletions lib/mongoid/association/embedded.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# frozen_string_literal: true

require 'mongoid/association/embedded/cyclic'
require 'mongoid/association/embedded/eager'
require 'mongoid/association/embedded/embedded_in'
require 'mongoid/association/embedded/embeds_many'
require 'mongoid/association/embedded/embeds_one'
22 changes: 22 additions & 0 deletions lib/mongoid/association/embedded/eager.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# frozen_string_literal: true

module Mongoid
module Association
module Embedded

# Eager class for embedded associations (embedded_in, embeds_many,
# embeds_one).
class Eager < Association::Eager

private

# Embedded associations have no preload phase, since the embedded
# documents are loaded with the parent document. This method is
# implemented as a no-op to represent that.
def preload
end
end

end
end
end
12 changes: 12 additions & 0 deletions lib/mongoid/association/embedded/embedded_in/proxy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,18 @@ def persistable?
end

class << self
# Returns the eager loader for this association.
#
# @param [ Array<Mongoid::Association> ] associations The
# associations to be eager loaded
# @param [ Array<Mongoid::Document> ] docs The parent documents
# that possess the given associations, which ought to be
# populated by the eager-loaded documents.
#
# @return [ Mongoid::Association::Embedded::Eager ]
def eager_loader(associations, docs)
Eager.new(associations, docs)
end

# Returns true if the association is an embedded one. In this case
# always true.
Expand Down
12 changes: 12 additions & 0 deletions lib/mongoid/association/embedded/embeds_many/proxy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,18 @@ def update_attributes_hash
end

class << self
# Returns the eager loader for this association.
#
# @param [ Array<Mongoid::Association> ] associations The
# associations to be eager loaded
# @param [ Array<Mongoid::Document> ] docs The parent documents
# that possess the given associations, which ought to be
# populated by the eager-loaded documents.
#
# @return [ Mongoid::Association::Embedded::Eager ]
def eager_loader(associations, docs)
Eager.new(associations, docs)
end

# Returns true if the association is an embedded one. In this case
# always true.
Expand Down
12 changes: 12 additions & 0 deletions lib/mongoid/association/embedded/embeds_one/proxy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,18 @@ def update_attributes_hash(replacement)
end

class << self
# Returns the eager loader for this association.
#
# @param [ Array<Mongoid::Association> ] associations The
# associations to be eager loaded
# @param [ Array<Mongoid::Document> ] docs The parent documents
# that possess the given associations, which ought to be
# populated by the eager-loaded documents.
#
# @return [ Mongoid::Association::Embedded::Eager ]
def eager_loader(associations, docs)
Eager.new(associations, docs)
end

# Returns true if the association is an embedded one. In this case
# always true.
Expand Down
2 changes: 1 addition & 1 deletion lib/mongoid/association/referenced/belongs_to/eager.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ module Referenced
class BelongsTo

# Eager class for belongs_to associations.
class Eager < Association::Referenced::Eager::Base
class Eager < Association::Eager

private

Expand Down
Loading

0 comments on commit 009e104

Please sign in to comment.