mongoid-casino 0.0.1
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/.gitignore +20 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +93 -0
- data/Rakefile +9 -0
- data/casino.gemspec +30 -0
- data/lib/casino.rb +13 -0
- data/lib/casino/collection.rb +195 -0
- data/lib/casino/dimension.rb +11 -0
- data/lib/casino/focus.rb +26 -0
- data/lib/casino/intersection.rb +30 -0
- data/lib/casino/intersection/match/all.rb +29 -0
- data/lib/casino/intersection/match/base.rb +49 -0
- data/lib/casino/intersection/match/equivalence.rb +25 -0
- data/lib/casino/intersection/match/expression.rb +15 -0
- data/lib/casino/intersection/match/greater.rb +43 -0
- data/lib/casino/intersection/match/include.rb +15 -0
- data/lib/casino/intersection/match/lesser.rb +31 -0
- data/lib/casino/intersection/match/recurse.rb +19 -0
- data/lib/casino/lobby.rb +21 -0
- data/lib/casino/projection.rb +76 -0
- data/lib/casino/query.rb +23 -0
- data/lib/casino/question.rb +9 -0
- data/lib/casino/store.rb +49 -0
- data/lib/casino/version.rb +3 -0
- data/spec/fabricators/model_fabricator.rb +12 -0
- data/spec/fabricators/note_fabricator.rb +3 -0
- data/spec/fixtures/collections/collection.rb +3 -0
- data/spec/fixtures/collections/emails_by_day.rb +28 -0
- data/spec/fixtures/models/model.rb +8 -0
- data/spec/fixtures/models/note.rb +7 -0
- data/spec/lib/casino/collection_spec.rb +146 -0
- data/spec/lib/casino/dimension_spec.rb +27 -0
- data/spec/lib/casino/focus_spec.rb +53 -0
- data/spec/lib/casino/intersection/match/all_spec.rb +24 -0
- data/spec/lib/casino/intersection/match/base_spec.rb +159 -0
- data/spec/lib/casino/intersection/match/equivalence_spec.rb +26 -0
- data/spec/lib/casino/intersection/match/expression_spec.rb +26 -0
- data/spec/lib/casino/intersection/match/greater_spec.rb +72 -0
- data/spec/lib/casino/intersection/match/include_spec.rb +27 -0
- data/spec/lib/casino/intersection/match/lesser_spec.rb +74 -0
- data/spec/lib/casino/intersection/match/recurse_spec.rb +24 -0
- data/spec/lib/casino/intersection_spec.rb +33 -0
- data/spec/lib/casino/lobby_spec.rb +20 -0
- data/spec/lib/casino/projection_spec.rb +81 -0
- data/spec/lib/casino/query_spec.rb +42 -0
- data/spec/lib/casino/question_spec.rb +10 -0
- data/spec/lib/casino/store_spec.rb +60 -0
- data/spec/spec_helper.rb +26 -0
- data/spec/support/mongoid.yml +6 -0
- metadata +234 -0
@@ -0,0 +1,29 @@
|
|
1
|
+
module Casino
|
2
|
+
class Intersection
|
3
|
+
module Match
|
4
|
+
class All < Equivalence
|
5
|
+
|
6
|
+
def eligible?
|
7
|
+
key == '$and'
|
8
|
+
end
|
9
|
+
|
10
|
+
def evaluate
|
11
|
+
matchers.map(&:evaluate).all?
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def matchers
|
17
|
+
field.reduce(Array.new) do |list, element|
|
18
|
+
list + build_bases_with_element_keys(element)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def build_bases_with_element_keys(element)
|
23
|
+
element.keys.map { |key| Base.new(document, key, element, value) }
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Casino
|
2
|
+
class Intersection
|
3
|
+
module Match
|
4
|
+
class Base
|
5
|
+
attr_accessor :document, :field, :key, :selector, :value
|
6
|
+
|
7
|
+
def initialize(document, key, selector, value = nil)
|
8
|
+
self.document = document
|
9
|
+
self.field = selector[key]
|
10
|
+
self.key = key
|
11
|
+
self.selector = selector
|
12
|
+
self.value = document_value || value
|
13
|
+
end
|
14
|
+
|
15
|
+
def evaluate
|
16
|
+
matcher.evaluate
|
17
|
+
end
|
18
|
+
|
19
|
+
def match_arguments
|
20
|
+
[ key, value, document, field ]
|
21
|
+
end
|
22
|
+
|
23
|
+
def matchers
|
24
|
+
matcher_classes.map { |class_name| matcher_for class_name }
|
25
|
+
end
|
26
|
+
|
27
|
+
def matcher
|
28
|
+
matchers.find { |matcher| matcher.eligible? }
|
29
|
+
end
|
30
|
+
|
31
|
+
def matcher_for(class_name)
|
32
|
+
class_name = String(class_name).humanize
|
33
|
+
Match.const_get(class_name).new(*match_arguments)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def matcher_classes
|
39
|
+
%w(all include recurse greater lesser expression equivalence)
|
40
|
+
end
|
41
|
+
|
42
|
+
def document_value
|
43
|
+
document.send(key) if document.respond_to?(key)
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Casino
|
2
|
+
class Intersection
|
3
|
+
module Match
|
4
|
+
class Equivalence
|
5
|
+
attr_accessor :document, :field, :key, :value
|
6
|
+
|
7
|
+
def initialize(key, value, document, field)
|
8
|
+
self.key = key
|
9
|
+
self.document = document
|
10
|
+
self.field = field
|
11
|
+
self.value = value
|
12
|
+
end
|
13
|
+
|
14
|
+
def eligible?
|
15
|
+
true
|
16
|
+
end
|
17
|
+
|
18
|
+
def evaluate
|
19
|
+
value == field
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Casino
|
2
|
+
class Intersection
|
3
|
+
module Match
|
4
|
+
class Greater < Equivalence
|
5
|
+
|
6
|
+
def eligible?
|
7
|
+
%w($gt $gte).include? key
|
8
|
+
end
|
9
|
+
|
10
|
+
def evaluate
|
11
|
+
greater_than? ? greater_than! : greater_than_or_equal!
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def greater_than?
|
17
|
+
key == '$gt'
|
18
|
+
end
|
19
|
+
|
20
|
+
def greater_than!
|
21
|
+
evolved_value > evolved_field
|
22
|
+
end
|
23
|
+
|
24
|
+
def greater_than_or_equal!
|
25
|
+
evolved_value >= evolved_field
|
26
|
+
end
|
27
|
+
|
28
|
+
def evolved_value
|
29
|
+
evolve value
|
30
|
+
end
|
31
|
+
|
32
|
+
def evolved_field
|
33
|
+
evolve field
|
34
|
+
end
|
35
|
+
|
36
|
+
def evolve(instance)
|
37
|
+
instance.class.evolve(instance)
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Casino
|
2
|
+
class Intersection
|
3
|
+
module Match
|
4
|
+
class Lesser < Greater
|
5
|
+
|
6
|
+
def eligible?
|
7
|
+
%w($lt $lte).include? key
|
8
|
+
end
|
9
|
+
|
10
|
+
def evaluate
|
11
|
+
lesser_than? ? lesser_than! : lesser_than_or_equal!
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def lesser_than?
|
17
|
+
key == '$lt'
|
18
|
+
end
|
19
|
+
|
20
|
+
def lesser_than!
|
21
|
+
evolved_value < evolved_field
|
22
|
+
end
|
23
|
+
|
24
|
+
def lesser_than_or_equal!
|
25
|
+
evolved_value <= evolved_field
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Casino
|
2
|
+
class Intersection
|
3
|
+
module Match
|
4
|
+
class Recurse < Equivalence
|
5
|
+
|
6
|
+
def eligible?
|
7
|
+
field.is_a? Hash
|
8
|
+
end
|
9
|
+
|
10
|
+
def evaluate
|
11
|
+
keys = field.keys
|
12
|
+
bases = keys.map { |key| Base.new(document, key, field, value) }
|
13
|
+
bases.map(&:evaluate).all?
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/casino/lobby.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
module Casino
|
2
|
+
class Lobby
|
3
|
+
attr_accessor :collection
|
4
|
+
|
5
|
+
def initialize(klass)
|
6
|
+
self.collection = klass
|
7
|
+
end
|
8
|
+
|
9
|
+
def registry
|
10
|
+
@registry ||= Hash.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def add_registry(object)
|
14
|
+
key = object.class.name.downcase.split("::").last.to_sym
|
15
|
+
registry[key] ||= Array.new
|
16
|
+
registry[key] << object
|
17
|
+
registry[key] = registry[key].uniq
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module Casino
|
2
|
+
class Projection
|
3
|
+
attr_accessor :target, :pipeline
|
4
|
+
|
5
|
+
def initialize(klass, pipeline = [])
|
6
|
+
self.target = klass
|
7
|
+
self.pipeline = pipeline
|
8
|
+
end
|
9
|
+
|
10
|
+
def results
|
11
|
+
target.collection.aggregate(pipeline)
|
12
|
+
end
|
13
|
+
|
14
|
+
def mongoize(hash)
|
15
|
+
hash.keys.map { |key| build_mongoized_hash(hash, key) }.reduce(&:merge)
|
16
|
+
end
|
17
|
+
|
18
|
+
def group(conditions)
|
19
|
+
clone_with group: conditions
|
20
|
+
end
|
21
|
+
alias :pivot :group
|
22
|
+
|
23
|
+
def project(conditions)
|
24
|
+
clone_with project: conditions
|
25
|
+
end
|
26
|
+
alias :describe :project
|
27
|
+
alias :build :project
|
28
|
+
|
29
|
+
def unwind(conditions)
|
30
|
+
clone_with unwind: conditions
|
31
|
+
end
|
32
|
+
alias :expand :unwind
|
33
|
+
|
34
|
+
def match(conditions)
|
35
|
+
clone_with match: conditions
|
36
|
+
end
|
37
|
+
alias :where :match
|
38
|
+
alias :find :match
|
39
|
+
|
40
|
+
def sort(conditions)
|
41
|
+
clone_with sort: conditions
|
42
|
+
end
|
43
|
+
alias :order :sort
|
44
|
+
|
45
|
+
def skip(conditions)
|
46
|
+
clone_with skip: conditions
|
47
|
+
end
|
48
|
+
alias :offset :skip
|
49
|
+
|
50
|
+
def limit(conditions)
|
51
|
+
clone_with limit: conditions
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def clone_with(condition)
|
57
|
+
self.class.new target, pipeline + [mongoize(condition)]
|
58
|
+
end
|
59
|
+
|
60
|
+
def build_mongoized_hash(hash, key)
|
61
|
+
new_key = mongo_ready(key)
|
62
|
+
value = hash[key]
|
63
|
+
value = value.is_a?(Hash) ? mongoize(value) : mongo_ready(value)
|
64
|
+
{ new_key => evolve(value) }
|
65
|
+
end
|
66
|
+
|
67
|
+
def evolve(value)
|
68
|
+
value.class.respond_to?(:evolve) ? value.class.evolve(value) : value
|
69
|
+
end
|
70
|
+
|
71
|
+
def mongo_ready(object)
|
72
|
+
object.is_a?(Symbol) ? "$#{object}" : object
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
data/lib/casino/query.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
module Casino
|
2
|
+
class Query
|
3
|
+
attr_accessor :label, :criteria, :conditions
|
4
|
+
|
5
|
+
def initialize(label, conditions, *criteria)
|
6
|
+
self.label = label
|
7
|
+
self.conditions = conditions
|
8
|
+
self.criteria = criteria
|
9
|
+
end
|
10
|
+
|
11
|
+
def merge(dimension)
|
12
|
+
self.class.new(label, build_conditions(dimension), *criteria)
|
13
|
+
end
|
14
|
+
|
15
|
+
def build_conditions(dimension)
|
16
|
+
criteria.map do |condition|
|
17
|
+
[ dimension.approach[:operator],
|
18
|
+
{ dimension.field => condition } ]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
data/lib/casino/store.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
module Casino
|
2
|
+
class Store
|
3
|
+
attr_accessor :collection_name
|
4
|
+
|
5
|
+
delegate :drop, :find, :indexes, :insert, to: :collection
|
6
|
+
|
7
|
+
delegate :count, :distinct, :each, :first, :limit, :remove, :remove_all,
|
8
|
+
:select, :skip, :sort, :update, :update_all, :upsert, to: :query
|
9
|
+
|
10
|
+
delegate :where, :in, to: :criteria
|
11
|
+
|
12
|
+
def initialize(collection_name)
|
13
|
+
self.collection_name = collection_name
|
14
|
+
end
|
15
|
+
|
16
|
+
def collection
|
17
|
+
@collection ||= session[collection_name.to_sym]
|
18
|
+
end
|
19
|
+
|
20
|
+
def query
|
21
|
+
@query ||= collection.find
|
22
|
+
end
|
23
|
+
|
24
|
+
def merge(*documents)
|
25
|
+
documents.each do |document|
|
26
|
+
criteria = find _id: document['_id']
|
27
|
+
criteria.upsert document
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def criteria
|
32
|
+
@criteria ||= build_criteria
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def session
|
38
|
+
@session ||= Mongoid.default_session
|
39
|
+
end
|
40
|
+
|
41
|
+
def build_criteria
|
42
|
+
klass = Class.new
|
43
|
+
klass.send(:include, Mongoid::Document)
|
44
|
+
klass.store_in collection: collection_name
|
45
|
+
klass.scoped
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
random_number = -> { rand(3) + 1 }
|
2
|
+
|
3
|
+
Fabricator(:model) do
|
4
|
+
created_at { Date.today }
|
5
|
+
source { %w(Google Facebook Twitter).shuffle.first }
|
6
|
+
end
|
7
|
+
|
8
|
+
Fabricator(:model_with_notes, from: :model) do
|
9
|
+
after_create do |model|
|
10
|
+
random_number.call.times { model.notes << Fabricate(:note, model: model) }
|
11
|
+
end
|
12
|
+
end
|