mongo_ql 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -1
- data/bin/console +10 -0
- data/design_specs.md +9 -4
- data/lib/mongo_ql/binary_operators.rb +6 -0
- data/lib/mongo_ql/expression/ascend.rb +15 -0
- data/lib/mongo_ql/expression/descend.rb +15 -0
- data/lib/mongo_ql/expression/field_node.rb +16 -0
- data/lib/mongo_ql/expression/projection.rb +31 -0
- data/lib/mongo_ql/stage/group.rb +22 -0
- data/lib/mongo_ql/stage/lookup.rb +101 -0
- data/lib/mongo_ql/stage/match.rb +34 -0
- data/lib/mongo_ql/stage/project.rb +33 -0
- data/lib/mongo_ql/stage/sort.rb +28 -0
- data/lib/mongo_ql/stage/unwind.rb +21 -0
- data/lib/mongo_ql/stage.rb +10 -0
- data/lib/mongo_ql/stage_context.rb +75 -0
- data/lib/mongo_ql/string_operators.rb +6 -0
- data/lib/mongo_ql/version.rb +1 -1
- data/lib/mongo_ql.rb +45 -1
- data/mongo_ql.gemspec +2 -0
- metadata +28 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 39d6acd8e471a93e4b6598473110d45935c2f17a1bae9ac2c65435669cd054fb
|
4
|
+
data.tar.gz: 0b1efe2e91c015963e9cd0f90b291d14b2b2d0cff55f0c02a3a646327b349ca2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ae59e895897c0c23d05b1ad1d2063b0b5f543712876abdd1bb2edd1c75b28dc69686d0dfc1a49c049e61a983920a3e879964a1bf927327a19454377ebcc180c8
|
7
|
+
data.tar.gz: 47d606ac87f2c577cd2ea0cb16915f883cafa393b32bd44ccc6a54969fd14404703fff0a5ecfd1928c439d123c58a5dc2966f2553ce73e1ce91f638876a3d5da
|
data/.gitignore
CHANGED
data/bin/console
CHANGED
@@ -3,5 +3,15 @@
|
|
3
3
|
require "bundler/setup"
|
4
4
|
require "./lib/mongo_ql"
|
5
5
|
|
6
|
+
include MongoQL
|
7
|
+
|
8
|
+
define_singleton_method(:method_missing) do |m, *_args, &_block|
|
9
|
+
MongoQL::Expression::FieldNode.new(m)
|
10
|
+
end
|
11
|
+
|
12
|
+
define_singleton_method(:aggregate) do |*variables, &block|
|
13
|
+
MongoQL.compose(*variables, &block)
|
14
|
+
end
|
15
|
+
|
6
16
|
require "irb"
|
7
17
|
IRB.start
|
data/design_specs.md
CHANGED
@@ -16,9 +16,9 @@ Order.where { total >= If(currency == "CAD", 100, 80) }
|
|
16
16
|
# Aggregation Pipeline DSL
|
17
17
|
```ruby
|
18
18
|
Order.all.mongo_ql do
|
19
|
-
join Customer,
|
20
|
-
:customer_id
|
21
|
-
:
|
19
|
+
join Customer,
|
20
|
+
on: customer_id == _id.to_id,
|
21
|
+
as: customers
|
22
22
|
|
23
23
|
join Shipping, :as => shippings do
|
24
24
|
match order_id == doc._id,
|
@@ -26,7 +26,7 @@ Order.all.mongo_ql do
|
|
26
26
|
end
|
27
27
|
|
28
28
|
match province == "ON"
|
29
|
-
|
29
|
+
|
30
30
|
project :_id,
|
31
31
|
:total,
|
32
32
|
:customer => customers.name,
|
@@ -35,6 +35,11 @@ Order.all.mongo_ql do
|
|
35
35
|
group customer,
|
36
36
|
:total => total.sum,
|
37
37
|
:total_tax => tax.sum * 5
|
38
|
+
|
39
|
+
sort_by age.desc
|
40
|
+
|
41
|
+
page 1
|
42
|
+
per 10
|
38
43
|
end
|
39
44
|
|
40
45
|
# The above aggregation is equivalent to the following mognodb pipeline
|
@@ -8,11 +8,17 @@ module MongoQL
|
|
8
8
|
"*": "$multiply",
|
9
9
|
"/": "$divide",
|
10
10
|
">": "$gt",
|
11
|
+
"gt?": "$gt",
|
11
12
|
"<": "$lt",
|
13
|
+
"lt?": "$lt",
|
12
14
|
">=": "$gte",
|
15
|
+
"gte?": "$gte",
|
13
16
|
"<=": "$lte",
|
17
|
+
"lte?": "$lte",
|
14
18
|
"!=": "$ne",
|
19
|
+
"neq?": "$ne",
|
15
20
|
"==": "$eq",
|
21
|
+
"eq?": "$eq",
|
16
22
|
"&": "$and",
|
17
23
|
"|": "$or",
|
18
24
|
"%": "$mod",
|
@@ -19,5 +19,21 @@ module MongoQL
|
|
19
19
|
def to_ast
|
20
20
|
"$#{field_name}"
|
21
21
|
end
|
22
|
+
|
23
|
+
def to_s
|
24
|
+
field_name.to_s
|
25
|
+
end
|
26
|
+
|
27
|
+
def name
|
28
|
+
field_name.to_s
|
29
|
+
end
|
30
|
+
|
31
|
+
def dsc
|
32
|
+
Expression::Descend.new(self)
|
33
|
+
end
|
34
|
+
|
35
|
+
def asc
|
36
|
+
Expression::Ascend.new(self)
|
37
|
+
end
|
22
38
|
end
|
23
39
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MongoQL
|
4
|
+
class Expression::Projection < Expression
|
5
|
+
attr_accessor :field, :expression
|
6
|
+
|
7
|
+
def initialize(field, expression = 1)
|
8
|
+
@expression = case expression
|
9
|
+
when 0, 1
|
10
|
+
expression
|
11
|
+
when Expression::FieldNode
|
12
|
+
expression
|
13
|
+
else
|
14
|
+
raise ArgumentError, "#{expression&.inspect} is not a valid project expression"
|
15
|
+
end
|
16
|
+
|
17
|
+
@field = case field
|
18
|
+
when String, Symbol
|
19
|
+
Expression::FieldNode.new(field)
|
20
|
+
when Expression::FieldNode
|
21
|
+
field
|
22
|
+
else
|
23
|
+
raise ArgumentError, "#{field&.inspect} is not a valid project field"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_ast
|
28
|
+
{ field.to_s => expression }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MongoQL
|
4
|
+
class Stage::Group < Stage
|
5
|
+
EXPRESSION_TO_AST_MAPPER = proc { |v| v.is_a?(Expression) ? v.to_ast : v }
|
6
|
+
|
7
|
+
attr_accessor :by, :fields
|
8
|
+
|
9
|
+
def initialize(by, arrow_fields = {}, **fields)
|
10
|
+
@by = by
|
11
|
+
@fields = fields.transform_keys(&:to_s).merge(arrow_fields.transform_keys(&:to_s))
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_ast
|
15
|
+
{
|
16
|
+
"$group" => {
|
17
|
+
"_id" => by.to_ast,
|
18
|
+
}.merge(fields.transform_values(&EXPRESSION_TO_AST_MAPPER))
|
19
|
+
}
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MongoQL
|
4
|
+
class Stage::Lookup < Stage
|
5
|
+
class NestedPipelineVars
|
6
|
+
attr_accessor :vars
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@vars = {}
|
10
|
+
end
|
11
|
+
|
12
|
+
def method_missing(m, *args, &block)
|
13
|
+
if is_setter?(m)
|
14
|
+
set(m, args.first)
|
15
|
+
else
|
16
|
+
get(m)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def get(name)
|
21
|
+
vars["var_#{name}"] ||= Expression::FieldNode.new(name)
|
22
|
+
Expression::FieldNode.new("$var_#{name}")
|
23
|
+
end
|
24
|
+
|
25
|
+
def set(name, val)
|
26
|
+
vars["var_#{name.to_s[0..-2]}"] = val
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
def is_setter?(method_name)
|
31
|
+
method_name.to_s.end_with?("=")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
attr_accessor :from, :condition, :as, :nested_pipeline_block, :let_vars
|
36
|
+
|
37
|
+
def initialize(from, condition = nil, on: nil, as: nil, &block)
|
38
|
+
@from = collection_name(from)
|
39
|
+
@as = new_array_name(as)
|
40
|
+
@nested_pipeline_block = block
|
41
|
+
|
42
|
+
if has_nested_pipeline?
|
43
|
+
@let_vars = NestedPipelineVars.new
|
44
|
+
else
|
45
|
+
@condition = condition_ast(condition || on)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def to_ast
|
50
|
+
lookup_expr = { "from" => from, "as" => as }
|
51
|
+
if has_nested_pipeline?
|
52
|
+
lookup_expr["pipeline"] = nested_pipeline.to_ast
|
53
|
+
lookup_expr["let"] = let_vars.vars
|
54
|
+
else
|
55
|
+
lookup_expr = lookup_expr.merge(condition)
|
56
|
+
end
|
57
|
+
{ "$lookup" => lookup_expr }
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
def has_nested_pipeline?
|
62
|
+
condition.nil? && !nested_pipeline_block.nil?
|
63
|
+
end
|
64
|
+
|
65
|
+
def nested_pipeline
|
66
|
+
sub_ctx = StageContext.new
|
67
|
+
sub_ctx.instance_exec(let_vars, &nested_pipeline_block)
|
68
|
+
sub_ctx
|
69
|
+
end
|
70
|
+
|
71
|
+
def collection_name(from)
|
72
|
+
case from
|
73
|
+
when String, Symbol
|
74
|
+
from
|
75
|
+
when Expression::FieldNode
|
76
|
+
from.to_s
|
77
|
+
else
|
78
|
+
if from&.respond_to?(:collection)
|
79
|
+
from&.collection&.name
|
80
|
+
elsif from&.respond_to?(:name)
|
81
|
+
from.name
|
82
|
+
else
|
83
|
+
raise ArgumentError, "#{from} is not a valid collection"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def condition_ast(cond)
|
89
|
+
raise ArgumentError, "#{cond.inspect} must be a valid Expression::Binary, example: _id == user_id" unless cond.is_a?(Expression::Binary)
|
90
|
+
raise ArgumentError, "#{cond.inspect} must be an 'equal' expression, example: _id == user_id" unless cond.operator == "$eq"
|
91
|
+
{
|
92
|
+
"localField" => cond&.left_node&.to_s,
|
93
|
+
"foreignField" => cond&.right_node&.to_s
|
94
|
+
}
|
95
|
+
end
|
96
|
+
|
97
|
+
def new_array_name(as)
|
98
|
+
as&.to_s
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MongoQL
|
4
|
+
class Stage::Match < Stage
|
5
|
+
attr_accessor :conditions, :field_filters
|
6
|
+
|
7
|
+
def initialize(*conds, **field_filters)
|
8
|
+
conds.each do |c|
|
9
|
+
raise ArgumentError, "#{c.inspect} is not a MongoQL::Expression" unless c.is_a?(MongoQL::Expression)
|
10
|
+
end
|
11
|
+
@conditions = conds
|
12
|
+
@field_filters = field_filters
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_ast
|
16
|
+
conds = {}
|
17
|
+
if conditions_ast
|
18
|
+
conds["$expr"] = conditions_ast
|
19
|
+
end
|
20
|
+
{ "$match" => conds.merge(field_filters) }
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
def conditions_ast
|
25
|
+
if conditions.size > 1
|
26
|
+
{ "$and" => conditions.map(&:to_ast) }
|
27
|
+
elsif conditions.size == 1
|
28
|
+
conditions[0].to_ast
|
29
|
+
else
|
30
|
+
nil
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MongoQL
|
4
|
+
class Stage::Project < Stage
|
5
|
+
attr_accessor :field_projections
|
6
|
+
|
7
|
+
def initialize(*fields)
|
8
|
+
@field_projections = fields.map do |field|
|
9
|
+
case field
|
10
|
+
when String, Symbol, Expression::FieldNode
|
11
|
+
{ field.to_s => 1 }
|
12
|
+
when Hash
|
13
|
+
field.map { |k, v| [k.to_s, to_expression(v).to_ast] }.to_h
|
14
|
+
else
|
15
|
+
raise ArgumentError, "#{field} is not a valid field mapping option"
|
16
|
+
end
|
17
|
+
end.inject({}) { |p, c| p.merge(c) }
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_ast
|
21
|
+
{ "$project" => field_projections }
|
22
|
+
end
|
23
|
+
|
24
|
+
protected
|
25
|
+
def to_expression(val)
|
26
|
+
if val.is_a?(Expression)
|
27
|
+
val
|
28
|
+
else
|
29
|
+
Expression::ValueNode.new(val)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MongoQL
|
4
|
+
class Stage::Sort < Stage
|
5
|
+
attr_accessor :fields
|
6
|
+
|
7
|
+
def initialize(*fields)
|
8
|
+
@fields = fields.map do |field|
|
9
|
+
case field
|
10
|
+
when Expression::FieldNode
|
11
|
+
field.asc
|
12
|
+
when String, Symbol
|
13
|
+
Expression::FieldNode.new(field).asc
|
14
|
+
when Expression::Ascend, Expression::Descend
|
15
|
+
field
|
16
|
+
else
|
17
|
+
raise ArgumentError, "#{field.inspect} must be in type [String, Symbol, Expression::FieldNode, Expression::Ascend, Expression::Descend]"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_ast
|
23
|
+
{
|
24
|
+
"$sort" => fields.inject({}) { |p, c| p.merge(c.to_ast) }
|
25
|
+
}
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MongoQL
|
4
|
+
class Stage::Unwind < Stage
|
5
|
+
attr_accessor :path, :allow_null
|
6
|
+
|
7
|
+
def initialize(path, allow_null: false)
|
8
|
+
@path = path.is_a?(Expression) ? path.to_ast : path
|
9
|
+
@allow_null = allow_null
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_ast
|
13
|
+
{
|
14
|
+
"$unwind" => {
|
15
|
+
"path" => path,
|
16
|
+
"preserveNullAndEmptyArrays" => allow_null
|
17
|
+
}
|
18
|
+
}
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MongoQL
|
4
|
+
class StageContext
|
5
|
+
attr_accessor :pipeline
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@pipeline = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def where(*args)
|
12
|
+
pipeline << Stage::Match.new(*args)
|
13
|
+
end
|
14
|
+
alias_method :match, :where
|
15
|
+
|
16
|
+
def add_fields(*args)
|
17
|
+
raise NotImplementedError, "add_fields is not implemented"
|
18
|
+
end
|
19
|
+
|
20
|
+
def project(*fields)
|
21
|
+
pipeline << Stage::Project.new(*fields)
|
22
|
+
end
|
23
|
+
alias_method :select, :project
|
24
|
+
|
25
|
+
def lookup(*args, &block)
|
26
|
+
pipeline << Stage::Lookup.new(*args, &block)
|
27
|
+
end
|
28
|
+
alias_method :join, :lookup
|
29
|
+
|
30
|
+
def group(*args)
|
31
|
+
pipeline << Stage::Group.new(*args)
|
32
|
+
end
|
33
|
+
|
34
|
+
def unwind(*args)
|
35
|
+
pipeline << Stage::Unwind.new(*args)
|
36
|
+
end
|
37
|
+
alias_method :flatten, :unwind
|
38
|
+
|
39
|
+
def sort(*args)
|
40
|
+
pipeline << Stage::Sort.new(*args)
|
41
|
+
end
|
42
|
+
alias_method :sort_by, :sort
|
43
|
+
|
44
|
+
def method_missing(m, *args, &block)
|
45
|
+
Expression::FieldNode.new(m)
|
46
|
+
end
|
47
|
+
|
48
|
+
def first_of(*field_expressions)
|
49
|
+
field_expressions.map do |expr|
|
50
|
+
[expr, expr.first]
|
51
|
+
end.to_h
|
52
|
+
end
|
53
|
+
|
54
|
+
def f(name)
|
55
|
+
Expression::FieldNode.new(name)
|
56
|
+
end
|
57
|
+
|
58
|
+
def v(val)
|
59
|
+
Expression::ValueNode.new(val)
|
60
|
+
end
|
61
|
+
|
62
|
+
def to_ast
|
63
|
+
stages = pipeline.map(&:to_ast)
|
64
|
+
stages.map do |stage|
|
65
|
+
stage.deep_transform_values do |v|
|
66
|
+
v.is_a?(Expression) ? v.to_ast : v
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
%w(where match project select sort flatten unwind lookup join).each do |m|
|
72
|
+
alias_method :"#{m.capitalize}", m
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
data/lib/mongo_ql/version.rb
CHANGED
data/lib/mongo_ql.rb
CHANGED
@@ -1,6 +1,36 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_support/core_ext/hash"
|
4
|
+
require "logger"
|
3
5
|
module MongoQL
|
6
|
+
class InvalidVariableAccess < StandardError; end
|
7
|
+
|
8
|
+
def self.compose(*variable_names, &block)
|
9
|
+
block_binding = block.binding
|
10
|
+
ctx = MongoQL::StageContext.new
|
11
|
+
|
12
|
+
variables = variable_names.map do |name|
|
13
|
+
[name, block_binding.local_variable_get(name)]
|
14
|
+
end.to_h
|
15
|
+
|
16
|
+
# Update injected local variables to ValueNode expressions
|
17
|
+
variable_names.each do |name|
|
18
|
+
block_binding.local_variable_set(name, Expression::ValueNode.new(variables[name]))
|
19
|
+
end
|
20
|
+
|
21
|
+
ctx.instance_exec(*variables, &block)
|
22
|
+
|
23
|
+
# Restore local variables
|
24
|
+
variable_names.each do |name|
|
25
|
+
block_binding.local_variable_set(name, variables[name])
|
26
|
+
end
|
27
|
+
|
28
|
+
ctx
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.logger
|
32
|
+
@logger ||= Logger.new($stdout)
|
33
|
+
end
|
4
34
|
end
|
5
35
|
|
6
36
|
require_relative "mongo_ql/version"
|
@@ -10,4 +40,18 @@ require_relative "mongo_ql/expression/field_node"
|
|
10
40
|
require_relative "mongo_ql/expression/value_node"
|
11
41
|
require_relative "mongo_ql/expression/method_call"
|
12
42
|
require_relative "mongo_ql/expression/binary"
|
13
|
-
require_relative "mongo_ql/expression/unary"
|
43
|
+
require_relative "mongo_ql/expression/unary"
|
44
|
+
|
45
|
+
require_relative "mongo_ql/expression/descend"
|
46
|
+
require_relative "mongo_ql/expression/ascend"
|
47
|
+
require_relative "mongo_ql/expression/projection"
|
48
|
+
|
49
|
+
require_relative "mongo_ql/stage"
|
50
|
+
require_relative "mongo_ql/stage/project"
|
51
|
+
require_relative "mongo_ql/stage/lookup"
|
52
|
+
require_relative "mongo_ql/stage/match"
|
53
|
+
require_relative "mongo_ql/stage/group"
|
54
|
+
require_relative "mongo_ql/stage/unwind"
|
55
|
+
require_relative "mongo_ql/stage/sort"
|
56
|
+
|
57
|
+
require_relative "mongo_ql/stage_context"
|
data/mongo_ql.gemspec
CHANGED
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mongo_ql
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Xizheng Ding
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-10-
|
12
|
-
dependencies:
|
11
|
+
date: 2019-10-17 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activesupport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
13
27
|
description:
|
14
28
|
email:
|
15
29
|
- dingxizheng@gamil.com
|
@@ -30,12 +44,23 @@ files:
|
|
30
44
|
- lib/mongo_ql/collection_operators.rb
|
31
45
|
- lib/mongo_ql/date_operators.rb
|
32
46
|
- lib/mongo_ql/expression.rb
|
47
|
+
- lib/mongo_ql/expression/ascend.rb
|
33
48
|
- lib/mongo_ql/expression/binary.rb
|
34
49
|
- lib/mongo_ql/expression/date_note.rb
|
50
|
+
- lib/mongo_ql/expression/descend.rb
|
35
51
|
- lib/mongo_ql/expression/field_node.rb
|
36
52
|
- lib/mongo_ql/expression/method_call.rb
|
53
|
+
- lib/mongo_ql/expression/projection.rb
|
37
54
|
- lib/mongo_ql/expression/unary.rb
|
38
55
|
- lib/mongo_ql/expression/value_node.rb
|
56
|
+
- lib/mongo_ql/stage.rb
|
57
|
+
- lib/mongo_ql/stage/group.rb
|
58
|
+
- lib/mongo_ql/stage/lookup.rb
|
59
|
+
- lib/mongo_ql/stage/match.rb
|
60
|
+
- lib/mongo_ql/stage/project.rb
|
61
|
+
- lib/mongo_ql/stage/sort.rb
|
62
|
+
- lib/mongo_ql/stage/unwind.rb
|
63
|
+
- lib/mongo_ql/stage_context.rb
|
39
64
|
- lib/mongo_ql/string_operators.rb
|
40
65
|
- lib/mongo_ql/unary_operators.rb
|
41
66
|
- lib/mongo_ql/version.rb
|