daodalus 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
data/lib/daodalus.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'mongo'
|
2
|
+
require 'optional'
|
3
|
+
|
4
|
+
require 'daodalus/connection'
|
5
|
+
require 'daodalus/invalid_connection_error'
|
6
|
+
require 'daodalus/invalid_query_error'
|
7
|
+
|
8
|
+
require 'daodalus/dsl/query'
|
9
|
+
require 'daodalus/dsl/clause'
|
10
|
+
require 'daodalus/dsl/matchers'
|
11
|
+
|
12
|
+
require 'daodalus/dsl/queries'
|
13
|
+
require 'daodalus/dsl/updates'
|
14
|
+
|
15
|
+
require 'daodalus/dsl/where'
|
16
|
+
require 'daodalus/dsl/select'
|
17
|
+
require 'daodalus/dsl/update'
|
18
|
+
|
19
|
+
require 'daodalus/dsl/aggregations'
|
20
|
+
require 'daodalus/dsl/aggregation/match'
|
21
|
+
require 'daodalus/dsl/aggregation/group'
|
22
|
+
require 'daodalus/dsl/aggregation/project'
|
23
|
+
require 'daodalus/dsl/aggregation/limit'
|
24
|
+
require 'daodalus/dsl/aggregation/skip'
|
25
|
+
require 'daodalus/dsl/aggregation/sort'
|
26
|
+
require 'daodalus/dsl/aggregation/unwind'
|
27
|
+
|
28
|
+
require 'daodalus/dsl'
|
29
|
+
require 'daodalus/dao'
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Daodalus
|
2
|
+
|
3
|
+
module Connection
|
4
|
+
extend self
|
5
|
+
|
6
|
+
def register(connection, name='default')
|
7
|
+
connections[name.to_s] = connection
|
8
|
+
end
|
9
|
+
|
10
|
+
def fetch(name='default')
|
11
|
+
connections.fetch(name.to_s) { raise InvalidConnectionError.new(name) }
|
12
|
+
end
|
13
|
+
|
14
|
+
def connections
|
15
|
+
@connections ||= {}
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
data/lib/daodalus/dao.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'delegate'
|
2
|
+
|
3
|
+
module Daodalus
|
4
|
+
class DAO
|
5
|
+
include DSL
|
6
|
+
extend Forwardable
|
7
|
+
|
8
|
+
def initialize(db, collection, connection=:default)
|
9
|
+
@db = db
|
10
|
+
@collection = collection
|
11
|
+
@connection = connection
|
12
|
+
end
|
13
|
+
|
14
|
+
def coll
|
15
|
+
@coll ||= Daodalus::Connection.fetch(connection)[db.to_s][collection.to_s]
|
16
|
+
end
|
17
|
+
|
18
|
+
delegate [
|
19
|
+
:find,
|
20
|
+
:update,
|
21
|
+
:insert,
|
22
|
+
:save,
|
23
|
+
:remove,
|
24
|
+
:count,
|
25
|
+
:aggregate
|
26
|
+
] => :coll
|
27
|
+
|
28
|
+
def find_one(*args)
|
29
|
+
Option[coll.find_one(*args)]
|
30
|
+
end
|
31
|
+
|
32
|
+
def find_and_modify(*args)
|
33
|
+
Option[coll.find_and_modify(*args)]
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
attr_reader :db, :collection, :connection
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
data/lib/daodalus/dsl.rb
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
module Daodalus
|
2
|
+
module DSL
|
3
|
+
module Aggregation
|
4
|
+
class Group
|
5
|
+
include Aggregations
|
6
|
+
|
7
|
+
def initialize(dao, aggregations, id, values)
|
8
|
+
@dao = dao
|
9
|
+
@aggregations = aggregations
|
10
|
+
@id = id
|
11
|
+
@values = values
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_aggregation
|
15
|
+
{ '$group' => values.merge('_id' => id) }
|
16
|
+
end
|
17
|
+
|
18
|
+
def sum(field)
|
19
|
+
aliased '$sum' => field
|
20
|
+
end
|
21
|
+
alias_method :total, :sum
|
22
|
+
|
23
|
+
def add_to_set(field)
|
24
|
+
aliased '$addToSet' => field
|
25
|
+
end
|
26
|
+
alias_method :distinct, :add_to_set
|
27
|
+
|
28
|
+
def push(field)
|
29
|
+
aliased '$push' => field
|
30
|
+
end
|
31
|
+
alias_method :collect, :push
|
32
|
+
|
33
|
+
def first(field)
|
34
|
+
aliased '$first' => field
|
35
|
+
end
|
36
|
+
|
37
|
+
def last(field)
|
38
|
+
aliased '$last' => field
|
39
|
+
end
|
40
|
+
|
41
|
+
def max(field)
|
42
|
+
aliased '$max' => field
|
43
|
+
end
|
44
|
+
|
45
|
+
def min(field)
|
46
|
+
aliased '$min' => field
|
47
|
+
end
|
48
|
+
|
49
|
+
def avg(field)
|
50
|
+
aliased '$avg' => field
|
51
|
+
end
|
52
|
+
alias_method :average, :avg
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def id
|
57
|
+
case @id
|
58
|
+
when Symbol then @id.to_s
|
59
|
+
when Hash then @id.reduce({}) {|acc, (a,b)| acc.merge(a.to_s => b.to_s) }
|
60
|
+
else @id
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def aliased clause
|
65
|
+
Alias.new do |aka|
|
66
|
+
Group.new(dao, aggregations, id, values.merge(aka => clause))
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
attr_reader :dao, :aggregations, :values
|
71
|
+
|
72
|
+
class Alias
|
73
|
+
def initialize(&block)
|
74
|
+
@block = block
|
75
|
+
end
|
76
|
+
|
77
|
+
def as(aka)
|
78
|
+
block.call(aka)
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
|
83
|
+
attr_reader :block
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Daodalus
|
2
|
+
module DSL
|
3
|
+
module Aggregation
|
4
|
+
class Limit
|
5
|
+
include Aggregations
|
6
|
+
|
7
|
+
def initialize(dao, aggregations, limit)
|
8
|
+
@dao = dao
|
9
|
+
@aggregations = aggregations
|
10
|
+
@limit = limit
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_aggregation
|
14
|
+
{ '$limit' => limit }
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
attr_reader :dao, :aggregations, :limit
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Daodalus
|
2
|
+
module DSL
|
3
|
+
module Aggregation
|
4
|
+
class Match
|
5
|
+
include Matchers
|
6
|
+
include Aggregations
|
7
|
+
|
8
|
+
def initialize(dao, aggregations, query, field)
|
9
|
+
@dao = dao
|
10
|
+
@aggregations = aggregations
|
11
|
+
@query = query
|
12
|
+
@field = field
|
13
|
+
end
|
14
|
+
|
15
|
+
alias_method :and, :match
|
16
|
+
|
17
|
+
def to_aggregation
|
18
|
+
{ '$match' => query.wheres }
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def add_clause clause
|
24
|
+
Match.new(dao, aggregations, query.where(field.to_s => clause), field)
|
25
|
+
end
|
26
|
+
|
27
|
+
def add_logical_clause clause
|
28
|
+
Match.new(dao, aggregations, query.where(clause), field)
|
29
|
+
end
|
30
|
+
|
31
|
+
attr_reader :dao, :aggregations, :query, :field
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module Daodalus
|
2
|
+
module DSL
|
3
|
+
module Aggregation
|
4
|
+
class Project
|
5
|
+
include Aggregations
|
6
|
+
|
7
|
+
def initialize(dao, aggregations, projection = {}, keys)
|
8
|
+
@dao = dao
|
9
|
+
@aggregations = aggregations
|
10
|
+
@projection = projection
|
11
|
+
@keys = keys
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_aggregation
|
15
|
+
{ '$project' => { '_id' => 0 }.merge(projection) }
|
16
|
+
end
|
17
|
+
|
18
|
+
def project(*keys)
|
19
|
+
Project.new(dao, aggregations, projection, keys)
|
20
|
+
end
|
21
|
+
alias_method :and, :project
|
22
|
+
|
23
|
+
def as(aka)
|
24
|
+
Project.new(dao, aggregations, @projection, [aka => keys.first])
|
25
|
+
end
|
26
|
+
|
27
|
+
def eq(*others)
|
28
|
+
Project.new(dao, aggregations, @projection, ['$eq' => keys + others])
|
29
|
+
end
|
30
|
+
|
31
|
+
def add(*others)
|
32
|
+
Project.new(dao, aggregations, @projection, ['$add' => keys + others])
|
33
|
+
end
|
34
|
+
alias_method :plus, :add
|
35
|
+
|
36
|
+
def divide(other)
|
37
|
+
Project.new(dao, aggregations, @projection, ['$divide' => keys + [other]])
|
38
|
+
end
|
39
|
+
alias_method :divided_by, :divide
|
40
|
+
|
41
|
+
def multiply(other)
|
42
|
+
Project.new(dao, aggregations, @projection, ['$multiply' => keys + [other]])
|
43
|
+
end
|
44
|
+
alias_method :multiplied_by, :multiply
|
45
|
+
|
46
|
+
def subtract(other)
|
47
|
+
Project.new(dao, aggregations, @projection, ['$subtract' => keys + [other]])
|
48
|
+
end
|
49
|
+
alias_method :minus, :subtract
|
50
|
+
|
51
|
+
def mod(other)
|
52
|
+
Project.new(dao, aggregations, @projection, ['$mod' => keys + [other]])
|
53
|
+
end
|
54
|
+
|
55
|
+
protected
|
56
|
+
|
57
|
+
def projection
|
58
|
+
keys.reduce(@projection) do |acc, k|
|
59
|
+
case k
|
60
|
+
when Hash then acc.merge(hashify k)
|
61
|
+
else acc.merge(k.to_s => 1)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def hashify(key)
|
69
|
+
case key
|
70
|
+
when Hash then key.reduce({}) { |acc, (k,v)| acc.merge(k => hashify(v)) }
|
71
|
+
when Project then hashify key.projection
|
72
|
+
else key
|
73
|
+
end
|
74
|
+
end
|
75
|
+
attr_reader :dao, :aggregations, :keys
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Daodalus
|
2
|
+
module DSL
|
3
|
+
module Aggregation
|
4
|
+
class Skip
|
5
|
+
include Aggregations
|
6
|
+
|
7
|
+
def initialize(dao, aggregations, skip)
|
8
|
+
@dao = dao
|
9
|
+
@aggregations = aggregations
|
10
|
+
@skip = skip
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_aggregation
|
14
|
+
{ '$skip' => skip }
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
attr_reader :dao, :aggregations, :skip
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Daodalus
|
2
|
+
module DSL
|
3
|
+
module Aggregation
|
4
|
+
class Sort
|
5
|
+
include Aggregations
|
6
|
+
|
7
|
+
def initialize(dao, aggregations, keys)
|
8
|
+
@dao = dao
|
9
|
+
@aggregations = aggregations
|
10
|
+
@keys = keys
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_aggregation
|
14
|
+
{ '$sort' => keys }
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def keys
|
20
|
+
@keys.reduce({}) do |acc, (k,v)|
|
21
|
+
acc.merge(k => ([-1, :desc, 'desc'].include?(v) ? -1 : 1))
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
attr_reader :dao, :aggregations
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Daodalus
|
2
|
+
module DSL
|
3
|
+
module Aggregation
|
4
|
+
class Unwind
|
5
|
+
include Aggregations
|
6
|
+
|
7
|
+
def initialize(dao, aggregations, field)
|
8
|
+
@dao = dao
|
9
|
+
@aggregations = aggregations
|
10
|
+
@field = field
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_aggregation
|
14
|
+
{ '$unwind' => "$#{field}" }
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
attr_reader :dao, :aggregations, :field
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Daodalus
|
2
|
+
module DSL
|
3
|
+
module Aggregations
|
4
|
+
|
5
|
+
def aggregate
|
6
|
+
dao.aggregate(pipeline)
|
7
|
+
end
|
8
|
+
|
9
|
+
def match(field=nil)
|
10
|
+
Aggregation::Match.new(dao, pipeline, Query.new, field)
|
11
|
+
end
|
12
|
+
|
13
|
+
def group(keys)
|
14
|
+
Aggregation::Group.new(dao, pipeline, keys, {})
|
15
|
+
end
|
16
|
+
alias_method :group_by, :group
|
17
|
+
|
18
|
+
def project(*keys)
|
19
|
+
Aggregation::Project.new(dao, pipeline, keys)
|
20
|
+
end
|
21
|
+
|
22
|
+
def limit(limit)
|
23
|
+
Aggregation::Limit.new(dao, pipeline, limit)
|
24
|
+
end
|
25
|
+
|
26
|
+
def skip(skip)
|
27
|
+
Aggregation::Skip.new(dao, pipeline, skip)
|
28
|
+
end
|
29
|
+
|
30
|
+
def sort(sort)
|
31
|
+
Aggregation::Sort.new(dao, pipeline, sort)
|
32
|
+
end
|
33
|
+
|
34
|
+
def unwind(field)
|
35
|
+
Aggregation::Unwind.new(dao, pipeline, field)
|
36
|
+
end
|
37
|
+
|
38
|
+
def pipeline
|
39
|
+
aggregations + [to_aggregation]
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|