def test_comparison(): # reduce less than result = optimize(parse("1 < 2 AND attr = 1")) assert result == ast.Equal( ast.Attribute('attr'), 1 ) # reduce greater than result = optimize(parse("2 > 1 AND attr = 1")) assert result == ast.Equal( ast.Attribute('attr'), 1 ) # reduce less or equal result = optimize(parse("1 <= 2 AND attr = 1")) assert result == ast.Equal( ast.Attribute('attr'), 1 ) # reduce greater or equal result = optimize(parse("2 >= 1 AND attr = 1")) assert result == ast.Equal( ast.Attribute('attr'), 1 ) # reduce not equal result = optimize(parse("2 <> 1 AND attr = 1")) assert result == ast.Equal( ast.Attribute('attr'), 1 )
def test_in(): # allow reduction when the left hand side and all options # are certain result = optimize(parse("1 IN (1, 2, 3) AND attr = 1")) assert result == ast.Equal( ast.Attribute('attr'), 1 ) result = optimize(parse("5 NOT IN (1, 2, 3) AND attr = 1")) assert result == ast.Equal( ast.Attribute('attr'), 1 ) # don't allow reduction if either left hand side or either option # is uncertain result = optimize(parse("attr IN (1, 2, 3)")) assert result == ast.In( ast.Attribute('attr'), [1, 2, 3], False ) result = optimize(parse("1 IN (attr, 2, 3)")) assert result == ast.In( 1, [ast.Attribute('attr'), 2, 3], False )
def test_between(): # allow reduction result = optimize(parse("5 BETWEEN 1 AND 6 AND attr = 1")) assert result == ast.Equal( ast.Attribute('attr'), 1 ) result = optimize(parse("10 NOT BETWEEN 1 AND 6 AND attr = 1")) assert result == ast.Equal( ast.Attribute('attr'), 1 ) # don't reduce if either lhs, low or high are uncertain result = optimize(parse("attr BETWEEN 1 AND 6")) assert result == ast.Between( ast.Attribute("attr"), 1, 6, False ) result = optimize(parse("5 BETWEEN attr AND 6")) assert result == ast.Between( 5, ast.Attribute("attr"), 6, False ) result = optimize(parse("5 BETWEEN 1 AND attr")) assert result == ast.Between( 5, 1, ast.Attribute("attr"), False )
def test_like(): # allow reduction result = optimize(parse("'This is a test' LIKE 'This is %' AND attr = 1")) assert result == ast.Equal( ast.Attribute('attr'), 1 ) result = optimize( parse("'This is a test' LIKE 'This is . test' AND attr = 1") ) assert result == ast.Equal( ast.Attribute('attr'), 1 ) # don't reduction when an attribute is referenced result = optimize(parse("attr LIKE 'This is %'")) assert result == ast.Like( ast.Attribute('attr'), 'This is %', False, '%', '.', '\\', False )
def test_combination(): # reduce right hand side result = optimize(parse("attr = 1 AND 1 < 2")) assert result == ast.Equal( ast.Attribute('attr'), 1 ) # reduce left hand side result = optimize(parse("1 < 2 AND attr = 1")) assert result == ast.Equal( ast.Attribute('attr'), 1 ) # reduce left hand side result = optimize(parse("1 < 2 AND attr = 1")) assert result == ast.Equal( ast.Attribute('attr'), 1 ) # can' reduce result = optimize(parse("attr = 1 AND other = 2")) assert result == ast.And( ast.Equal( ast.Attribute('attr'), 1 ), ast.Equal( ast.Attribute('other'), 2 ) ) # reduce AND to an INCLUDE if both sides evaluate to true result = optimize(parse("1 = 1 AND 2 = 2")) assert result == ast.Include(False) # reduce AND to an EXCLUDE if either side evaluates to false result = optimize(parse("attr = 1 AND 2 = 3")) assert result == ast.Include(True) result = optimize(parse("2 = 3 AND attr = 1")) assert result == ast.Include(True) result = optimize(parse("0 = 1 AND 2 = 3")) assert result == ast.Include(True) # reduce OR to INCLUDE if either side evaluates to true result = optimize(parse("attr = 1 OR 2 = 2")) assert result == ast.Include(False) result = optimize(parse("2 = 2 OR attr = 1")) assert result == ast.Include(False) # reduce OR to an EXCLUDE if both sides evaluate to false result = optimize(parse("1 = 2 AND 2 = 1")) assert result == ast.Include(True)
def test_arithmetic(): # test possible optimizations result = optimize(parse("attr = 10 + 10")) assert result == ast.Equal( ast.Attribute('attr'), 20 ) result = optimize(parse("attr = 30 - 10")) assert result == ast.Equal( ast.Attribute('attr'), 20 ) result = optimize(parse("attr = 10 * 2")) assert result == ast.Equal( ast.Attribute('attr'), 20 ) result = optimize(parse("attr = 40 / 2")) assert result == ast.Equal( ast.Attribute('attr'), 20 ) # test imppossible optimizations result = optimize(parse("attr = other + 10")) assert result == ast.Equal( ast.Attribute('attr'), ast.Add( ast.Attribute('other'), 10 ), ) result = optimize(parse("attr = other - 10")) assert result == ast.Equal( ast.Attribute('attr'), ast.Sub( ast.Attribute('other'), 10 ), ) result = optimize(parse("attr = other * 2")) assert result == ast.Equal( ast.Attribute('attr'), ast.Mul( ast.Attribute('other'), 2 ), ) result = optimize(parse("attr = other / 2")) assert result == ast.Equal( ast.Attribute('attr'), ast.Div( ast.Attribute('other'), 2 ), )
def test_attribute_arithmetic_add_mul(): result = parse( { "op": "eq", "args": [ {"property": "attr"}, { "op": "+", "args": [ 3, {"op": "*", "args": [5, 2]}, ], }, ], } ) assert result == ast.Equal( ast.Attribute("attr"), ast.Add( 3, ast.Mul( 5, 2, ), ), )
def test_function_attr_string_arg(): result = parse( { "op": "eq", "args": [ {"property": "attr"}, { "function": { "name": "myfunc", "arguments": [{"property": "other_attr"}, "abc"], } }, ], } ) assert result == ast.Equal( ast.Attribute("attr"), ast.Function( "myfunc", [ ast.Attribute("other_attr"), "abc", ], ), )
def test_attribute_arithmetic_div_sub_bracketted(): result = parse( { "op": "eq", "args": [ {"property": "attr"}, { "op": "/", "args": [ 3, {"op": "-", "args": [5, 2]}, ], }, ], } ) assert result == ast.Equal( ast.Attribute("attr"), ast.Div( 3, ast.Sub( 5, 2, ), ), )
def test_function(): def myadder(a, b): return a + b result = optimize(parse("attr = myadder(1, 2)"), {"myadder": myadder}) assert result == ast.Equal( ast.Attribute('attr'), 3, ) # can't optimize a function referencing an attribute result = optimize(parse("attr = myadder(other, 2)"), {"myadder": myadder}) assert result == ast.Equal( ast.Attribute('attr'), ast.Function( "myadder", [ ast.Attribute("other"), 2 ] ) ) # can't optimize a function with a nested reference to an attribute result = optimize( parse("attr = myadder(other + 2, 2)"), {"myadder": myadder} ) assert result == ast.Equal( ast.Attribute('attr'), ast.Function( "myadder", [ ast.Add(ast.Attribute("other"), 2), 2 ] ) ) # can't optimize an unknown functions result = optimize(parse("attr = unkown(1, 2)"), {"myadder": myadder}) assert result == ast.Equal( ast.Attribute('attr'), ast.Function( "unkown", [ 1, 2, ] ) )
def test_function_single_arg(): result = parse('attr = myfunc(1)') assert result == ast.Equal( ast.Attribute('attr'), ast.Function('myfunc', [ 1, ]), )
def test_attribute_arithmetic_div(): result = parse('attr = 5 / 2') assert result == ast.Equal( ast.Attribute('attr'), ast.Div( 5, 2, ), )
def test_attribute_arithmetic_mul(): result = parse('attr = 5 * 2') assert result == ast.Equal( ast.Attribute('attr'), ast.Mul( 5, 2, ), )
def test_attribute_arithmetic_sub(): result = parse('attr = 5 - 2') assert result == ast.Equal( ast.Attribute('attr'), ast.Sub( 5, 2, ), )
def test_attribute_arithmetic_add(): result = parse('attr = 5 + 2') assert result == ast.Equal( ast.Attribute('attr'), ast.Add( 5, 2, ), )
def test_function_attr_string_arg(): result = parse('attr = myfunc(other_attr, \'abc\')') assert result == ast.Equal( ast.Attribute('attr'), ast.Function('myfunc', [ ast.Attribute('other_attr'), "abc", ]), )
def test_attribute_arithmetic_div(): result = parse(['==', ['get', 'attr'], ['/', 5, 2]]) assert result == ast.Equal( ast.Attribute('attr'), ast.Div( 5, 2, ), )
def test_arithmetic_modulo(): result = parse(['==', ['get', 'attr'], ['%', 3, 7]]) assert result == ast.Equal( ast.Attribute('attr'), ast.Function( 'mod', [3, 7], ), )
def test_arithmetic_ceil(): result = parse(['==', ['ceil', ['get', 'age']], 42]) assert result == ast.Equal( ast.Function( 'ceil', [ ast.Attribute('age'), ], ), 42)
def test_logical_all(): result = parse([ 'all', ['>', ['get', 'height'], 50], ['==', ['get', 'type'], 'commercial'], ['get', 'occupied'] ]) assert result == ast.And( ast.And(ast.GreaterThan( ast.Attribute('height'), 50, ), ast.Equal(ast.Attribute('type'), 'commercial')), ast.Attribute('occupied'))
def test_attribute_arithmetic_div_sub_bracketted(): result = parse('attr = 3 / (5 - 2)') assert result == ast.Equal( ast.Attribute('attr'), ast.Div( 3, ast.Sub( 5, 2, ), ), )
def test_attribute_arithmetic_div_sub(): result = parse('attr = 3 / 5 - 2') assert result == ast.Equal( ast.Attribute('attr'), ast.Sub( ast.Div( 3, 5, ), 2, ), )
def test_attribute_arithmetic_add_mul(): result = parse(['==', ['get', 'attr'], ['+', 3, ['*', 5, 2]]]) assert result == ast.Equal( ast.Attribute('attr'), ast.Add( 3, ast.Mul( 5, 2, ), ), )
def test_attribute_arithmetic_div_sub_bracketted(): result = parse(['==', ['get', 'attr'], ['/', 3, ['-', 5, 2]]]) assert result == ast.Equal( ast.Attribute('attr'), ast.Div( 3, ast.Sub( 5, 2, ), ), )
def test_function_no_arg(): result = parse( { "op": "eq", "args": [ {"property": "attr"}, {"function": {"name": "myfunc", "arguments": []}}, ], } ) assert result == ast.Equal( ast.Attribute("attr"), ast.Function("myfunc", []), )
def test_attribute_arithmetic_div(): result = parse( { "op": "eq", "args": [{"property": "attr"}, {"op": "/", "args": [5, 2]}], } ) assert result == ast.Equal( ast.Attribute("attr"), ast.Div( 5, 2, ), )
def test_attribute_arithmetic_div(): result = parse({ "eq": [ {"property": "attr"}, {"/": [5, 2]} ] }) assert result == ast.Equal( ast.Attribute('attr'), ast.Div( 5, 2, ), )
def test_not(): result = parse(''' <fes:Filter xmlns:fes="http://www.opengis.net/fes/2.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema-datatypes"> <fes:Not> <fes:PropertyIsEqualTo> <fes:ValueReference>attr</fes:ValueReference> <fes:Literal type="xsd:string">value</fes:Literal> </fes:PropertyIsEqualTo> </fes:Not> </fes:Filter> ''') assert result == ast.Not(ast.Equal( ast.Attribute('attr'), 'value', ), )
def test_function_single_arg(): result = parse({ "eq": [ {"property": "attr"}, { "function": { "name": "myfunc", "arguments": [1] } } ] }) assert result == ast.Equal( ast.Attribute('attr'), ast.Function( 'myfunc', [1], ), )
def test_attribute_arithmetic_div_sub(): result = parse({ "eq": [ {"property": "attr"}, {"-": [ {"/": [3, 5]}, 2, ]}, ], }) assert result == ast.Equal( ast.Attribute('attr'), ast.Sub( ast.Div( 3, 5, ), 2, ), )