mongo_db 0.1.9 → 0.1.10
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/lib/mongo_db/driver/{core/collection.rb → collection.rb} +13 -5
- data/lib/mongo_db/driver/{core/database.rb → database.rb} +0 -0
- data/lib/mongo_db/driver/dynamic_finders.rb +41 -0
- data/lib/mongo_db/driver.rb +33 -2
- data/lib/mongo_db/migration/definition.rb +19 -0
- data/lib/mongo_db/migration/migration.rb +68 -0
- data/lib/mongo_db/migration/tasks.rb +19 -0
- data/lib/mongo_db/migration.rb +8 -0
- data/lib/mongo_db/model/assignment.rb +54 -0
- data/lib/mongo_db/model/callbacks.rb +36 -0
- data/lib/mongo_db/model/crud.rb +28 -0
- data/lib/mongo_db/model/db.rb +53 -0
- data/lib/mongo_db/model/misc.rb +14 -0
- data/lib/mongo_db/model/model.rb +10 -0
- data/lib/mongo_db/model/query.rb +36 -0
- data/lib/mongo_db/model/scope.rb +99 -0
- data/lib/mongo_db/model/spec.rb +12 -0
- data/lib/mongo_db/model/support/types.rb +110 -0
- data/lib/mongo_db/model/validation.rb +5 -0
- data/lib/mongo_db/model.rb +30 -0
- data/lib/mongo_db/object/object_serializer.rb +20 -21
- data/readme.md +132 -19
- data/spec/driver/{core/collection_spec.rb → collection_spec.rb} +13 -0
- data/spec/driver/{core/crud_spec.rb → crud_spec.rb} +0 -0
- data/spec/driver/{core/database_spec.rb → database_spec.rb} +0 -0
- data/spec/driver/dynamic_finders_spec.rb +50 -0
- data/spec/driver/{core/hash_helper_spec.rb → hash_helper_spec.rb} +0 -0
- data/spec/{model/example.rb → integration/am_conversion_spec.rb} +0 -0
- data/spec/integration/am_validation_spec.rb +40 -0
- data/spec/migration/migration_spec.rb +60 -0
- data/spec/model/assignment_spec.rb +79 -0
- data/spec/model/callbacks_spec.rb +47 -0
- data/spec/model/{model_crud.rb → crud_spec.rb} +46 -36
- data/spec/model/db_spec.rb +63 -0
- data/spec/model/misc_spec.rb +32 -0
- data/spec/model/query_spec.rb +47 -0
- data/spec/model/scope_spec.rb +149 -0
- data/spec/model/spec_helper.rb +4 -0
- data/spec/model/validation_spec.rb +37 -0
- data/spec/object/callbacks_spec.rb +6 -4
- data/spec/object/crud_shared.rb +1 -1
- data/spec/object/crud_spec.rb +15 -10
- data/spec/object/spec_helper.rb +3 -2
- data/spec/object/validation_spec.rb +4 -2
- metadata +39 -18
- data/lib/mongo_db/driver/core.rb +0 -29
- data/lib/mongo_db/driver/more/collection_finders.rb +0 -43
- data/lib/mongo_db/driver/more.rb +0 -10
- data/spec/driver/more/querying_spec.rb +0 -59
- data/spec/model/callbacks.rb +0 -100
- data/spec/test.rb +0 -10
@@ -38,7 +38,7 @@ module Mongo::CollectionExt
|
|
38
38
|
def destroy *args
|
39
39
|
remove *args
|
40
40
|
end
|
41
|
-
|
41
|
+
|
42
42
|
def create *args
|
43
43
|
insert *args
|
44
44
|
end
|
@@ -46,19 +46,23 @@ module Mongo::CollectionExt
|
|
46
46
|
#
|
47
47
|
# Querying
|
48
48
|
#
|
49
|
-
def first selector =
|
49
|
+
def first selector = {}, opts = {}
|
50
50
|
selector = convert_underscore_to_dollar_in_selector selector if selector.is_a? Hash
|
51
51
|
|
52
52
|
h = find_one selector, opts
|
53
53
|
symbolize_doc h
|
54
54
|
end
|
55
55
|
|
56
|
-
def
|
56
|
+
def first! selector = {}, opts = {}
|
57
|
+
first(selector, opts) || raise(Mongo::NotFound, "document with selector #{selector} not found!")
|
58
|
+
end
|
59
|
+
|
60
|
+
def all selector = {}, opts = {}, &block
|
57
61
|
if block
|
58
|
-
each
|
62
|
+
each selector, opts, &block
|
59
63
|
else
|
60
64
|
list = []
|
61
|
-
each(
|
65
|
+
each(selector, opts){|doc| list << doc}
|
62
66
|
list
|
63
67
|
end
|
64
68
|
end
|
@@ -80,6 +84,10 @@ module Mongo::CollectionExt
|
|
80
84
|
nil
|
81
85
|
end
|
82
86
|
|
87
|
+
def count_with_ext selector = {}, opts = {}
|
88
|
+
find(selector, opts).count()
|
89
|
+
end
|
90
|
+
|
83
91
|
protected
|
84
92
|
QUERY_KEYWORDS = [
|
85
93
|
:_lt, :_lte, :_gt, :_gte,
|
File without changes
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Mongo::DynamicFinders
|
2
|
+
protected
|
3
|
+
#
|
4
|
+
# first_by_field, all_by_field, each_by_field, first_by_field
|
5
|
+
#
|
6
|
+
def method_missing clause, *args, &block
|
7
|
+
if clause =~ /^([a-z]_by_[a-z_])|(by_[a-z_])/
|
8
|
+
clause = clause.to_s
|
9
|
+
|
10
|
+
bang = clause =~ /!$/
|
11
|
+
clause = clause[0..-2] if bang
|
12
|
+
|
13
|
+
finder, field = if clause =~ /^by_/
|
14
|
+
['first', clause.sub(/by_/, '')]
|
15
|
+
else
|
16
|
+
clause.split(/_by_/, 2)
|
17
|
+
end
|
18
|
+
|
19
|
+
finder = 'first' if finder == 'find'
|
20
|
+
field = '_id' if field == 'id'
|
21
|
+
|
22
|
+
if bang
|
23
|
+
raise "You can't use bang version with :#{finder}!" unless finder == 'first'
|
24
|
+
finder = "#{finder}!"
|
25
|
+
end
|
26
|
+
|
27
|
+
raise "invalid arguments for finder (#{args})!" unless args.size == 1
|
28
|
+
field_value = args.first
|
29
|
+
|
30
|
+
finder, field = finder.to_sym, field.to_sym
|
31
|
+
|
32
|
+
if respond_to? finder
|
33
|
+
send finder, {field => field_value}, &block
|
34
|
+
else
|
35
|
+
super
|
36
|
+
end
|
37
|
+
else
|
38
|
+
super
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/mongo_db/driver.rb
CHANGED
@@ -1,2 +1,33 @@
|
|
1
|
-
require 'mongo_db/
|
2
|
-
|
1
|
+
require 'mongo_db/gems'
|
2
|
+
|
3
|
+
require 'mongo'
|
4
|
+
|
5
|
+
class Mongo::Error < StandardError; end
|
6
|
+
class Mongo::NotFound < Mongo::Error; end
|
7
|
+
|
8
|
+
%w(
|
9
|
+
database
|
10
|
+
collection
|
11
|
+
dynamic_finders
|
12
|
+
).each{|f| require "mongo_db/driver/#{f}"}
|
13
|
+
|
14
|
+
# defaults
|
15
|
+
Mongo.class_eval do
|
16
|
+
class << self
|
17
|
+
def defaults; @defaults ||= {} end
|
18
|
+
attr_writer :defaults
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# database
|
23
|
+
Mongo::DB.send :include, Mongo::DBExt
|
24
|
+
|
25
|
+
# collection
|
26
|
+
Mongo::Collection.class_eval do
|
27
|
+
include Mongo::CollectionExt, Mongo::DynamicFinders
|
28
|
+
|
29
|
+
%w(insert update remove save count).each do |method|
|
30
|
+
alias_method "#{method}_without_ext", method
|
31
|
+
alias_method method, "#{method}_with_ext"
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class Mongo::Migration::Definition
|
2
|
+
def upgrade &block
|
3
|
+
if block
|
4
|
+
@upgrade = block
|
5
|
+
else
|
6
|
+
@upgrade
|
7
|
+
end
|
8
|
+
end
|
9
|
+
alias_method :up, :upgrade
|
10
|
+
|
11
|
+
def downgrade &block
|
12
|
+
if block
|
13
|
+
@downgrade = block
|
14
|
+
else
|
15
|
+
@downgrade
|
16
|
+
end
|
17
|
+
end
|
18
|
+
alias_method :down, :downgrade
|
19
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
class Mongo::Migration
|
2
|
+
def initialize db
|
3
|
+
@db, @definitions = db, {}
|
4
|
+
end
|
5
|
+
|
6
|
+
def add version, &block
|
7
|
+
raise "version should be an Integer! (but you provided '#{version}' instad)!" unless version.is_a? Integer
|
8
|
+
definition = Definition.new
|
9
|
+
block.call definition
|
10
|
+
definitions[version] = definition
|
11
|
+
end
|
12
|
+
|
13
|
+
def update version = nil
|
14
|
+
version ||= definitions.keys.max
|
15
|
+
|
16
|
+
if current_version == version
|
17
|
+
info "database '#{db.name}' already is of #{version} version, no migration needed"
|
18
|
+
return false
|
19
|
+
else
|
20
|
+
info "updating '#{db.name}' to #{version}"
|
21
|
+
end
|
22
|
+
|
23
|
+
increase_db_version while current_version < version
|
24
|
+
decrease_db_version while current_version > version
|
25
|
+
true
|
26
|
+
end
|
27
|
+
|
28
|
+
def current_version
|
29
|
+
if doc = db.db_metadata.first(name: 'migration')
|
30
|
+
doc[:version] || doc['version']
|
31
|
+
else
|
32
|
+
0
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
protected
|
37
|
+
attr_accessor :db, :definitions
|
38
|
+
|
39
|
+
def info msg
|
40
|
+
db.connection.logger and db.connection.logger.info(msg)
|
41
|
+
end
|
42
|
+
|
43
|
+
def update_version new_version
|
44
|
+
db.db_metadata.update({name: 'migration'}, {name: 'migration', version: new_version}, {upsert: true, safe: true})
|
45
|
+
end
|
46
|
+
|
47
|
+
def increase_db_version
|
48
|
+
new_version = current_version + 1
|
49
|
+
migration = definitions[new_version]
|
50
|
+
raise "no upgrade of #{db.name} database to #{new_version} version!" unless migration and migration.up
|
51
|
+
|
52
|
+
migration.up.call db
|
53
|
+
update_version new_version
|
54
|
+
|
55
|
+
info "database '#{db.name}' upgraded to #{new_version} version."
|
56
|
+
end
|
57
|
+
|
58
|
+
def decrease_db_version
|
59
|
+
new_version = current_version - 1
|
60
|
+
migration = definitions[new_version + 1]
|
61
|
+
raise "no downgrade of #{db.name} database to #{new_version} version!" unless migration and migration.down
|
62
|
+
|
63
|
+
migration.down.call db
|
64
|
+
update_version new_version
|
65
|
+
|
66
|
+
info "database '#{db.name}' downgraded to #{new_version} version."
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# namespace :db do
|
2
|
+
# desc "Migrate Database"
|
3
|
+
# task migrate: :migration_evnironment do
|
4
|
+
# require 'mongo_migration'
|
5
|
+
#
|
6
|
+
# database_name = (ENV['d'] || ENV['database'] || :default).to_sym
|
7
|
+
# version = ENV['v'] || ENV['version']
|
8
|
+
#
|
9
|
+
# if version.blank?
|
10
|
+
# size = Mongo.migration.definitions[database_name].size
|
11
|
+
# highest_defined_version = size == 0 ? 0 : size - 1
|
12
|
+
# version = highest_defined_version
|
13
|
+
# else
|
14
|
+
# version = version.to_i
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# Mongo.migration.update version, database_name
|
18
|
+
# end
|
19
|
+
# end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Mongo::Model::Assignment
|
2
|
+
class Dsl < BasicObject
|
3
|
+
def initialize
|
4
|
+
@attributes = {}
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.const_missing name
|
8
|
+
# BasicObject doesn't have access to any constants like String, Symbol, ...
|
9
|
+
::Object.const_get name
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_h; attributes end
|
13
|
+
|
14
|
+
protected
|
15
|
+
attr_reader :attributes
|
16
|
+
|
17
|
+
def method_missing attribute_name, type, mass_assignment = false
|
18
|
+
attribute_name.must_be.a Symbol
|
19
|
+
type.must.respond_to :cast
|
20
|
+
attributes[attribute_name] = [type, mass_assignment]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def set attributes, options = {}
|
25
|
+
if rules = self.class._assignment
|
26
|
+
force = options[:force]
|
27
|
+
attributes.each do |n, v|
|
28
|
+
n = n.to_sym
|
29
|
+
type, mass_assignment = rules[n]
|
30
|
+
if type and (mass_assignment or force)
|
31
|
+
v = type.cast(v)
|
32
|
+
send "#{n}=", v
|
33
|
+
end
|
34
|
+
end
|
35
|
+
else
|
36
|
+
attributes.each{|n, v| send "#{n}=", v}
|
37
|
+
end
|
38
|
+
self
|
39
|
+
end
|
40
|
+
|
41
|
+
def set! attributes, options = {}
|
42
|
+
set attributes, options.merge(force: true)
|
43
|
+
end
|
44
|
+
|
45
|
+
module ClassMethods
|
46
|
+
inheritable_accessor :_assignment, nil
|
47
|
+
|
48
|
+
def assignment &block
|
49
|
+
dsl = ::Mongo::Model::Assignment::Dsl.new
|
50
|
+
dsl.instance_eval &block
|
51
|
+
self._assignment = (_assignment || {}).merge dsl.to_h
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Mongo::Model::Callbacks
|
2
|
+
inherit RubyExt::Callbacks
|
3
|
+
|
4
|
+
def _run_callbacks type, method_name
|
5
|
+
if type == :before
|
6
|
+
run_before_callbacks method_name, method: method_name
|
7
|
+
elsif type == :after
|
8
|
+
run_after_callbacks method_name, method: method_name
|
9
|
+
else
|
10
|
+
raise "invalid callback type (#{type})!"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
module ClassMethods
|
15
|
+
[:validate, :update, :save, :destroy].each do |method_name|
|
16
|
+
define_method "before_#{method_name}" do |*args, &block|
|
17
|
+
opt = args.extract_options!
|
18
|
+
if block
|
19
|
+
set_callback method_name, :before, opt, &block
|
20
|
+
else
|
21
|
+
opt[:terminator] = false unless opt.include? :terminator
|
22
|
+
args.each{|executor| set_callback method_name, :before, executor, opt}
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
define_method "after_#{method_name}" do |*args, &block|
|
27
|
+
opt = args.extract_options!
|
28
|
+
if block
|
29
|
+
set_callback method_name, :after, opt, &block
|
30
|
+
else
|
31
|
+
args.each{|executor| set_callback method_name, :after, executor, opt}
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Mongo::Model::Crud
|
2
|
+
def save opts = {}
|
3
|
+
with_collection opts do |collection, opts|
|
4
|
+
collection.save self, opts
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
def save! *args
|
9
|
+
save(*args) || raise(Mongo::Error, "can't save #{self.inspect}!")
|
10
|
+
end
|
11
|
+
|
12
|
+
def destroy opts = {}
|
13
|
+
with_collection opts do |collection, opts|
|
14
|
+
collection.destroy self, opts
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def destroy! *args
|
19
|
+
destroy(*args)|| raise(Mongo::Error, "can't destroy #{self.inspect}!")
|
20
|
+
end
|
21
|
+
|
22
|
+
protected
|
23
|
+
def with_collection opts, &block
|
24
|
+
opts = opts.clone
|
25
|
+
collection = opts.delete(:collection) || self.class.collection
|
26
|
+
block.call collection, opts
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Mongo::Model::Db
|
2
|
+
module ClassMethods
|
3
|
+
inheritable_accessor :_db, nil
|
4
|
+
def db= v
|
5
|
+
self._db = if v.is_a? ::Proc
|
6
|
+
v
|
7
|
+
elsif v.is_a? ::Symbol
|
8
|
+
-> {::Mongo::Model.connection.db v.to_s}
|
9
|
+
else
|
10
|
+
-> {v}
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def db *args, &block
|
15
|
+
if block
|
16
|
+
self.db = block
|
17
|
+
elsif !args.empty?
|
18
|
+
args.size.must == 1
|
19
|
+
self.db = args.first
|
20
|
+
else
|
21
|
+
(_db && _db.call) || ::Mongo::Model.db
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
inheritable_accessor :_collection, nil
|
26
|
+
def collection= v
|
27
|
+
self._collection = if v.is_a? ::Proc
|
28
|
+
v
|
29
|
+
elsif v.is_a? ::Symbol
|
30
|
+
-> {db.collection v}
|
31
|
+
else
|
32
|
+
-> {v}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def collection *args, &block
|
37
|
+
if block
|
38
|
+
self.collection = block
|
39
|
+
elsif !args.empty?
|
40
|
+
args.size.must == 1
|
41
|
+
self.collection = args.first
|
42
|
+
else
|
43
|
+
(_collection && _collection.call) || db.collection(default_collection_name)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def default_collection_name
|
48
|
+
first_ancestor_class = ancestors.find{|a| a.is_a? Class} ||
|
49
|
+
raise("can't evaluate default collection name for #{self}!")
|
50
|
+
first_ancestor_class.alias.pluralize.underscore.to_sym
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Mongo::Model::Misc
|
2
|
+
def update_timestamps
|
3
|
+
now = Time.now.utc
|
4
|
+
self.created_at ||= now
|
5
|
+
self.updated_at = now
|
6
|
+
end
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
def timestamps!
|
10
|
+
attr_accessor :created_at, :updated_at
|
11
|
+
before_save :update_timestamps
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Mongo::Model::Query
|
2
|
+
module ClassMethods
|
3
|
+
include Mongo::DynamicFinders
|
4
|
+
|
5
|
+
def count selector = {}, opts = {}
|
6
|
+
collection.count selector, opts
|
7
|
+
end
|
8
|
+
|
9
|
+
def first selector = {}, opts = {}
|
10
|
+
collection.first selector, opts
|
11
|
+
end
|
12
|
+
|
13
|
+
def each selector = {}, opts = {}, &block
|
14
|
+
collection.each selector, opts, &block
|
15
|
+
end
|
16
|
+
|
17
|
+
def all selector = {}, opts = {}, &block
|
18
|
+
if block
|
19
|
+
each selector, opts, &block
|
20
|
+
else
|
21
|
+
list = []
|
22
|
+
each(selector, opts){|doc| list << doc}
|
23
|
+
list
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def first! selector = {}, opts = {}
|
28
|
+
first(selector, opts) || raise(Mongo::NotFound, "document with selector #{selector} not found!")
|
29
|
+
end
|
30
|
+
|
31
|
+
def exists? selector = {}, opts = {}
|
32
|
+
count(selector, opts) > 0
|
33
|
+
end
|
34
|
+
alias :exist? :exists?
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
module Mongo::Model::Scope
|
2
|
+
class ScopeProxy < BasicObject
|
3
|
+
def initialize model, scope
|
4
|
+
@model, @scope = model, scope
|
5
|
+
end
|
6
|
+
|
7
|
+
def class
|
8
|
+
::Mongo::Model::Scope::ScopeProxy
|
9
|
+
end
|
10
|
+
|
11
|
+
def reverse_merge! scope
|
12
|
+
@scope = scope.merge @scope
|
13
|
+
end
|
14
|
+
|
15
|
+
def inspect
|
16
|
+
"#<ScopeProxy:{#{scope.inspect}}>"
|
17
|
+
end
|
18
|
+
alias_method :to_s, :inspect
|
19
|
+
|
20
|
+
protected
|
21
|
+
attr_reader :model, :scope
|
22
|
+
|
23
|
+
def method_missing method, *args, &block
|
24
|
+
model.with_scope scope do
|
25
|
+
result = model.send method, *args, &block
|
26
|
+
result.reverse_merge! scope if result.class == ::Mongo::Model::Scope::ScopeProxy
|
27
|
+
result
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
module ClassMethods
|
33
|
+
def current_scope
|
34
|
+
scope, exclusive = Thread.current[:mongo_model_scope]
|
35
|
+
if exclusive
|
36
|
+
scope
|
37
|
+
elsif scope
|
38
|
+
default_scope.merge scope
|
39
|
+
else
|
40
|
+
default_scope
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def with_exclusive_scope options = {}, &block
|
45
|
+
with_scope options, true, &block
|
46
|
+
end
|
47
|
+
|
48
|
+
def with_scope options = {}, exclusive = false, &block
|
49
|
+
previous_options, previous_exclusive = Thread.current[:mongo_model_scope]
|
50
|
+
raise "exclusive scope already applied!" if previous_exclusive
|
51
|
+
|
52
|
+
begin
|
53
|
+
options = previous_options.merge options if previous_options and !exclusive
|
54
|
+
Thread.current[:mongo_model_scope] = [options, exclusive]
|
55
|
+
return block.call
|
56
|
+
ensure
|
57
|
+
Thread.current[:mongo_model_scope] = [previous_options, false]
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
inheritable_accessor :_default_scope, -> {{}}
|
62
|
+
def default_scope *args, &block
|
63
|
+
if block
|
64
|
+
self._default_scope = block
|
65
|
+
elsif !args.empty?
|
66
|
+
args.size.must == 1
|
67
|
+
args.first.must_be.a Hash
|
68
|
+
scope = args.first
|
69
|
+
self._default_scope = -> {args.first}
|
70
|
+
else
|
71
|
+
_default_scope.call
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def scope name, options = nil, &block
|
76
|
+
model = self
|
77
|
+
metaclass.define_method name do
|
78
|
+
scope = (block && block.call) || options
|
79
|
+
ScopeProxy.new model, scope
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
#
|
85
|
+
# finders
|
86
|
+
#
|
87
|
+
def count selector = {}, opts = {}
|
88
|
+
super current_scope.merge(selector), opts
|
89
|
+
end
|
90
|
+
|
91
|
+
def first selector = {}, opts = {}
|
92
|
+
super current_scope.merge(selector), opts
|
93
|
+
end
|
94
|
+
|
95
|
+
def each selector = {}, opts = {}, &block
|
96
|
+
super current_scope.merge(selector), opts, &block
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|