mongo_ql 0.0.1 → 0.0.2
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.
- 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
|