mongoid_includes 1.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +17 -0
- data/LICENSE.txt +20 -0
- data/README.md +49 -0
- data/Rakefile +31 -0
- data/lib/config/locales/en.yml +19 -0
- data/lib/mongoid/includes.rb +4 -0
- data/lib/mongoid/includes/criteria.rb +67 -0
- data/lib/mongoid/includes/eager_load.rb +50 -0
- data/lib/mongoid/includes/errors.rb +2 -0
- data/lib/mongoid/includes/errors/invalid_includes.rb +30 -0
- data/lib/mongoid/includes/errors/invalid_polymorphic_includes.rb +16 -0
- data/lib/mongoid/includes/inclusion.rb +64 -0
- data/lib/mongoid/includes/inclusions.rb +40 -0
- data/lib/mongoid/includes/relations/eager.rb +19 -0
- data/lib/mongoid/includes/version.rb +10 -0
- data/lib/mongoid_includes.rb +12 -0
- data/spec/mongoid/includes/criteria_spec.rb +25 -0
- data/spec/mongoid/includes/errors/invalid_includes_spec.rb +29 -0
- data/spec/mongoid/includes/errors/invalid_polymorphic_includes_spec.rb +29 -0
- data/spec/mongoid/includes/inclusions_spec.rb +23 -0
- data/spec/mongoid/includes/nested_inclusions_spec.rb +52 -0
- data/spec/mongoid/includes/simple_inclusions_spec.rb +1010 -0
- data/spec/spec_helper.rb +60 -0
- data/spec/support/config/mongoid.yml +27 -0
- data/spec/support/helpers.rb +47 -0
- data/spec/support/models/address.rb +69 -0
- data/spec/support/models/album.rb +9 -0
- data/spec/support/models/artist.rb +8 -0
- data/spec/support/models/band.rb +25 -0
- data/spec/support/models/game.rb +18 -0
- data/spec/support/models/musician.rb +10 -0
- data/spec/support/models/person.rb +72 -0
- data/spec/support/models/post.rb +11 -0
- data/spec/support/models/preference.rb +11 -0
- data/spec/support/models/record.rb +50 -0
- data/spec/support/models/song.rb +7 -0
- metadata +123 -0
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
if ENV['CODECLIMATE_REPO_TOKEN']
|
2
|
+
require 'codeclimate-test-reporter'
|
3
|
+
CodeClimate::TestReporter.start
|
4
|
+
end
|
5
|
+
|
6
|
+
require 'rspec/given'
|
7
|
+
require 'pry'
|
8
|
+
require 'mongoid_includes'
|
9
|
+
|
10
|
+
# Load Support files
|
11
|
+
Dir['./spec/support/**/*.rb'].map do |f|
|
12
|
+
require f
|
13
|
+
end
|
14
|
+
|
15
|
+
def mongodb_version
|
16
|
+
session = Mongoid::Sessions.default
|
17
|
+
session.command(buildinfo: 1)[version]
|
18
|
+
end
|
19
|
+
|
20
|
+
I18n.config.enforce_available_locales = false
|
21
|
+
|
22
|
+
# These are used when creating any connection in the test suite.
|
23
|
+
HOST = ENV['MONGOID_SPEC_HOST'] ||= 'localhost'
|
24
|
+
PORT = ENV['MONGOID_SPEC_PORT'] ||= '27017'
|
25
|
+
DATABASE = ENV['MONGOID_DATABASE'] ||= 'mongoid_test'
|
26
|
+
|
27
|
+
# Set the database that the spec suite connects to.
|
28
|
+
Mongoid.configure do |config|
|
29
|
+
config.load_configuration(
|
30
|
+
clients: {
|
31
|
+
default: {
|
32
|
+
database: DATABASE,
|
33
|
+
hosts: [ "#{HOST}:#{PORT.to_i}" ],
|
34
|
+
options: {
|
35
|
+
max_pool_size: 1,
|
36
|
+
}
|
37
|
+
}
|
38
|
+
},
|
39
|
+
sessions: {
|
40
|
+
default: {
|
41
|
+
database: DATABASE,
|
42
|
+
hosts: [ "#{HOST}:#{PORT.to_i}" ]
|
43
|
+
}
|
44
|
+
}
|
45
|
+
)
|
46
|
+
end
|
47
|
+
|
48
|
+
if defined?(Mongo)
|
49
|
+
Mongo::Logger.logger = Logger.new("./spec/mongo.log")
|
50
|
+
end
|
51
|
+
|
52
|
+
RSpec.configure do |config|
|
53
|
+
config.include Mongoid::SpecHelpers
|
54
|
+
config.raise_errors_for_deprecations!
|
55
|
+
|
56
|
+
# Drop all collections and clear the identity map before each spec.
|
57
|
+
config.before(:each) do
|
58
|
+
Mongoid.purge!
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
test:
|
2
|
+
clients:
|
3
|
+
default:
|
4
|
+
database: mongoid_test
|
5
|
+
hosts:
|
6
|
+
- <%=ENV["MONGOID_SPEC_HOST"]%>:<%=ENV["MONGOID_SPEC_PORT"]%>
|
7
|
+
options:
|
8
|
+
read:
|
9
|
+
mode: :primary
|
10
|
+
max_pool_size: 1
|
11
|
+
|
12
|
+
sessions:
|
13
|
+
default:
|
14
|
+
database: mongoid_test
|
15
|
+
hosts:
|
16
|
+
- <%=ENV["MONGOID_SPEC_HOST"]%>:<%=ENV["MONGOID_SPEC_PORT"]%>
|
17
|
+
options:
|
18
|
+
read: primary
|
19
|
+
|
20
|
+
options:
|
21
|
+
include_root_in_json: false
|
22
|
+
include_type_for_serialization: false
|
23
|
+
preload_models: false
|
24
|
+
scope_overwrite_exception: false
|
25
|
+
raise_not_found_error: true
|
26
|
+
use_activesupport_time_zone: true
|
27
|
+
use_utc: false
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Mongoid
|
2
|
+
class QueryCounter
|
3
|
+
attr_reader :events
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@events = []
|
7
|
+
end
|
8
|
+
|
9
|
+
def instrument
|
10
|
+
subscriber = ActiveSupport::Notifications.subscribe('query.moped') do |*args|
|
11
|
+
@events << ActiveSupport::Notifications::Event.new(*args)
|
12
|
+
end
|
13
|
+
yield
|
14
|
+
ensure
|
15
|
+
ActiveSupport::Notifications.unsubscribe(subscriber)
|
16
|
+
end
|
17
|
+
|
18
|
+
def inspect
|
19
|
+
@events.map { |e| e.payload[:ops].map(&:log_inspect) }.join("\n")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
module Mongoid
|
25
|
+
module SpecHelpers
|
26
|
+
if defined?(Mongo::Logger.logger)
|
27
|
+
def expect_query(number)
|
28
|
+
# There are both start and complete events for each query.
|
29
|
+
expect(Mongo::Logger.logger).to receive(:debug?).exactly(number * 4).times.and_call_original
|
30
|
+
yield
|
31
|
+
end
|
32
|
+
else
|
33
|
+
def expect_query(number, &block)
|
34
|
+
query_counter = Mongoid::QueryCounter.new
|
35
|
+
query_counter.instrument(&block)
|
36
|
+
expect(query_counter.events.size).to(eq(number), %[
|
37
|
+
Expected to receive #{number} queries, it received #{query_counter.events.size}
|
38
|
+
#{query_counter.inspect}
|
39
|
+
])
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def expect_no_queries(&block)
|
44
|
+
expect_query(0, &block)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
class Address
|
2
|
+
include Mongoid::Document
|
3
|
+
|
4
|
+
field :_id, type: String, overwrite: true, default: ->{ street.try(:parameterize) }
|
5
|
+
|
6
|
+
attr_accessor :mode
|
7
|
+
|
8
|
+
field :address_type
|
9
|
+
field :number, type: Integer
|
10
|
+
field :no, type: Integer
|
11
|
+
field :h, as: :house, type: Integer
|
12
|
+
field :street
|
13
|
+
field :city
|
14
|
+
field :state
|
15
|
+
field :post_code
|
16
|
+
field :parent_title
|
17
|
+
field :services, type: Array
|
18
|
+
field :aliases, as: :a, type: Array
|
19
|
+
field :test, type: Array
|
20
|
+
field :latlng, type: Array
|
21
|
+
field :map, type: Hash
|
22
|
+
field :move_in, type: DateTime
|
23
|
+
field :end_date, type: Date
|
24
|
+
field :s, type: String, as: :suite
|
25
|
+
field :name, localize: true
|
26
|
+
|
27
|
+
belongs_to :band
|
28
|
+
|
29
|
+
embedded_in :addressable, polymorphic: true do
|
30
|
+
def extension
|
31
|
+
"Testing"
|
32
|
+
end
|
33
|
+
def doctor?
|
34
|
+
title == "Dr"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
scope :without_postcode, ->{ where(postcode: nil) }
|
39
|
+
scope :rodeo, ->{ where(street: "Rodeo Dr") } do
|
40
|
+
def mansion?
|
41
|
+
all? { |address| address.street == "Rodeo Dr" }
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
validates_presence_of :street, on: :update
|
46
|
+
validates_format_of :street, with: /\D/, allow_nil: true
|
47
|
+
|
48
|
+
def set_parent=(set = false)
|
49
|
+
self.parent_title = addressable.title if set
|
50
|
+
end
|
51
|
+
|
52
|
+
def <=>(other)
|
53
|
+
street <=> other.street
|
54
|
+
end
|
55
|
+
|
56
|
+
class << self
|
57
|
+
def california
|
58
|
+
where(state: "CA")
|
59
|
+
end
|
60
|
+
|
61
|
+
def homes
|
62
|
+
where(address_type: "Home")
|
63
|
+
end
|
64
|
+
|
65
|
+
def streets
|
66
|
+
all.map(&:street)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class Band
|
2
|
+
include Mongoid::Document
|
3
|
+
include Mongoid::Attributes::Dynamic
|
4
|
+
|
5
|
+
field :name, type: String
|
6
|
+
field :active, type: Mongoid::Boolean, default: true
|
7
|
+
field :origin, type: String
|
8
|
+
field :genres, type: Array
|
9
|
+
field :member_count, type: Integer
|
10
|
+
field :mems, as: :members, type: Array
|
11
|
+
field :likes, type: Integer
|
12
|
+
field :views, type: Integer
|
13
|
+
field :rating, type: Float
|
14
|
+
field :upserted, type: Mongoid::Boolean, default: false
|
15
|
+
field :created, type: DateTime
|
16
|
+
field :sales, type: BigDecimal
|
17
|
+
field :y, as: :years, type: Integer
|
18
|
+
field :founded, type: Date
|
19
|
+
|
20
|
+
|
21
|
+
has_many :albums, as: :owner
|
22
|
+
has_and_belongs_to_many :musicians
|
23
|
+
|
24
|
+
embeds_many :records, cascade_callbacks: true
|
25
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class Game
|
2
|
+
include Mongoid::Document
|
3
|
+
|
4
|
+
field :high_score, type: Integer, default: 500
|
5
|
+
field :score, type: Integer, default: 0
|
6
|
+
field :name
|
7
|
+
|
8
|
+
belongs_to :person, index: true, validate: true
|
9
|
+
belongs_to :parent, class_name: "Game", foreign_key: "parent-id"
|
10
|
+
|
11
|
+
accepts_nested_attributes_for :person
|
12
|
+
|
13
|
+
validates_format_of :name, without: /\$\$\$/
|
14
|
+
|
15
|
+
set_callback(:initialize, :after) do |document|
|
16
|
+
write_attribute("name", "Testing") unless name
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
class Person
|
2
|
+
include Mongoid::Document
|
3
|
+
include Mongoid::Attributes::Dynamic
|
4
|
+
attr_accessor :mode
|
5
|
+
|
6
|
+
class_attribute :somebody_elses_important_class_options
|
7
|
+
self.somebody_elses_important_class_options = { keep_me_around: true }
|
8
|
+
|
9
|
+
field :username, default: -> { "arthurnn#{rand(0..10)}" }
|
10
|
+
field :title
|
11
|
+
field :terms, type: Mongoid::Boolean
|
12
|
+
field :pets, type: Mongoid::Boolean, default: false
|
13
|
+
field :age, type: Integer, default: "100"
|
14
|
+
field :dob, type: Date
|
15
|
+
field :employer_id
|
16
|
+
field :lunch_time, type: Time
|
17
|
+
field :aliases, type: Array
|
18
|
+
field :map, type: Hash
|
19
|
+
field :map_with_default, type: Hash, default: {}
|
20
|
+
field :score, type: Integer
|
21
|
+
field :blood_alcohol_content, type: Float, default: ->{ 0.0 }
|
22
|
+
field :last_drink_taken_at, type: Date, default: ->{ 1.day.ago.in_time_zone("Alaska") }
|
23
|
+
field :ssn
|
24
|
+
field :owner_id, type: Integer
|
25
|
+
field :security_code
|
26
|
+
field :reading, type: Object
|
27
|
+
field :bson_id, type: BSON::ObjectId
|
28
|
+
field :pattern, type: Regexp
|
29
|
+
field :override_me, type: Integer
|
30
|
+
field :at, as: :aliased_timestamp, type: Time
|
31
|
+
field :t, as: :test, type: String
|
32
|
+
field :i, as: :inte, type: Integer
|
33
|
+
field :a, as: :array, type: Array
|
34
|
+
field :desc, localize: true
|
35
|
+
field :test_array, type: Array
|
36
|
+
field :overridden_setter, type: String
|
37
|
+
field :arrays, type: Array
|
38
|
+
field :range, type: Range
|
39
|
+
|
40
|
+
index age: 1
|
41
|
+
index addresses: 1
|
42
|
+
index dob: 1
|
43
|
+
index name: 1
|
44
|
+
index title: 1
|
45
|
+
|
46
|
+
index({ ssn: 1 }, { unique: true })
|
47
|
+
|
48
|
+
attr_reader :rescored
|
49
|
+
|
50
|
+
embeds_many :addresses, as: :addressable, validate: false do
|
51
|
+
def extension
|
52
|
+
"Testing"
|
53
|
+
end
|
54
|
+
def find_by_street(street)
|
55
|
+
where(street: street).first
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
has_one :game, dependent: :destroy, validate: false do
|
60
|
+
def extension
|
61
|
+
"Testing"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
has_many :posts, dependent: :delete, validate: false do
|
66
|
+
def extension
|
67
|
+
"Testing"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
has_and_belongs_to_many :preferences, index: true, dependent: :nullify, validate: false
|
72
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class Post
|
2
|
+
include Mongoid::Document
|
3
|
+
include Mongoid::Attributes::Dynamic
|
4
|
+
|
5
|
+
field :title, type: String
|
6
|
+
field :content, type: String
|
7
|
+
field :rating, type: Integer
|
8
|
+
field :person_title, type: String, default: ->{ person.title if ivar(:person) }
|
9
|
+
|
10
|
+
belongs_to :person, counter_cache: true
|
11
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class Preference
|
2
|
+
include Mongoid::Document
|
3
|
+
|
4
|
+
field :name, type: String
|
5
|
+
field :value, type: String
|
6
|
+
field :ranking, type: Integer
|
7
|
+
|
8
|
+
has_and_belongs_to_many :people, validate: false
|
9
|
+
validates_length_of :name, minimum: 2, allow_nil: true
|
10
|
+
scope :posting, ->{ where(:value.in => [ "Posting" ]) }
|
11
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
class Record
|
2
|
+
include Mongoid::Document
|
3
|
+
|
4
|
+
field :name, type: String
|
5
|
+
|
6
|
+
field :before_create_called, type: Mongoid::Boolean, default: false
|
7
|
+
field :before_save_called, type: Mongoid::Boolean, default: false
|
8
|
+
field :before_update_called, type: Mongoid::Boolean, default: false
|
9
|
+
field :before_validation_called, type: Mongoid::Boolean, default: false
|
10
|
+
field :before_destroy_called, type: Mongoid::Boolean, default: false
|
11
|
+
|
12
|
+
embedded_in :band
|
13
|
+
|
14
|
+
before_create :before_create_stub
|
15
|
+
before_save :before_save_stub
|
16
|
+
before_update :before_update_stub
|
17
|
+
before_validation :before_validation_stub
|
18
|
+
before_destroy :before_destroy_stub
|
19
|
+
|
20
|
+
after_destroy :access_band
|
21
|
+
|
22
|
+
def before_create_stub
|
23
|
+
self.before_create_called = true
|
24
|
+
end
|
25
|
+
|
26
|
+
def before_save_stub
|
27
|
+
self.before_save_called = true
|
28
|
+
end
|
29
|
+
|
30
|
+
def before_update_stub
|
31
|
+
self.before_update_called = true
|
32
|
+
end
|
33
|
+
|
34
|
+
def before_validation_stub
|
35
|
+
self.before_validation_called = true
|
36
|
+
end
|
37
|
+
|
38
|
+
def before_destroy_stub
|
39
|
+
self.before_destroy_called = true
|
40
|
+
end
|
41
|
+
|
42
|
+
def access_band
|
43
|
+
band.name
|
44
|
+
end
|
45
|
+
|
46
|
+
def dont_call_me_twice
|
47
|
+
end
|
48
|
+
|
49
|
+
validate { dont_call_me_twice }
|
50
|
+
end
|