daodalus 0.1.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 +7 -0
- data/.travis.yml +7 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +65 -0
- data/LICENCE.md +9 -0
- data/README.md +316 -0
- data/Rakefile +8 -0
- data/daodalus.gemspec +23 -0
- data/lib/daodalus.rb +29 -0
- data/lib/daodalus/connection.rb +19 -0
- data/lib/daodalus/dao.rb +41 -0
- data/lib/daodalus/dsl.rb +21 -0
- data/lib/daodalus/dsl/aggregation/group.rb +88 -0
- data/lib/daodalus/dsl/aggregation/limit.rb +23 -0
- data/lib/daodalus/dsl/aggregation/match.rb +35 -0
- data/lib/daodalus/dsl/aggregation/project.rb +79 -0
- data/lib/daodalus/dsl/aggregation/skip.rb +23 -0
- data/lib/daodalus/dsl/aggregation/sort.rb +29 -0
- data/lib/daodalus/dsl/aggregation/unwind.rb +23 -0
- data/lib/daodalus/dsl/aggregations.rb +44 -0
- data/lib/daodalus/dsl/clause.rb +19 -0
- data/lib/daodalus/dsl/matchers.rb +87 -0
- data/lib/daodalus/dsl/queries.rb +29 -0
- data/lib/daodalus/dsl/query.rb +46 -0
- data/lib/daodalus/dsl/select.rb +43 -0
- data/lib/daodalus/dsl/update.rb +86 -0
- data/lib/daodalus/dsl/updates.rb +71 -0
- data/lib/daodalus/dsl/where.rb +30 -0
- data/lib/daodalus/invalid_connection_error.rb +7 -0
- data/lib/daodalus/invalid_query_error.rb +4 -0
- data/spec/lib/daodalus/connection_spec.rb +22 -0
- data/spec/lib/daodalus/dao_spec.rb +34 -0
- data/spec/lib/daodalus/dsl/aggregation/group_spec.rb +92 -0
- data/spec/lib/daodalus/dsl/aggregation/limit_spec.rb +22 -0
- data/spec/lib/daodalus/dsl/aggregation/match_spec.rb +32 -0
- data/spec/lib/daodalus/dsl/aggregation/project_spec.rb +74 -0
- data/spec/lib/daodalus/dsl/aggregation/skip_spec.rb +22 -0
- data/spec/lib/daodalus/dsl/aggregation/sort_spec.rb +36 -0
- data/spec/lib/daodalus/dsl/aggregation/unwind_spec.rb +24 -0
- data/spec/lib/daodalus/dsl/clause_spec.rb +22 -0
- data/spec/lib/daodalus/dsl/query_spec.rb +35 -0
- data/spec/lib/daodalus/dsl/select_spec.rb +46 -0
- data/spec/lib/daodalus/dsl/update_spec.rb +113 -0
- data/spec/lib/daodalus/dsl/where_spec.rb +133 -0
- data/spec/lib/daodalus/dsl_spec.rb +12 -0
- data/spec/pointless_coverage_spec.rb +9 -0
- data/spec/spec_helper.rb +18 -0
- data/spec/support/mongo_cleaner.rb +12 -0
- metadata +208 -0
@@ -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,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
|