stonegao-mongoid 2.0.0.rc.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +20 -0
- data/README.rdoc +50 -0
- data/Rakefile +51 -0
- data/lib/config/locales/bg.yml +44 -0
- data/lib/config/locales/de.yml +44 -0
- data/lib/config/locales/en.yml +45 -0
- data/lib/config/locales/es.yml +44 -0
- data/lib/config/locales/fr.yml +45 -0
- data/lib/config/locales/hu.yml +47 -0
- data/lib/config/locales/it.yml +42 -0
- data/lib/config/locales/kr.yml +68 -0
- data/lib/config/locales/nl.yml +42 -0
- data/lib/config/locales/pl.yml +42 -0
- data/lib/config/locales/pt-br.yml +43 -0
- data/lib/config/locales/pt.yml +43 -0
- data/lib/config/locales/ro.yml +49 -0
- data/lib/config/locales/sv.yml +43 -0
- data/lib/config/locales/zh-CN.yml +34 -0
- data/lib/mongoid/atomicity.rb +111 -0
- data/lib/mongoid/attributes.rb +251 -0
- data/lib/mongoid/callbacks.rb +13 -0
- data/lib/mongoid/collection.rb +137 -0
- data/lib/mongoid/collections/cyclic_iterator.rb +34 -0
- data/lib/mongoid/collections/master.rb +29 -0
- data/lib/mongoid/collections/operations.rb +42 -0
- data/lib/mongoid/collections/slaves.rb +45 -0
- data/lib/mongoid/collections.rb +70 -0
- data/lib/mongoid/components.rb +45 -0
- data/lib/mongoid/config/database.rb +167 -0
- data/lib/mongoid/config/replset_database.rb +48 -0
- data/lib/mongoid/config.rb +343 -0
- data/lib/mongoid/contexts/enumerable/sort.rb +43 -0
- data/lib/mongoid/contexts/enumerable.rb +226 -0
- data/lib/mongoid/contexts/ids.rb +25 -0
- data/lib/mongoid/contexts/mongo.rb +345 -0
- data/lib/mongoid/contexts/paging.rb +50 -0
- data/lib/mongoid/contexts.rb +21 -0
- data/lib/mongoid/copyable.rb +44 -0
- data/lib/mongoid/criteria.rb +325 -0
- data/lib/mongoid/criterion/complex.rb +34 -0
- data/lib/mongoid/criterion/creational.rb +34 -0
- data/lib/mongoid/criterion/exclusion.rb +67 -0
- data/lib/mongoid/criterion/inclusion.rb +134 -0
- data/lib/mongoid/criterion/inspection.rb +20 -0
- data/lib/mongoid/criterion/optional.rb +213 -0
- data/lib/mongoid/criterion/selector.rb +74 -0
- data/lib/mongoid/cursor.rb +81 -0
- data/lib/mongoid/default_scope.rb +28 -0
- data/lib/mongoid/dirty.rb +251 -0
- data/lib/mongoid/document.rb +256 -0
- data/lib/mongoid/errors/document_not_found.rb +29 -0
- data/lib/mongoid/errors/invalid_collection.rb +19 -0
- data/lib/mongoid/errors/invalid_database.rb +20 -0
- data/lib/mongoid/errors/invalid_field.rb +19 -0
- data/lib/mongoid/errors/invalid_options.rb +16 -0
- data/lib/mongoid/errors/invalid_type.rb +26 -0
- data/lib/mongoid/errors/mongoid_error.rb +27 -0
- data/lib/mongoid/errors/too_many_nested_attribute_records.rb +21 -0
- data/lib/mongoid/errors/unsaved_document.rb +23 -0
- data/lib/mongoid/errors/unsupported_version.rb +21 -0
- data/lib/mongoid/errors/validations.rb +24 -0
- data/lib/mongoid/errors.rb +12 -0
- data/lib/mongoid/extensions/array/conversions.rb +23 -0
- data/lib/mongoid/extensions/array/parentization.rb +13 -0
- data/lib/mongoid/extensions/big_decimal/conversions.rb +19 -0
- data/lib/mongoid/extensions/binary/conversions.rb +17 -0
- data/lib/mongoid/extensions/boolean/conversions.rb +27 -0
- data/lib/mongoid/extensions/date/conversions.rb +25 -0
- data/lib/mongoid/extensions/datetime/conversions.rb +12 -0
- data/lib/mongoid/extensions/false_class/equality.rb +13 -0
- data/lib/mongoid/extensions/float/conversions.rb +20 -0
- data/lib/mongoid/extensions/hash/conversions.rb +19 -0
- data/lib/mongoid/extensions/hash/criteria_helpers.rb +22 -0
- data/lib/mongoid/extensions/hash/scoping.rb +12 -0
- data/lib/mongoid/extensions/integer/conversions.rb +20 -0
- data/lib/mongoid/extensions/nil/collectionization.rb +12 -0
- data/lib/mongoid/extensions/object/conversions.rb +25 -0
- data/lib/mongoid/extensions/object/reflections.rb +17 -0
- data/lib/mongoid/extensions/object/yoda.rb +27 -0
- data/lib/mongoid/extensions/object_id/conversions.rb +57 -0
- data/lib/mongoid/extensions/proc/scoping.rb +12 -0
- data/lib/mongoid/extensions/set/conversions.rb +20 -0
- data/lib/mongoid/extensions/string/conversions.rb +34 -0
- data/lib/mongoid/extensions/string/inflections.rb +97 -0
- data/lib/mongoid/extensions/symbol/conversions.rb +21 -0
- data/lib/mongoid/extensions/symbol/inflections.rb +40 -0
- data/lib/mongoid/extensions/time_conversions.rb +38 -0
- data/lib/mongoid/extensions/true_class/equality.rb +13 -0
- data/lib/mongoid/extensions.rb +116 -0
- data/lib/mongoid/extras.rb +61 -0
- data/lib/mongoid/factory.rb +20 -0
- data/lib/mongoid/field.rb +95 -0
- data/lib/mongoid/fields.rb +138 -0
- data/lib/mongoid/finders.rb +173 -0
- data/lib/mongoid/hierarchy.rb +85 -0
- data/lib/mongoid/identity.rb +89 -0
- data/lib/mongoid/indexes.rb +38 -0
- data/lib/mongoid/inspection.rb +58 -0
- data/lib/mongoid/javascript/functions.yml +37 -0
- data/lib/mongoid/javascript.rb +21 -0
- data/lib/mongoid/json.rb +16 -0
- data/lib/mongoid/keys.rb +77 -0
- data/lib/mongoid/logger.rb +18 -0
- data/lib/mongoid/matchers/all.rb +11 -0
- data/lib/mongoid/matchers/default.rb +27 -0
- data/lib/mongoid/matchers/exists.rb +13 -0
- data/lib/mongoid/matchers/gt.rb +11 -0
- data/lib/mongoid/matchers/gte.rb +11 -0
- data/lib/mongoid/matchers/in.rb +11 -0
- data/lib/mongoid/matchers/lt.rb +11 -0
- data/lib/mongoid/matchers/lte.rb +11 -0
- data/lib/mongoid/matchers/ne.rb +11 -0
- data/lib/mongoid/matchers/nin.rb +11 -0
- data/lib/mongoid/matchers/size.rb +11 -0
- data/lib/mongoid/matchers.rb +55 -0
- data/lib/mongoid/modifiers/command.rb +18 -0
- data/lib/mongoid/modifiers/inc.rb +24 -0
- data/lib/mongoid/modifiers.rb +24 -0
- data/lib/mongoid/multi_database.rb +11 -0
- data/lib/mongoid/multi_parameter_attributes.rb +80 -0
- data/lib/mongoid/named_scope.rb +36 -0
- data/lib/mongoid/nested_attributes.rb +43 -0
- data/lib/mongoid/paranoia.rb +103 -0
- data/lib/mongoid/paths.rb +61 -0
- data/lib/mongoid/persistence/command.rb +59 -0
- data/lib/mongoid/persistence/insert.rb +53 -0
- data/lib/mongoid/persistence/insert_embedded.rb +42 -0
- data/lib/mongoid/persistence/remove.rb +44 -0
- data/lib/mongoid/persistence/remove_all.rb +40 -0
- data/lib/mongoid/persistence/remove_embedded.rb +48 -0
- data/lib/mongoid/persistence/update.rb +76 -0
- data/lib/mongoid/persistence.rb +237 -0
- data/lib/mongoid/railtie.rb +129 -0
- data/lib/mongoid/railties/database.rake +171 -0
- data/lib/mongoid/railties/document.rb +12 -0
- data/lib/mongoid/relations/accessors.rb +157 -0
- data/lib/mongoid/relations/auto_save.rb +34 -0
- data/lib/mongoid/relations/binding.rb +26 -0
- data/lib/mongoid/relations/bindings/embedded/in.rb +82 -0
- data/lib/mongoid/relations/bindings/embedded/many.rb +98 -0
- data/lib/mongoid/relations/bindings/embedded/one.rb +66 -0
- data/lib/mongoid/relations/bindings/referenced/in.rb +74 -0
- data/lib/mongoid/relations/bindings/referenced/many.rb +96 -0
- data/lib/mongoid/relations/bindings/referenced/many_to_many.rb +99 -0
- data/lib/mongoid/relations/bindings/referenced/one.rb +66 -0
- data/lib/mongoid/relations/bindings.rb +9 -0
- data/lib/mongoid/relations/builder.rb +42 -0
- data/lib/mongoid/relations/builders/embedded/in.rb +25 -0
- data/lib/mongoid/relations/builders/embedded/many.rb +32 -0
- data/lib/mongoid/relations/builders/embedded/one.rb +26 -0
- data/lib/mongoid/relations/builders/nested_attributes/many.rb +116 -0
- data/lib/mongoid/relations/builders/nested_attributes/one.rb +135 -0
- data/lib/mongoid/relations/builders/referenced/in.rb +32 -0
- data/lib/mongoid/relations/builders/referenced/many.rb +26 -0
- data/lib/mongoid/relations/builders/referenced/many_to_many.rb +29 -0
- data/lib/mongoid/relations/builders/referenced/one.rb +30 -0
- data/lib/mongoid/relations/builders.rb +79 -0
- data/lib/mongoid/relations/cascading/delete.rb +19 -0
- data/lib/mongoid/relations/cascading/destroy.rb +19 -0
- data/lib/mongoid/relations/cascading/nullify.rb +18 -0
- data/lib/mongoid/relations/cascading/strategy.rb +26 -0
- data/lib/mongoid/relations/cascading.rb +55 -0
- data/lib/mongoid/relations/constraint.rb +45 -0
- data/lib/mongoid/relations/cyclic.rb +97 -0
- data/lib/mongoid/relations/embedded/in.rb +173 -0
- data/lib/mongoid/relations/embedded/many.rb +483 -0
- data/lib/mongoid/relations/embedded/one.rb +170 -0
- data/lib/mongoid/relations/macros.rb +306 -0
- data/lib/mongoid/relations/many.rb +171 -0
- data/lib/mongoid/relations/metadata.rb +533 -0
- data/lib/mongoid/relations/nested_builder.rb +68 -0
- data/lib/mongoid/relations/one.rb +47 -0
- data/lib/mongoid/relations/polymorphic.rb +54 -0
- data/lib/mongoid/relations/proxy.rb +128 -0
- data/lib/mongoid/relations/referenced/in.rb +216 -0
- data/lib/mongoid/relations/referenced/many.rb +443 -0
- data/lib/mongoid/relations/referenced/many_to_many.rb +344 -0
- data/lib/mongoid/relations/referenced/one.rb +206 -0
- data/lib/mongoid/relations/reflections.rb +45 -0
- data/lib/mongoid/relations.rb +105 -0
- data/lib/mongoid/safe.rb +23 -0
- data/lib/mongoid/safety.rb +207 -0
- data/lib/mongoid/scope.rb +31 -0
- data/lib/mongoid/serialization.rb +99 -0
- data/lib/mongoid/state.rb +66 -0
- data/lib/mongoid/timestamps.rb +38 -0
- data/lib/mongoid/validations/associated.rb +42 -0
- data/lib/mongoid/validations/uniqueness.rb +85 -0
- data/lib/mongoid/validations.rb +117 -0
- data/lib/mongoid/version.rb +4 -0
- data/lib/mongoid/versioning.rb +51 -0
- data/lib/mongoid.rb +139 -0
- data/lib/rails/generators/mongoid/config/config_generator.rb +25 -0
- data/lib/rails/generators/mongoid/config/templates/mongoid.yml +23 -0
- data/lib/rails/generators/mongoid/model/model_generator.rb +24 -0
- data/lib/rails/generators/mongoid/model/templates/model.rb +17 -0
- data/lib/rails/generators/mongoid_generator.rb +61 -0
- data/lib/rails/mongoid.rb +57 -0
- metadata +380 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module Mongoid #:nodoc:
|
|
3
|
+
module Extras #:nodoc:
|
|
4
|
+
extend ActiveSupport::Concern
|
|
5
|
+
included do
|
|
6
|
+
class_attribute :cached, :enslaved
|
|
7
|
+
self.cached = false
|
|
8
|
+
self.enslaved = false
|
|
9
|
+
delegate :cached?, :enslaved?, :to => "self.class"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
module ClassMethods #:nodoc
|
|
13
|
+
# Sets caching on for this class. This class level configuration will
|
|
14
|
+
# default all queries to cache the results of the first iteration over
|
|
15
|
+
# the cursor into an internal array. This should only be used for queries
|
|
16
|
+
# that return a small number of results or have small documents, as after
|
|
17
|
+
# the first iteration the entire results will be stored in memory.
|
|
18
|
+
#
|
|
19
|
+
# Example:
|
|
20
|
+
#
|
|
21
|
+
# class Person
|
|
22
|
+
# include Mongoid::Document
|
|
23
|
+
# cache
|
|
24
|
+
# end
|
|
25
|
+
def cache
|
|
26
|
+
self.cached = true
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Determines if the class is cached or not.
|
|
30
|
+
#
|
|
31
|
+
# Returns:
|
|
32
|
+
#
|
|
33
|
+
# True if cached, false if not.
|
|
34
|
+
def cached?
|
|
35
|
+
!!self.cached
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Set whether or not this documents read operations should delegate to
|
|
39
|
+
# the slave database by default.
|
|
40
|
+
#
|
|
41
|
+
# Example:
|
|
42
|
+
#
|
|
43
|
+
# class Person
|
|
44
|
+
# include Mongoid::Document
|
|
45
|
+
# enslave
|
|
46
|
+
# end
|
|
47
|
+
def enslave
|
|
48
|
+
self.enslaved = true
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Determines if the class is enslaved or not.
|
|
52
|
+
#
|
|
53
|
+
# Returns:
|
|
54
|
+
#
|
|
55
|
+
# True if enslaved, false if not.
|
|
56
|
+
def enslaved?
|
|
57
|
+
!!self.enslaved
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module Mongoid #:nodoc:
|
|
3
|
+
class Factory #:nodoc:
|
|
4
|
+
# Builds a new +Document+ from the supplied attributes.
|
|
5
|
+
#
|
|
6
|
+
# Example:
|
|
7
|
+
#
|
|
8
|
+
# <tt>Mongoid::Factory.build(Person, {})</tt>
|
|
9
|
+
#
|
|
10
|
+
# Options:
|
|
11
|
+
#
|
|
12
|
+
# klass: The class to instantiate from if _type is not present.
|
|
13
|
+
# attributes: The +Document+ attributes.
|
|
14
|
+
def self.build(klass, attributes)
|
|
15
|
+
attrs = {}.merge(attributes)
|
|
16
|
+
type = attrs["_type"]
|
|
17
|
+
type ? type.constantize.instantiate(attrs) : klass.instantiate(attrs)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module Mongoid #:nodoc:
|
|
3
|
+
class Field
|
|
4
|
+
attr_reader :copyable, :klass, :label, :name, :options, :type
|
|
5
|
+
|
|
6
|
+
# Get the default value for the field.
|
|
7
|
+
#
|
|
8
|
+
# Returns:
|
|
9
|
+
#
|
|
10
|
+
# The typecast default value.
|
|
11
|
+
def default
|
|
12
|
+
copy.respond_to?(:call) ? copy : set(copy)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Create the new field with a name and optional additional options. Valid
|
|
16
|
+
# options are :default
|
|
17
|
+
#
|
|
18
|
+
# Options:
|
|
19
|
+
#
|
|
20
|
+
# name: The name of the field as a +Symbol+.
|
|
21
|
+
# options: A +Hash+ of options for the field.
|
|
22
|
+
#
|
|
23
|
+
# Example:
|
|
24
|
+
#
|
|
25
|
+
# <tt>Field.new(:score, :default => 0)</tt>
|
|
26
|
+
def initialize(name, options = {})
|
|
27
|
+
check_name!(name)
|
|
28
|
+
@type = options[:type] || Object
|
|
29
|
+
@name, @default = name, options[:default]
|
|
30
|
+
@copyable = (@default.is_a?(Array) || @default.is_a?(Hash))
|
|
31
|
+
@label = options[:label]
|
|
32
|
+
@options = options
|
|
33
|
+
check_default!
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Used for setting an object in the attributes hash.
|
|
37
|
+
#
|
|
38
|
+
# If nil is provided the default will get returned if it exists.
|
|
39
|
+
#
|
|
40
|
+
# If the field is an identity field, ie an id, it performs the necessary
|
|
41
|
+
# cast.
|
|
42
|
+
#
|
|
43
|
+
# Example:
|
|
44
|
+
#
|
|
45
|
+
# <tt>field.set("New Value")</tt>
|
|
46
|
+
#
|
|
47
|
+
# Returns:
|
|
48
|
+
#
|
|
49
|
+
# The new value.
|
|
50
|
+
def set(object)
|
|
51
|
+
unless options[:identity]
|
|
52
|
+
type.set(object)
|
|
53
|
+
else
|
|
54
|
+
if object.blank?
|
|
55
|
+
type.set(object)
|
|
56
|
+
else
|
|
57
|
+
options[:metadata].constraint.convert(object)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Used for retrieving the object out of the attributes hash.
|
|
63
|
+
#
|
|
64
|
+
# Example:
|
|
65
|
+
#
|
|
66
|
+
# <tt>field.get("Value")</tt>
|
|
67
|
+
#
|
|
68
|
+
# Returns:
|
|
69
|
+
#
|
|
70
|
+
# The converted value.
|
|
71
|
+
def get(object)
|
|
72
|
+
type.get(object)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
protected
|
|
76
|
+
# Slightly faster default check.
|
|
77
|
+
def copy
|
|
78
|
+
copyable ? @default.dup : @default
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Check if the name is valid.
|
|
82
|
+
def check_name!(name)
|
|
83
|
+
if Mongoid.destructive_fields.include?(name.to_s)
|
|
84
|
+
raise Mongoid::Errors::InvalidField.new(name)
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def check_default!
|
|
89
|
+
return if @default.is_a?(Proc)
|
|
90
|
+
if !@default.nil? && !@default.is_a?(type)
|
|
91
|
+
raise Mongoid::Errors::InvalidType.new(type, @default)
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module Mongoid #:nodoc
|
|
3
|
+
|
|
4
|
+
# This module defines behaviour for fields.
|
|
5
|
+
module Fields
|
|
6
|
+
extend ActiveSupport::Concern
|
|
7
|
+
|
|
8
|
+
included do
|
|
9
|
+
# Set up the class attributes that must be available to all subclasses.
|
|
10
|
+
# These include defaults, fields
|
|
11
|
+
delegate :defaults, :fields, :to => "self.class"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
module ClassMethods #:nodoc
|
|
15
|
+
|
|
16
|
+
# Defines all the fields that are accessable on the Document
|
|
17
|
+
# For each field that is defined, a getter and setter will be
|
|
18
|
+
# added as an instance method to the Document.
|
|
19
|
+
#
|
|
20
|
+
# @example Define a field.
|
|
21
|
+
# field :score, :type => Integer, :default => 0
|
|
22
|
+
#
|
|
23
|
+
# @param [ Symbol ] name The name of the field.
|
|
24
|
+
# @param [ Hash ] options The options to pass to the field.
|
|
25
|
+
#
|
|
26
|
+
# @option options [ Class ] :type The type of the field.
|
|
27
|
+
# @option options [ String ] :label The label for the field.
|
|
28
|
+
# @option options [ Object, Proc ] :default The field's default
|
|
29
|
+
def field(name, options = {})
|
|
30
|
+
access = name.to_s
|
|
31
|
+
set_field(access, options)
|
|
32
|
+
attr_protected name if options[:accessible] == false
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Return the fields for this class.
|
|
36
|
+
#
|
|
37
|
+
# @example Get the fields.
|
|
38
|
+
# Person.fields
|
|
39
|
+
#
|
|
40
|
+
# @return [ Hash ] The fields for this document.
|
|
41
|
+
#
|
|
42
|
+
# @since 2.0.0.rc.6
|
|
43
|
+
def fields
|
|
44
|
+
@fields ||= {}
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Set the fields for the class.
|
|
48
|
+
#
|
|
49
|
+
# @example Set the fields.
|
|
50
|
+
# Person.fields = fields
|
|
51
|
+
#
|
|
52
|
+
# @param [ Hash ] fields The hash of fields to set.
|
|
53
|
+
#
|
|
54
|
+
# @since 2.0.0.rc.6
|
|
55
|
+
def fields=(fields)
|
|
56
|
+
@fields = fields
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Returns the default values for the fields on the document.
|
|
60
|
+
#
|
|
61
|
+
# @example Get the defaults.
|
|
62
|
+
# Person.defaults
|
|
63
|
+
#
|
|
64
|
+
# @return [ Hash ] The field defaults.
|
|
65
|
+
def defaults
|
|
66
|
+
fields.inject({}) do |defs, (field_name,field)|
|
|
67
|
+
next(defs) if field.default.nil?
|
|
68
|
+
defs[field_name.to_s] = field.default
|
|
69
|
+
defs
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# When inheriting, we want to copy the fields from the parent class and
|
|
74
|
+
# set the on the child to start, mimicing the behaviour of the old
|
|
75
|
+
# class_inheritable_accessor that was deprecated in Rails edge.
|
|
76
|
+
#
|
|
77
|
+
# @example Inherit from this class.
|
|
78
|
+
# Person.inherited(Doctor)
|
|
79
|
+
#
|
|
80
|
+
# @param [ Class ] subclass The inheriting class.
|
|
81
|
+
#
|
|
82
|
+
# @since 2.0.0.rc.6
|
|
83
|
+
def inherited(subclass)
|
|
84
|
+
subclass.fields = fields.dup
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
protected
|
|
88
|
+
|
|
89
|
+
# Define a field attribute for the +Document+.
|
|
90
|
+
#
|
|
91
|
+
# @example Set the field.
|
|
92
|
+
# Person.set_field(:name, :default => "Test")
|
|
93
|
+
#
|
|
94
|
+
# @param [ Symbol ] name The name of the field.
|
|
95
|
+
# @param [ Hash ] options The hash of options.
|
|
96
|
+
def set_field(name, options = {})
|
|
97
|
+
meth = options.delete(:as) || name
|
|
98
|
+
fields[name] = Field.new(name, options)
|
|
99
|
+
create_accessors(name, meth, options)
|
|
100
|
+
add_dirty_methods(name)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Create the field accessors.
|
|
104
|
+
#
|
|
105
|
+
# @example Generate the accessors.
|
|
106
|
+
# Person.create_accessors(:name, "name")
|
|
107
|
+
# person.name #=> returns the field
|
|
108
|
+
# person.name = "" #=> sets the field
|
|
109
|
+
# person.name? #=> Is the field present?
|
|
110
|
+
#
|
|
111
|
+
# @param [ Symbol ] name The name of the field.
|
|
112
|
+
# @param [ Symbol ] meth The name of the accessor.
|
|
113
|
+
# @param [ Hash ] options The options.
|
|
114
|
+
def create_accessors(name, meth, options = {})
|
|
115
|
+
generated_field_methods.module_eval do
|
|
116
|
+
define_method(meth) { read_attribute(name) }
|
|
117
|
+
define_method("#{meth}=") { |value| write_attribute(name, value) }
|
|
118
|
+
define_method("#{meth}?") do
|
|
119
|
+
attr = read_attribute(name)
|
|
120
|
+
(options[:type] == Boolean) ? attr == true : attr.present?
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# Include the field methods as a module, so they can be overridden.
|
|
126
|
+
#
|
|
127
|
+
# @example Include the fields.
|
|
128
|
+
# Person.generated_field_methods
|
|
129
|
+
def generated_field_methods
|
|
130
|
+
@generated_field_methods ||= begin
|
|
131
|
+
Module.new.tap do |mod|
|
|
132
|
+
include mod
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module Mongoid #:nodoc:
|
|
3
|
+
module Finders #:nodoc:
|
|
4
|
+
|
|
5
|
+
# Delegate to the criteria methods that are natural for creating a new
|
|
6
|
+
# criteria.
|
|
7
|
+
[ :all_in, :any_in, :any_of, :asc, :ascending, :avg, :desc, :descending,
|
|
8
|
+
:excludes, :limit, :max, :min, :not_in, :only, :order_by,
|
|
9
|
+
:skip, :sum, :where, :update, :update_all, :near ].each do |name|
|
|
10
|
+
define_method(name) do |*args|
|
|
11
|
+
criteria.send(name, *args)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Find +Documents+ given the conditions.
|
|
16
|
+
#
|
|
17
|
+
# Options:
|
|
18
|
+
#
|
|
19
|
+
# args: A +Hash+ with a conditions key and other options
|
|
20
|
+
#
|
|
21
|
+
# <tt>Person.all(:conditions => { :attribute => "value" })</tt>
|
|
22
|
+
def all(*args)
|
|
23
|
+
find(:all, *args)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Returns a count of matching records in the database based on the
|
|
27
|
+
# provided arguments.
|
|
28
|
+
#
|
|
29
|
+
# <tt>Person.count(:conditions => { :attribute => "value" })</tt>
|
|
30
|
+
def count(*args)
|
|
31
|
+
Criteria.translate(self, false, *args).count
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Returns true if there are on document in database based on the
|
|
35
|
+
# provided arguments.
|
|
36
|
+
#
|
|
37
|
+
# <tt>Person.exists?(:conditions => { :attribute => "value" })</tt>
|
|
38
|
+
def exists?(*args)
|
|
39
|
+
Criteria.translate(self, false, *args).limit(1).count == 1
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Helper to initialize a new +Criteria+ object for this class, or return
|
|
43
|
+
# the currently scoped +Criteria+ object.
|
|
44
|
+
#
|
|
45
|
+
# Example:
|
|
46
|
+
#
|
|
47
|
+
# <tt>Person.criteria</tt>
|
|
48
|
+
def criteria(embedded = false)
|
|
49
|
+
scope_stack.last || Criteria.new(self, embedded)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Find a +Document+ in several different ways.
|
|
53
|
+
#
|
|
54
|
+
# If a +String+ is provided, it will be assumed that it is a
|
|
55
|
+
# representation of a Mongo::ObjectID and will attempt to find a single
|
|
56
|
+
# +Document+ based on that id. If a +Symbol+ and +Hash+ is provided then
|
|
57
|
+
# it will attempt to find either a single +Document+ or multiples based
|
|
58
|
+
# on the conditions provided and the first parameter.
|
|
59
|
+
#
|
|
60
|
+
# Example:
|
|
61
|
+
#
|
|
62
|
+
# <tt>Person.find(:first, :conditions => { :attribute => "value" })</tt>
|
|
63
|
+
# <tt>Person.find(:all, :conditions => { :attribute => "value" })</tt>
|
|
64
|
+
# <tt>Person.find(BSON::ObjectId)</tt>
|
|
65
|
+
#
|
|
66
|
+
# Options:
|
|
67
|
+
#
|
|
68
|
+
# args: An assortment of finder options.
|
|
69
|
+
#
|
|
70
|
+
# Returns:
|
|
71
|
+
#
|
|
72
|
+
# A document or criteria.
|
|
73
|
+
def find(*args)
|
|
74
|
+
raise Errors::InvalidOptions.new(
|
|
75
|
+
:calling_document_find_with_nil_is_invalid, {}
|
|
76
|
+
) if args[0].nil?
|
|
77
|
+
type, criteria = Criteria.parse!(self, false, *args)
|
|
78
|
+
case type
|
|
79
|
+
when :first then return criteria.one
|
|
80
|
+
when :last then return criteria.last
|
|
81
|
+
else
|
|
82
|
+
return criteria
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Find the first +Document+ given the conditions, or creates a new document
|
|
87
|
+
# with the conditions that were supplied
|
|
88
|
+
#
|
|
89
|
+
# Options:
|
|
90
|
+
#
|
|
91
|
+
# args: A +Hash+ of attributes
|
|
92
|
+
#
|
|
93
|
+
# <tt>Person.find_or_create_by(:attribute => "value")</tt>
|
|
94
|
+
def find_or_create_by(attrs = {})
|
|
95
|
+
find_or(:create, attrs)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Find the first +Document+ given the conditions, or instantiates a new document
|
|
99
|
+
# with the conditions that were supplied
|
|
100
|
+
#
|
|
101
|
+
# Options:
|
|
102
|
+
#
|
|
103
|
+
# args: A +Hash+ of attributes
|
|
104
|
+
#
|
|
105
|
+
# <tt>Person.find_or_initialize_by(:attribute => "value")</tt>
|
|
106
|
+
def find_or_initialize_by(attrs = {})
|
|
107
|
+
find_or(:new, attrs)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Find the first +Document+ given the conditions.
|
|
111
|
+
#
|
|
112
|
+
# Options:
|
|
113
|
+
#
|
|
114
|
+
# args: A +Hash+ with a conditions key and other options
|
|
115
|
+
#
|
|
116
|
+
# <tt>Person.first(:conditions => { :attribute => "value" })</tt>
|
|
117
|
+
def first(*args)
|
|
118
|
+
find(:first, *args)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Find the last +Document+ given the conditions.
|
|
122
|
+
#
|
|
123
|
+
# Options:
|
|
124
|
+
#
|
|
125
|
+
# args: A +Hash+ with a conditions key and other options
|
|
126
|
+
#
|
|
127
|
+
# <tt>Person.last(:conditions => { :attribute => "value" })</tt>
|
|
128
|
+
def last(*args)
|
|
129
|
+
find(:last, *args)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# Find all documents in paginated fashion given the supplied arguments.
|
|
133
|
+
# If no parameters are passed just default to offset 0 and limit 20.
|
|
134
|
+
#
|
|
135
|
+
# Options:
|
|
136
|
+
#
|
|
137
|
+
# params: A +Hash+ of params to pass to the Criteria API.
|
|
138
|
+
#
|
|
139
|
+
# Example:
|
|
140
|
+
#
|
|
141
|
+
# <tt>Person.paginate(:conditions => { :field => "Test" }, :page => 1,
|
|
142
|
+
# :per_page => 20)</tt>
|
|
143
|
+
#
|
|
144
|
+
# Returns paginated array of docs.
|
|
145
|
+
def paginate(params = {})
|
|
146
|
+
Criteria.translate(self, false, params).paginate
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
protected
|
|
150
|
+
# Find the first object or create/initialize it.
|
|
151
|
+
def find_or(method, attrs = {})
|
|
152
|
+
first(:conditions => attrs) || send(method, attrs)
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# Initializes and returns the current scope stack.
|
|
156
|
+
def scope_stack
|
|
157
|
+
scope_stack_for = Thread.current[:mongoid_scope_stack] ||= {}
|
|
158
|
+
scope_stack_for[object_id] ||= []
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# Pushes the provided criteria onto the scope stack, and removes it after the
|
|
162
|
+
# provided block is yielded.
|
|
163
|
+
def with_scope(criteria)
|
|
164
|
+
scope_stack = self.scope_stack
|
|
165
|
+
scope_stack << criteria
|
|
166
|
+
begin
|
|
167
|
+
yield criteria
|
|
168
|
+
ensure
|
|
169
|
+
scope_stack.pop
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
end
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module Mongoid #:nodoc
|
|
3
|
+
module Hierarchy #:nodoc
|
|
4
|
+
extend ActiveSupport::Concern
|
|
5
|
+
included do
|
|
6
|
+
attr_accessor :_parent
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
module ClassMethods #:nodoc:
|
|
10
|
+
|
|
11
|
+
# Determines if the document is a subclass of another document.
|
|
12
|
+
#
|
|
13
|
+
# @example Check if the document is a subclass.
|
|
14
|
+
# Square.hereditary?
|
|
15
|
+
#
|
|
16
|
+
# @return [ true, false ] True if hereditary, false if not.
|
|
17
|
+
def hereditary?
|
|
18
|
+
Mongoid::Document > superclass
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
module InstanceMethods #:nodoc:
|
|
23
|
+
|
|
24
|
+
# Get all child +Documents+ to this +Document+, going n levels deep if
|
|
25
|
+
# necessary. This is used when calling update persistence operations from
|
|
26
|
+
# the root document, where changes in the entire tree need to be
|
|
27
|
+
# determined. Note that persistence from the embedded documents will
|
|
28
|
+
# always be preferred, since they are optimized calls... This operation
|
|
29
|
+
# can get expensive in domains with large hierarchies.
|
|
30
|
+
#
|
|
31
|
+
# @example Get all the document's children.
|
|
32
|
+
# person._children
|
|
33
|
+
#
|
|
34
|
+
# @return [ Array<Document> ] All child documents in the hierarchy.
|
|
35
|
+
def _children
|
|
36
|
+
relations.inject([]) do |children, (name, metadata)|
|
|
37
|
+
children.tap do |kids|
|
|
38
|
+
if metadata.embedded? && name != "versions"
|
|
39
|
+
child = send(name)
|
|
40
|
+
child.to_a.each do |doc|
|
|
41
|
+
kids.push(doc).concat(doc._children)
|
|
42
|
+
end unless child.blank?
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Determines if the document is a subclass of another document.
|
|
49
|
+
#
|
|
50
|
+
# @example Check if the document is a subclass
|
|
51
|
+
# Square.new.hereditary?
|
|
52
|
+
#
|
|
53
|
+
# @return [ true, false ] True if hereditary, false if not.
|
|
54
|
+
def hereditary?
|
|
55
|
+
self.class.hereditary?
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Sets up a child/parent association. This is used for newly created
|
|
59
|
+
# objects so they can be properly added to the graph.
|
|
60
|
+
#
|
|
61
|
+
# @example Set the parent document.
|
|
62
|
+
# document.parentize(parent)
|
|
63
|
+
#
|
|
64
|
+
# @param [ Document ] document The parent document.
|
|
65
|
+
#
|
|
66
|
+
# @return [ Document ] The parent document.
|
|
67
|
+
def parentize(document)
|
|
68
|
+
self._parent = document
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Return the root document in the object graph. If the current document
|
|
72
|
+
# is the root object in the graph it will return self.
|
|
73
|
+
#
|
|
74
|
+
# @example Get the root document in the hierarchy.
|
|
75
|
+
# document._root
|
|
76
|
+
#
|
|
77
|
+
# @return [ Document ] The root document in the hierarchy.
|
|
78
|
+
def _root
|
|
79
|
+
object = self
|
|
80
|
+
while (object._parent) do object = object._parent; end
|
|
81
|
+
object || self
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module Mongoid #:nodoc:
|
|
3
|
+
class Identity #:nodoc:
|
|
4
|
+
|
|
5
|
+
attr_reader :document
|
|
6
|
+
|
|
7
|
+
# Create the identity for the document. The id will be set in either in
|
|
8
|
+
# the form of a Mongo object id or a composite key set up by defining
|
|
9
|
+
# a key on the document. The _type will be set to the document's class
|
|
10
|
+
# name.
|
|
11
|
+
#
|
|
12
|
+
# @example Create the id and set the type.
|
|
13
|
+
# identity.create
|
|
14
|
+
def create
|
|
15
|
+
identify and type
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Create the new identity generator - this will be expanded in the future
|
|
19
|
+
# to support pk generators.
|
|
20
|
+
#
|
|
21
|
+
# @example
|
|
22
|
+
# Identity.new(document)
|
|
23
|
+
#
|
|
24
|
+
# @param [ Document ] document The document to generate an id for.
|
|
25
|
+
#
|
|
26
|
+
# @return [ Identity ] The new identity object.
|
|
27
|
+
def initialize(document)
|
|
28
|
+
@document = document
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
# Return the proper id for the document. Will be an object id or its string
|
|
34
|
+
# representation depending on the configuration.
|
|
35
|
+
#
|
|
36
|
+
# @example Generate the id.
|
|
37
|
+
# identity.generate_id
|
|
38
|
+
#
|
|
39
|
+
# @return [ Object ] The bson object id or its string equivalent.
|
|
40
|
+
def generate_id
|
|
41
|
+
id = BSON::ObjectId.new
|
|
42
|
+
document.using_object_ids? ? id : id.to_s
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Sets the id on the document. Will either set a newly generated id or
|
|
46
|
+
# build the composite key.
|
|
47
|
+
#
|
|
48
|
+
# @example Set the id.
|
|
49
|
+
# identity.identify
|
|
50
|
+
def identify
|
|
51
|
+
document.id = compose.join(" ").identify if document.primary_key
|
|
52
|
+
document.id = generate_id if document.id.blank?
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Set the _type field on the document if the document is hereditary or in a
|
|
56
|
+
# polymorphic relation.
|
|
57
|
+
#
|
|
58
|
+
# @example Set the type.
|
|
59
|
+
# identity.type
|
|
60
|
+
def type
|
|
61
|
+
document._type = document.class.name if typed?
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Generates the array of keys to build the id.
|
|
65
|
+
#
|
|
66
|
+
# @example Build the array for the keys.
|
|
67
|
+
# identity.compose.
|
|
68
|
+
#
|
|
69
|
+
# @return [ Array<Object> ] The array of keys.
|
|
70
|
+
def compose
|
|
71
|
+
document.primary_key.collect do |key|
|
|
72
|
+
document.attributes[key]
|
|
73
|
+
end.reject { |val| val.nil? }
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Determines if the document stores the type information. This is if it is
|
|
77
|
+
# in a hierarchy, has subclasses, or is in a polymorphic relation.
|
|
78
|
+
#
|
|
79
|
+
# @example Check if the document is typed.
|
|
80
|
+
# identity.typed?
|
|
81
|
+
#
|
|
82
|
+
# @return [ true, false ] True if typed, false if not.
|
|
83
|
+
def typed?
|
|
84
|
+
document.hereditary? ||
|
|
85
|
+
document.class.descendants.any? ||
|
|
86
|
+
document.polymorphic?
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module Mongoid #:nodoc
|
|
3
|
+
module Indexes #:nodoc
|
|
4
|
+
extend ActiveSupport::Concern
|
|
5
|
+
included do
|
|
6
|
+
cattr_accessor :index_options
|
|
7
|
+
self.index_options = {}
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
module ClassMethods #:nodoc
|
|
11
|
+
|
|
12
|
+
# Send the actual index creation comments to the MongoDB driver
|
|
13
|
+
def create_indexes
|
|
14
|
+
return unless index_options
|
|
15
|
+
current_collection = self._collection || set_collection
|
|
16
|
+
index_options.each do |name, options|
|
|
17
|
+
current_collection.create_index(name, options)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Add the default indexes to the root document if they do not already
|
|
22
|
+
# exist. Currently this is only _type.
|
|
23
|
+
def add_indexes
|
|
24
|
+
if hereditary? && !index_options[:_type]
|
|
25
|
+
self.index_options[:_type] = {:unique => false, :background => true}
|
|
26
|
+
end
|
|
27
|
+
create_indexes if Mongoid.autocreate_indexes
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Adds an index on the field specified. Options can be :unique => true or
|
|
31
|
+
# :unique => false. It will default to the latter.
|
|
32
|
+
def index(name, options = { :unique => false })
|
|
33
|
+
self.index_options[name] = options
|
|
34
|
+
create_indexes if Mongoid.autocreate_indexes
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|