mongo_db 0.1.9 → 0.1.10
Sign up to get free protection for your applications and to get access to all the features.
- 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
|