diff --git a/lib/rasti/db/nql/nodes.rb b/lib/rasti/db/nql/nodes.rb index 881fb49..5cd2c5a 100644 --- a/lib/rasti/db/nql/nodes.rb +++ b/lib/rasti/db/nql/nodes.rb @@ -18,9 +18,23 @@ class Comparison < Treetop::Runtime::SyntaxNode end class Field < Treetop::Runtime::SyntaxNode + + def tables + _tables.elements.map{ |e| e.table.text_value } + end + + def column + _column.text_value + end + end class TimeConstant < Treetop::Runtime::SyntaxNode + + def value + Timing::TimeInZone.parse text_value + end + end class Date < Treetop::Runtime::SyntaxNode diff --git a/lib/rasti/db/nql/syntax.rb b/lib/rasti/db/nql/syntax.rb index 5c8eaab..23aae49 100644 --- a/lib/rasti/db/nql/syntax.rb +++ b/lib/rasti/db/nql/syntax.rb @@ -125,26 +125,38 @@ def _nt_disjunction end i0, s0 = index, [] - r1 = _nt_conjunction + i1 = index + r2 = _nt_statement + if r2 + r1 = r2 + else + r3 = _nt_conjunction + if r3 + r1 = r3 + else + @index = i1 + r1 = nil + end + end s0 << r1 if r1 - r2 = _nt_mandatory_space - s0 << r2 - if r2 + r4 = _nt_mandatory_space + s0 << r4 + if r4 if has_terminal?('|', false, index) - r3 = instantiate_node(SyntaxNode,input, index...(index + 1)) + r5 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure('|') - r3 = nil + r5 = nil end - s0 << r3 - if r3 - r4 = _nt_mandatory_space - s0 << r4 - if r4 - r5 = _nt_disjunction - s0 << r5 + s0 << r5 + if r5 + r6 = _nt_mandatory_space + s0 << r6 + if r6 + r7 = _nt_proposition + s0 << r7 end end end @@ -210,7 +222,19 @@ def _nt_conjunction r4 = _nt_mandatory_space s0 << r4 if r4 - r5 = _nt_conjunction + i5 = index + r6 = _nt_statement + if r6 + r5 = r6 + else + r7 = _nt_conjunction + if r7 + r5 = r7 + else + @index = i5 + r5 = nil + end + end s0 << r5 end end @@ -260,16 +284,8 @@ def _nt_statement end module ParenthesisSentence0 - def optional_space1 - elements[1] - end - def sentence - elements[2] - end - - def optional_space2 - elements[3] + elements[1] end end @@ -295,25 +311,17 @@ def _nt_parenthesis_sentence end s0 << r1 if r1 - r2 = _nt_optional_space + r2 = _nt_sentence s0 << r2 if r2 - r3 = _nt_sentence - s0 << r3 - if r3 - r4 = _nt_optional_space - s0 << r4 - if r4 - if has_terminal?(')', false, index) - r5 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 - else - terminal_parse_failure(')') - r5 = nil - end - s0 << r5 - end + if has_terminal?(')', false, index) + r3 = instantiate_node(SyntaxNode,input, index...(index + 1)) + @index += 1 + else + terminal_parse_failure(')') + r3 = nil end + s0 << r3 end end if s0.last @@ -395,18 +403,18 @@ def _nt_comparison end module Field0 - def field_name + def table elements[0] end end module Field1 - def tables + def _tables elements[0] end - def column + def _column elements[1] end end @@ -721,7 +729,7 @@ def _nt_field_name s0, i0 = [], index loop do - if has_terminal?('\G[a-z]', true, index) + if has_terminal?('\G[a-z_]', true, index) r1 = true @index += 1 else @@ -789,6 +797,12 @@ def value end module Time5 + def value + elements[0] + end + end + + module Time6 def date elements[0] end @@ -930,7 +944,16 @@ def _nt_time end s0 << r12 if r12 - r19 = _nt_timezone + i19, s19 = index, [] + r20 = _nt_timezone + s19 << r20 + if s19.last + r19 = instantiate_node(SyntaxNode,input, i19...index, s19) + r19.extend(Time5) + else + @index = i19 + r19 = nil + end if r19 r18 = r19 else @@ -944,7 +967,7 @@ def _nt_time end if s0.last r0 = instantiate_node(TimeConstant,input, i0...index, s0) - r0.extend(Time5) + r0.extend(Time6) else @index = i0 r0 = nil @@ -1353,7 +1376,7 @@ def _nt_character return cached end - if has_terminal?('\G[0-9a-zA-ZÁÀÄÂÃÅĀĂǍáàäâãåāăǎÉÈËÊĒĔĖĚéèëêēĕėěÍÌÏÎĨĬǏíìïîĩĭǐÓÒÖÔÕŌŎŐǑóòöôõōŏőǒÚÙÜÛŨŪŬŮŰǓúùüûũūŭůűǔÑñçÇ%&@#\\:\\+\\-_=ß\'\\?!$\\*\\/\\s\\(\\)\\.]', true, index) + if has_terminal?('\G[0-9a-zA-ZÁÀÄÂÃÅĀĂǍáàäâãåāăǎÉÈËÊĒĔĖĚéèëêēĕėěÍÌÏÎĨĬǏíìïîĩĭǐÓÒÖÔÕŌŎŐǑóòöôõōŏőǒÚÙÜÛŨŪŬŮŰǓúùüûũūŭůűǔÑñçÇ%&@#\\|\\:\\+\\-_=ß\'\\?!$\\*\\/\\s\\(\\)\\.]', true, index) r0 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else diff --git a/lib/rasti/db/nql/syntax.treetop b/lib/rasti/db/nql/syntax.treetop index a98dd75..815fb74 100644 --- a/lib/rasti/db/nql/syntax.treetop +++ b/lib/rasti/db/nql/syntax.treetop @@ -14,11 +14,11 @@ module Rasti end rule disjunction - left:conjunction mandatory_space '|' mandatory_space right:disjunction + left:(statement / conjunction) mandatory_space '|' mandatory_space right:proposition end rule conjunction - left:statement mandatory_space '&' mandatory_space right:conjunction + left:statement mandatory_space '&' mandatory_space right:(statement / conjunction) end rule statement @@ -27,7 +27,7 @@ module Rasti end rule parenthesis_sentence - '(' optional_space sentence optional_space ')' + '(' sentence ')' end rule comparison @@ -35,7 +35,7 @@ module Rasti end rule field - tables:(field_name '.')* column:field_name + _tables:(table:field_name '.')* _column:field_name end rule comparator @@ -68,11 +68,11 @@ module Rasti end rule field_name - [a-z]+ + [a-z_]+ end rule time - date:(value:date 'T')? hour:(digit digit) ':' minutes:(digit digit) seconds:(':' value:(digit digit))? timezone:(timezone)? + date:(value:date 'T')? hour:(digit digit) ':' minutes:(digit digit) seconds:(':' value:(digit digit))? timezone:(value:timezone)? end rule date @@ -97,7 +97,7 @@ module Rasti end rule character - [0-9a-zA-ZÁÀÄÂÃÅĀĂǍáàäâãåāăǎÉÈËÊĒĔĖĚéèëêēĕėěÍÌÏÎĨĬǏíìïîĩĭǐÓÒÖÔÕŌŎŐǑóòöôõōŏőǒÚÙÜÛŨŪŬŮŰǓúùüûũūŭůűǔÑñçÇ%&@#\:\+\-_=ß'\?!$\*\/\s\(\)\.] + [0-9a-zA-ZÁÀÄÂÃÅĀĂǍáàäâãåāăǎÉÈËÊĒĔĖĚéèëêēĕėěÍÌÏÎĨĬǏíìïîĩĭǐÓÒÖÔÕŌŎŐǑóòöôõōŏőǒÚÙÜÛŨŪŬŮŰǓúùüûũūŭůűǔÑñçÇ%&@#\|\:\+\-_=ß'\?!$\*\/\s\(\)\.] end rule boolean diff --git a/spec/nql/syntax_parser_spec.rb b/spec/nql/syntax_parser_spec.rb index 796950e..adcf71b 100644 --- a/spec/nql/syntax_parser_spec.rb +++ b/spec/nql/syntax_parser_spec.rb @@ -79,6 +79,56 @@ right_hand_operand.value.must_equal 'String1' end + it 'must parse expression with literal string' do + tree = parser.parse 'column = "a & (b | c) | d"' + tree.wont_be_nil + + right_hand_operand = tree.proposition.right + right_hand_operand.must_be_instance_of Rasti::DB::NQL::LiteralStringConstant + right_hand_operand.value.must_equal 'a & (b | c) | d' + end + + describe 'Time' do + + it 'must parse expression with hours and minutes' do + tree = parser.parse 'column > 12:20' + tree.wont_be_nil + + right_hand_operand = tree.proposition.right + right_hand_operand.must_be_instance_of Rasti::DB::NQL::TimeConstant + right_hand_operand.value.must_equal Timing::TimeInZone.parse('12:20') + end + + it 'must parse expression with date, hours, minutes and seconds' do + tree = parser.parse 'column > 2019-03-27T12:20:00' + tree.wont_be_nil + + right_hand_operand = tree.proposition.right + right_hand_operand.must_be_instance_of Rasti::DB::NQL::TimeConstant + right_hand_operand.value.must_equal Timing::TimeInZone.parse('2019-03-27T12:20:00') + end + + it 'must parse expression with date, hours, minutes, seconds and timezone' do + tree = parser.parse 'column > 2019-03-27T12:20:00-03:00' + tree.wont_be_nil + + right_hand_operand = tree.proposition.right + right_hand_operand.must_be_instance_of Rasti::DB::NQL::TimeConstant + right_hand_operand.value.must_equal Timing::TimeInZone.parse('2019-03-27T12:20:00-03:00') + end + + end + + end + + it 'must parse expression with field with tables' do + tree = parser.parse 'relation_table_one.relation_table_two.column = 1' + tree.wont_be_nil + + left_hand_operand = tree.proposition.left + left_hand_operand.tables.must_equal ['relation_table_one', 'relation_table_two'] + left_hand_operand.column.must_equal 'column' end + end end \ No newline at end of file