Skip to content
Snippets Groups Projects
Commit eff513b0 authored by Danis Kirasirov's avatar Danis Kirasirov
Browse files

Правки

parent fbbd09d4
No related branches found
No related tags found
No related merge requests found
...@@ -231,7 +231,7 @@ func (c *compiler) identifier(node ast.Node) string { ...@@ -231,7 +231,7 @@ func (c *compiler) identifier(node ast.Node) string {
} }
func (c *compiler) BinaryNode(node *ast.BinaryNode) interface{} { func (c *compiler) BinaryNode(node *ast.BinaryNode) interface{} {
if result, ok := c.handleLenNode(node); ok { if result := c.handleLenNode(node); result != nil {
return result return result
} }
...@@ -656,10 +656,12 @@ func (c *compiler) PairNode(node *ast.PairNode) interface{} { ...@@ -656,10 +656,12 @@ func (c *compiler) PairNode(node *ast.PairNode) interface{} {
//c.compile(node.Value) //c.compile(node.Value)
} }
func (c *compiler) handleLenNode(node *ast.BinaryNode) (result bson.M, ok bool) { // handleLenNode получает узел AST и возвращает запрос для mongo,
// если узел представляет вызов функции len, и nil в противном случае.
func (c *compiler) handleLenNode(node *ast.BinaryNode) bson.M {
lenNode, ok := node.Left.(*ast.BuiltinNode) lenNode, ok := node.Left.(*ast.BuiltinNode)
if !ok || lenNode.Name != "len" { if !ok || lenNode.Name != "len" {
return nil, false return nil
} }
if len(lenNode.Arguments) != 1 { if len(lenNode.Arguments) != 1 {
...@@ -667,44 +669,35 @@ func (c *compiler) handleLenNode(node *ast.BinaryNode) (result bson.M, ok bool) ...@@ -667,44 +669,35 @@ func (c *compiler) handleLenNode(node *ast.BinaryNode) (result bson.M, ok bool)
} }
length, ok := c.eval(node.Right).(int) length, ok := c.eval(node.Right).(int)
if !ok || length < 0 { if !ok {
panic("len() can only be compared with non-negative number") panic("len() can only be compared with number value")
}
switch node.Operator {
case "==":
if length == 0 {
return bson.M{c.identifier(lenNode.Arguments[0]): bson.M{"$eq": bson.A{}}}, true
}
return bson.M{c.identifier(lenNode.Arguments[0]): bson.M{"$size": length}}, true
case "!=":
if length == 0 {
return bson.M{c.identifier(lenNode.Arguments[0]): bson.M{"$exists": true, "$type": "array", "$ne": bson.A{}}}, true
}
return bson.M{c.identifier(lenNode.Arguments[0]): bson.M{"$not": bson.M{"$size": length}}}, true
case ">":
if length == 0 {
return bson.M{c.identifier(lenNode.Arguments[0]): bson.M{"$exists": true, "$type": "array", "$ne": bson.A{}}}, true
} }
return bson.M{c.identifier(lenNode.Arguments[0]) + "." + strconv.Itoa(length): bson.M{"$exists": true}}, true if length < 0 {
panic("len() can only be compared with non-negative number")
case ">=":
if length == 0 {
return bson.M{c.identifier(lenNode.Arguments[0]): bson.M{"$exists": true, "$type": "array"}}, true
} }
return bson.M{c.identifier(lenNode.Arguments[0]) + "." + strconv.Itoa(length-1): bson.M{"$exists": true}}, true
case "<": switch op := node.Operator; {
if length == 0 { case (op == "==" || op == "<=") && length == 0:
return bson.M{c.identifier(lenNode.Arguments[0]): bson.M{"$eq": bson.A{}}}
case (op == "!=" || op == ">") && length == 0:
return bson.M{c.identifier(lenNode.Arguments[0]): bson.M{"$exists": true, "$type": "array", "$ne": bson.A{}}}
case op == "==":
return bson.M{c.identifier(lenNode.Arguments[0]): bson.M{"$size": length}}
case op == "!=":
return bson.M{c.identifier(lenNode.Arguments[0]): bson.M{"$not": bson.M{"$size": length}}}
case op == ">":
return bson.M{c.identifier(lenNode.Arguments[0]) + "." + strconv.Itoa(length): bson.M{"$exists": true}}
case op == ">=" && length == 0:
return bson.M{c.identifier(lenNode.Arguments[0]): bson.M{"$exists": true, "$type": "array"}}
case op == ">=":
return bson.M{c.identifier(lenNode.Arguments[0]) + "." + strconv.Itoa(length-1): bson.M{"$exists": true}}
case op == "<" && length == 0:
panic("invalid comparison: len() cannot be less than 0") panic("invalid comparison: len() cannot be less than 0")
} case op == "<":
return bson.M{c.identifier(lenNode.Arguments[0]) + "." + strconv.Itoa(length-1): bson.M{"$exists": false}}, true return bson.M{c.identifier(lenNode.Arguments[0]) + "." + strconv.Itoa(length-1): bson.M{"$exists": false}}
case op == "<=":
case "<=": return bson.M{c.identifier(lenNode.Arguments[0]) + "." + strconv.Itoa(length): bson.M{"$exists": false}}
return bson.M{c.identifier(lenNode.Arguments[0]) + "." + strconv.Itoa(length): bson.M{"$exists": false}}, true default:
}
panic("invalid comparison operator with len()") panic("invalid comparison operator with len()")
} }
}
...@@ -48,7 +48,7 @@ func TestConvertToMongo(t *testing.T) { ...@@ -48,7 +48,7 @@ func TestConvertToMongo(t *testing.T) {
{"len lt", "len(s) < 1", nil, bson.M{"s.0": bson.M{"$exists": false}}, false}, {"len lt", "len(s) < 1", nil, bson.M{"s.0": bson.M{"$exists": false}}, false},
{"len lt zero", "len(s) < 0", nil, nil, true}, {"len lt zero", "len(s) < 0", nil, nil, true},
{"len lte", "len(s) <= 1", nil, bson.M{"s.1": bson.M{"$exists": false}}, false}, {"len lte", "len(s) <= 1", nil, bson.M{"s.1": bson.M{"$exists": false}}, false},
{"len lte zero", "len(s) <= 0", nil, bson.M{"s.0": bson.M{"$exists": false}}, false}, {"len lte zero", "len(s) <= 0", nil, bson.M{"s": bson.M{"$eq": bson.A{}}}, false},
{"field#1", "s.test > 3", nil, bson.M{"s.test": bson.M{"$gt": 3}}, false}, {"field#1", "s.test > 3", nil, bson.M{"s.test": bson.M{"$gt": 3}}, false},
{"field#2", "s['test'] > 3", nil, bson.M{"s.test": bson.M{"$gt": 3}}, false}, {"field#2", "s['test'] > 3", nil, bson.M{"s.test": bson.M{"$gt": 3}}, false},
{"field#3", "s[test] > 3", nil, bson.M{"s.test": bson.M{"$gt": 3}}, false}, {"field#3", "s[test] > 3", nil, bson.M{"s.test": bson.M{"$gt": 3}}, false},
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment