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.
Files changed (53) hide show
  1. data/.gitignore +20 -0
  2. data/.ruby-gemset +1 -0
  3. data/.ruby-version +1 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +93 -0
  7. data/Rakefile +9 -0
  8. data/casino.gemspec +30 -0
  9. data/lib/casino.rb +13 -0
  10. data/lib/casino/collection.rb +195 -0
  11. data/lib/casino/dimension.rb +11 -0
  12. data/lib/casino/focus.rb +26 -0
  13. data/lib/casino/intersection.rb +30 -0
  14. data/lib/casino/intersection/match/all.rb +29 -0
  15. data/lib/casino/intersection/match/base.rb +49 -0
  16. data/lib/casino/intersection/match/equivalence.rb +25 -0
  17. data/lib/casino/intersection/match/expression.rb +15 -0
  18. data/lib/casino/intersection/match/greater.rb +43 -0
  19. data/lib/casino/intersection/match/include.rb +15 -0
  20. data/lib/casino/intersection/match/lesser.rb +31 -0
  21. data/lib/casino/intersection/match/recurse.rb +19 -0
  22. data/lib/casino/lobby.rb +21 -0
  23. data/lib/casino/projection.rb +76 -0
  24. data/lib/casino/query.rb +23 -0
  25. data/lib/casino/question.rb +9 -0
  26. data/lib/casino/store.rb +49 -0
  27. data/lib/casino/version.rb +3 -0
  28. data/spec/fabricators/model_fabricator.rb +12 -0
  29. data/spec/fabricators/note_fabricator.rb +3 -0
  30. data/spec/fixtures/collections/collection.rb +3 -0
  31. data/spec/fixtures/collections/emails_by_day.rb +28 -0
  32. data/spec/fixtures/models/model.rb +8 -0
  33. data/spec/fixtures/models/note.rb +7 -0
  34. data/spec/lib/casino/collection_spec.rb +146 -0
  35. data/spec/lib/casino/dimension_spec.rb +27 -0
  36. data/spec/lib/casino/focus_spec.rb +53 -0
  37. data/spec/lib/casino/intersection/match/all_spec.rb +24 -0
  38. data/spec/lib/casino/intersection/match/base_spec.rb +159 -0
  39. data/spec/lib/casino/intersection/match/equivalence_spec.rb +26 -0
  40. data/spec/lib/casino/intersection/match/expression_spec.rb +26 -0
  41. data/spec/lib/casino/intersection/match/greater_spec.rb +72 -0
  42. data/spec/lib/casino/intersection/match/include_spec.rb +27 -0
  43. data/spec/lib/casino/intersection/match/lesser_spec.rb +74 -0
  44. data/spec/lib/casino/intersection/match/recurse_spec.rb +24 -0
  45. data/spec/lib/casino/intersection_spec.rb +33 -0
  46. data/spec/lib/casino/lobby_spec.rb +20 -0
  47. data/spec/lib/casino/projection_spec.rb +81 -0
  48. data/spec/lib/casino/query_spec.rb +42 -0
  49. data/spec/lib/casino/question_spec.rb +10 -0
  50. data/spec/lib/casino/store_spec.rb +60 -0
  51. data/spec/spec_helper.rb +26 -0
  52. data/spec/support/mongoid.yml +6 -0
  53. 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,15 @@
1
+ module Casino
2
+ class Intersection
3
+ module Match
4
+ class Expression < Equivalence
5
+ def eligible?
6
+ field.is_a? Regexp
7
+ end
8
+
9
+ def evaluate
10
+ !(value =~ field).nil?
11
+ end
12
+ end
13
+ end
14
+ end
15
+ 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,15 @@
1
+ module Casino
2
+ class Intersection
3
+ module Match
4
+ class Include < Equivalence
5
+ def eligible?
6
+ key == "$in"
7
+ end
8
+
9
+ def evaluate
10
+ field.include?(value)
11
+ end
12
+ end
13
+ end
14
+ end
15
+ 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
@@ -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
@@ -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
@@ -0,0 +1,9 @@
1
+ module Casino
2
+ class Question
3
+ attr_accessor :name, :answer
4
+ def initialize(name, answer)
5
+ self.name = name
6
+ self.answer = answer
7
+ end
8
+ end
9
+ end
@@ -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,3 @@
1
+ module Casino
2
+ VERSION = "0.0.1"
3
+ 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
@@ -0,0 +1,3 @@
1
+ Fabricator(:note) do
2
+ views { rand(3) + 1 }
3
+ end