daodalus 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. data/.gitignore +7 -0
  2. data/.travis.yml +7 -0
  3. data/Gemfile +10 -0
  4. data/Gemfile.lock +65 -0
  5. data/LICENCE.md +9 -0
  6. data/README.md +316 -0
  7. data/Rakefile +8 -0
  8. data/daodalus.gemspec +23 -0
  9. data/lib/daodalus.rb +29 -0
  10. data/lib/daodalus/connection.rb +19 -0
  11. data/lib/daodalus/dao.rb +41 -0
  12. data/lib/daodalus/dsl.rb +21 -0
  13. data/lib/daodalus/dsl/aggregation/group.rb +88 -0
  14. data/lib/daodalus/dsl/aggregation/limit.rb +23 -0
  15. data/lib/daodalus/dsl/aggregation/match.rb +35 -0
  16. data/lib/daodalus/dsl/aggregation/project.rb +79 -0
  17. data/lib/daodalus/dsl/aggregation/skip.rb +23 -0
  18. data/lib/daodalus/dsl/aggregation/sort.rb +29 -0
  19. data/lib/daodalus/dsl/aggregation/unwind.rb +23 -0
  20. data/lib/daodalus/dsl/aggregations.rb +44 -0
  21. data/lib/daodalus/dsl/clause.rb +19 -0
  22. data/lib/daodalus/dsl/matchers.rb +87 -0
  23. data/lib/daodalus/dsl/queries.rb +29 -0
  24. data/lib/daodalus/dsl/query.rb +46 -0
  25. data/lib/daodalus/dsl/select.rb +43 -0
  26. data/lib/daodalus/dsl/update.rb +86 -0
  27. data/lib/daodalus/dsl/updates.rb +71 -0
  28. data/lib/daodalus/dsl/where.rb +30 -0
  29. data/lib/daodalus/invalid_connection_error.rb +7 -0
  30. data/lib/daodalus/invalid_query_error.rb +4 -0
  31. data/spec/lib/daodalus/connection_spec.rb +22 -0
  32. data/spec/lib/daodalus/dao_spec.rb +34 -0
  33. data/spec/lib/daodalus/dsl/aggregation/group_spec.rb +92 -0
  34. data/spec/lib/daodalus/dsl/aggregation/limit_spec.rb +22 -0
  35. data/spec/lib/daodalus/dsl/aggregation/match_spec.rb +32 -0
  36. data/spec/lib/daodalus/dsl/aggregation/project_spec.rb +74 -0
  37. data/spec/lib/daodalus/dsl/aggregation/skip_spec.rb +22 -0
  38. data/spec/lib/daodalus/dsl/aggregation/sort_spec.rb +36 -0
  39. data/spec/lib/daodalus/dsl/aggregation/unwind_spec.rb +24 -0
  40. data/spec/lib/daodalus/dsl/clause_spec.rb +22 -0
  41. data/spec/lib/daodalus/dsl/query_spec.rb +35 -0
  42. data/spec/lib/daodalus/dsl/select_spec.rb +46 -0
  43. data/spec/lib/daodalus/dsl/update_spec.rb +113 -0
  44. data/spec/lib/daodalus/dsl/where_spec.rb +133 -0
  45. data/spec/lib/daodalus/dsl_spec.rb +12 -0
  46. data/spec/pointless_coverage_spec.rb +9 -0
  47. data/spec/spec_helper.rb +18 -0
  48. data/spec/support/mongo_cleaner.rb +12 -0
  49. metadata +208 -0
@@ -0,0 +1,19 @@
1
+ module Daodalus
2
+ module DSL
3
+ module Clause
4
+
5
+ def to_query
6
+ query.wheres
7
+ end
8
+
9
+ def to_projection
10
+ query.selects
11
+ end
12
+
13
+ def to_update
14
+ query.updates
15
+ end
16
+
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,87 @@
1
+ module Daodalus
2
+ module DSL
3
+ module Matchers
4
+
5
+ def eq value
6
+ add_clause value
7
+ end
8
+ alias_method :equals, :eq
9
+
10
+ def ne value
11
+ add_clause '$ne' => value
12
+ end
13
+ alias_method :not_equal, :ne
14
+
15
+ def lt value
16
+ add_clause '$lt' => value
17
+ end
18
+ alias_method :less_than, :lt
19
+
20
+ def gt value
21
+ add_clause '$gt' => value
22
+ end
23
+ alias_method :greater_than, :gt
24
+
25
+ def lte value
26
+ add_clause '$lte' => value
27
+ end
28
+ alias_method :less_than_or_equal, :lte
29
+
30
+ def gte value
31
+ add_clause '$gte' => value
32
+ end
33
+ alias_method :greater_than_or_equal, :gte
34
+
35
+ def in *values
36
+ add_clause '$in' => values
37
+ end
38
+
39
+ def nin *values
40
+ add_clause '$nin' => values
41
+ end
42
+ alias_method :not_in, :nin
43
+
44
+ def all *values
45
+ add_clause '$all' => values
46
+ end
47
+
48
+ def size value
49
+ add_clause '$size' => value
50
+ end
51
+
52
+ def exists value=true
53
+ add_clause '$exists' => value
54
+ end
55
+
56
+ def does_not_exist *values
57
+ exists false
58
+ end
59
+
60
+ def not
61
+ define_singleton_method :add_clause do |clause|
62
+ add_logical_clause field.to_s => { '$not' => clause }
63
+ end
64
+ define_singleton_method :eq do |value|
65
+ add_logical_clause field.to_s => { '$ne' => value}
66
+ end
67
+ self
68
+ end
69
+
70
+ def any *clauses
71
+ add_logical_clause '$or' => clauses.map(&:to_query)
72
+ end
73
+ alias_method :or, :any
74
+
75
+ def none *clauses
76
+ add_logical_clause '$nor' => clauses.map(&:to_query)
77
+ end
78
+ alias_method :nor, :none
79
+
80
+ def elem_match clause
81
+ add_clause '$elemMatch' => clause.to_query
82
+ end
83
+
84
+ end
85
+ end
86
+ end
87
+
@@ -0,0 +1,29 @@
1
+ module Daodalus
2
+ module DSL
3
+ module Queries
4
+
5
+ def find(options = {})
6
+ options = options.merge(fields: query.selects) if query.has_selects?
7
+ dao.find(query.wheres, options)
8
+ end
9
+
10
+ def find_one(options = {})
11
+ options = options.merge(fields: query.selects) if query.has_selects?
12
+ dao.find_one(query.wheres, options)
13
+ end
14
+
15
+ def where field=nil
16
+ if field.is_a? Hash
17
+ Where.new(dao, query.where(field), nil)
18
+ else
19
+ Where.new(dao, query, field)
20
+ end
21
+ end
22
+
23
+ def select *fields
24
+ Select.new(dao, query, fields)
25
+ end
26
+
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,46 @@
1
+ module Daodalus
2
+ module DSL
3
+ class Query
4
+
5
+ def initialize(wheres={}, selects={}, updates={})
6
+ @wheres = wheres
7
+ @selects = selects
8
+ @updates = updates
9
+ end
10
+ attr_reader :wheres, :updates
11
+
12
+ def where clause
13
+ Query.new(add_where(clause), selects, updates)
14
+ end
15
+
16
+ def update clause
17
+ Query.new(wheres, selects, updates.merge(clause))
18
+ end
19
+
20
+ def select clause
21
+ Query.new(wheres, selects.merge(clause), updates)
22
+ end
23
+
24
+ def selects
25
+ @selects.empty? ? @selects : {'_id' => 0}.merge(@selects)
26
+ end
27
+
28
+ def has_selects?
29
+ !selects.empty?
30
+ end
31
+
32
+ private
33
+
34
+ def add_where clause
35
+ wheres.merge(clause) do |f, a, b|
36
+ if a.respond_to?(:merge) && b.respond_to?(:merge)
37
+ a.merge(b)
38
+ else
39
+ raise InvalidQueryError.new("Invalid Query: Cannot merge clauses '#{a}' and '#{b}' for field '#{f}'")
40
+ end
41
+ end
42
+ end
43
+
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,43 @@
1
+ module Daodalus
2
+ module DSL
3
+ class Select
4
+ include Clause
5
+ include Queries
6
+
7
+ def initialize(dao, query, fields)
8
+ @dao = dao
9
+ @query = query
10
+ @fields = fields
11
+ end
12
+
13
+ alias_method :and, :select
14
+
15
+ def by_position
16
+ raise InvalidQueryError, "Too many fields for positional operator: #{fields.inspect}" if fields.size > 1
17
+ Select.new(dao, @query.select("#{fields.first}.$" => 1), [])
18
+ end
19
+ alias_method :positional, :by_position
20
+
21
+ def slice skip=false, limit
22
+ raise InvalidQueryError, "Too many fields for slice operator: #{fields.inspect}" if fields.size > 1
23
+ if skip
24
+ Select.new(dao, @query.select(fields.first.to_s => { '$slice' => [skip, limit]}), [])
25
+ else
26
+ Select.new(dao, @query.select(fields.first.to_s => { '$slice' => limit}), [])
27
+ end
28
+ end
29
+
30
+ def elem_match clause
31
+ Select.new(dao, @query.select(fields.first.to_s => { '$elemMatch' => clause.to_query}), [])
32
+ end
33
+
34
+ private
35
+
36
+ def query
37
+ @query.select(fields.reduce({}) { |acc, f| acc.merge(f.to_s => 1) })
38
+ end
39
+
40
+ attr_reader :dao, :fields
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,86 @@
1
+ module Daodalus
2
+ module DSL
3
+ class Update
4
+ include Clause
5
+ include Queries
6
+ include Updates
7
+
8
+ def initialize(dao, query)
9
+ @dao = dao
10
+ @query = query
11
+ end
12
+
13
+ def set(fields)
14
+ with_clause '$set' => fields
15
+ end
16
+
17
+ def unset(fields)
18
+ with_clause '$unset' => fields.reduce({}) { |acc, f| acc.merge(f => 1) }
19
+ end
20
+
21
+ def inc(field, amount)
22
+ with_clause '$inc' => { field => amount }
23
+ end
24
+
25
+ def dec(field, amount)
26
+ with_clause '$inc' => { field => -amount }
27
+ end
28
+
29
+ def rename(field, value)
30
+ with_clause '$rename' => { field => value.to_s }
31
+ end
32
+
33
+ def push(field, values)
34
+ if values.length == 1
35
+ with_clause '$push' => { field => values.first }
36
+ else
37
+ push_all field, values
38
+ end
39
+ end
40
+
41
+ def push_all(field, values)
42
+ with_clause '$pushAll' => { field => values }
43
+ end
44
+
45
+ def add_to_set(field, values)
46
+ if values.length == 1
47
+ with_clause '$addToSet' => { field => values.first }
48
+ else
49
+ add_each_to_set field, values
50
+ end
51
+ end
52
+
53
+ def add_each_to_set(field, values)
54
+ with_clause '$addToSet' => { field => { '$each' => values } }
55
+ end
56
+
57
+ def pop_first(field)
58
+ with_clause '$pop' => { field => -1 }
59
+ end
60
+
61
+ def pop_last(field)
62
+ with_clause '$pop' => { field => 1 }
63
+ end
64
+
65
+ def pull(field, values)
66
+ if values.length == 1
67
+ with_clause '$pull' => { field => values.first }
68
+ else
69
+ pull_all field, values
70
+ end
71
+ end
72
+
73
+ def pull_all(field, values)
74
+ with_clause '$pullAll' => { field => values }
75
+ end
76
+
77
+ private
78
+
79
+ def with_clause clause
80
+ Update.new(dao, query.update(clause))
81
+ end
82
+
83
+ attr_reader :dao, :query
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,71 @@
1
+ module Daodalus
2
+ module DSL
3
+ module Updates
4
+
5
+ def update(options = {})
6
+ dao.update(query.wheres, query.updates, options)
7
+ end
8
+
9
+ def upsert(options = {})
10
+ update(options.merge(upsert: true))
11
+ end
12
+
13
+ def find_and_modify(options = {})
14
+ dao.find_and_modify(options.merge(query: query.wheres, update: query.updates))
15
+ end
16
+
17
+ def set(fields)
18
+ Update.new(dao, query).set(fields)
19
+ end
20
+
21
+ def unset(*fields)
22
+ Update.new(dao, query).unset(fields)
23
+ end
24
+
25
+ def inc(field, amount=1)
26
+ Update.new(dao, query).inc(field, amount)
27
+ end
28
+
29
+ def dec(field, amount=1)
30
+ Update.new(dao, query).dec(field, amount)
31
+ end
32
+
33
+ def rename(field, value)
34
+ Update.new(dao, query).rename(field, value)
35
+ end
36
+
37
+ def push(field, *values)
38
+ Update.new(dao, query).push(field, values)
39
+ end
40
+
41
+ def push_all(field, values)
42
+ Update.new(dao, query).push_all(field, values)
43
+ end
44
+
45
+ def add_to_set(field, *values)
46
+ Update.new(dao, query).add_to_set(field, values)
47
+ end
48
+
49
+ def add_each_to_set(field, values)
50
+ Update.new(dao, query).add_each_to_set(field, values)
51
+ end
52
+
53
+ def pop_first(field)
54
+ Update.new(dao, query).pop_first(field)
55
+ end
56
+
57
+ def pop_last(field)
58
+ Update.new(dao, query).pop_last(field)
59
+ end
60
+
61
+ def pull(field, *values)
62
+ Update.new(dao, query).pull(field, values)
63
+ end
64
+
65
+ def pull_all(field, values)
66
+ Update.new(dao, query).pull_all(field, values)
67
+ end
68
+
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,30 @@
1
+ module Daodalus
2
+ module DSL
3
+ class Where
4
+ include Clause
5
+ include Updates
6
+ include Queries
7
+ include Matchers
8
+
9
+ def initialize(dao, query, field)
10
+ @dao = dao
11
+ @query = query
12
+ @field = field
13
+ end
14
+
15
+ alias_method :and, :where
16
+
17
+ private
18
+
19
+ def add_clause clause
20
+ Where.new(dao, query.where(field.to_s => clause), field)
21
+ end
22
+
23
+ def add_logical_clause clause
24
+ Where.new(dao, query.where(clause), field)
25
+ end
26
+
27
+ attr_reader :dao, :query, :field
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,7 @@
1
+ module Daodalus
2
+ class InvalidConnectionError < StandardError
3
+ def initialize(name)
4
+ super("Daodalus::InvalidConnectionError - #{name.inspect}")
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,4 @@
1
+ module Daodalus
2
+ class InvalidQueryError < StandardError
3
+ end
4
+ end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ module Daodalus
4
+ describe Connection do
5
+
6
+ let (:conn) { Mongo::MongoClient.new('localhost', 27017, pool_size: 5) }
7
+
8
+ it 'allows connections to be registered and fetched by name' do
9
+ Daodalus::Connection.register(conn, :animalhouse)
10
+ Daodalus::Connection.fetch(:animalhouse).should eq conn
11
+ end
12
+
13
+ it 'allows the default connection to be registered and fetched without a name' do
14
+ Daodalus::Connection.register(conn)
15
+ Daodalus::Connection.fetch.should eq conn
16
+ end
17
+
18
+ it 'raises an invalid connection error if asked for a non-existent connection' do
19
+ expect { Daodalus::Connection.fetch(:wrong) }.to raise_error InvalidConnectionError
20
+ end
21
+ end
22
+ end