Class: QueryBuilder::Parser

Inherits:
Object
  • Object
show all
Defined in:
lib/querybuilder_rb.rb,
lib/query_builder/parser.rb

Constant Summary collapse

OP_PRECEDENCE =
{
  :function => 50, :select_one => 50,
  :interval => 40,
  :binary   => 39, :collate  => 39,
  :"!" => 38,
  :"@-" => 37, :"@~" => 37,
  :"^" => 36,
  :"*" => 35, :"/" => 35, :div => 35, :"%" => 35, :mod => 35,
  :"-" => 34, :"+" => 34,
  :"<<" => 33, :">>" => 33,
  :"&" => 32,
  :"|" => 31,
  :"=" => 30, :"<=>" => 30, :">=" => 30, :">" => 30, :"<=" => 30, :"<" => 30, :"<>" => 30, :"!=" => 30, :is => 30, :like => 30, :regexp => 30, :in => 30,
  :lt => 30, :le => 30, :eq => 30, :ne => 30, :ge => 30, :gt => 30, :match => 30,
  :between => 29, :case => 29, :when => 29, :then => 29, :else => 29,
  :not => 28,
  :"&&" => 27, :and => 27,
  :xor => 26,
  :"||" => 25, :or => 25,
  :":=" => 24,
  :relation => 13, :filter => 13, :select => 13,
  :scope => 12,
  :from => 11,  # this is not the same as SQL 'FROM', it's "icons from friends"
  :asc  => 10, :desc => 10,
  :clause => 5,
  :clause_and => 4,
  :clause_or => 3,
  :offset => 2, :paginate => 2, :limit => 2, :order => 2, :group => 2,  :having => 2,
  :query => 1,
  :par_close => 0, :clause_par_close => 0,
  :par => -1, :clause_par => -1
}

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

._querybuilder_actionsObject

Returns the value of attribute _querybuilder_actions.



12
13
14
# File 'lib/querybuilder_rb.rb', line 12

def _querybuilder_actions
  @_querybuilder_actions
end

._querybuilder_eof_actionsObject

Returns the value of attribute _querybuilder_eof_actions.



1807
1808
1809
# File 'lib/querybuilder_rb.rb', line 1807

def _querybuilder_eof_actions
  @_querybuilder_eof_actions
end

._querybuilder_index_offsetsObject

Returns the value of attribute _querybuilder_index_offsets.



861
862
863
# File 'lib/querybuilder_rb.rb', line 861

def _querybuilder_index_offsets
  @_querybuilder_index_offsets
end

._querybuilder_indiciesObject

Returns the value of attribute _querybuilder_indicies.



979
980
981
# File 'lib/querybuilder_rb.rb', line 979

def _querybuilder_indicies
  @_querybuilder_indicies
end

._querybuilder_key_offsetsObject

Returns the value of attribute _querybuilder_key_offsets.



43
44
45
# File 'lib/querybuilder_rb.rb', line 43

def _querybuilder_key_offsets
  @_querybuilder_key_offsets
end

._querybuilder_range_lengthsObject

Returns the value of attribute _querybuilder_range_lengths.



743
744
745
# File 'lib/querybuilder_rb.rb', line 743

def _querybuilder_range_lengths
  @_querybuilder_range_lengths
end

._querybuilder_single_lengthsObject

Returns the value of attribute _querybuilder_single_lengths.



625
626
627
# File 'lib/querybuilder_rb.rb', line 625

def _querybuilder_single_lengths
  @_querybuilder_single_lengths
end

._querybuilder_trans_actionsObject

Returns the value of attribute _querybuilder_trans_actions.



1629
1630
1631
# File 'lib/querybuilder_rb.rb', line 1629

def _querybuilder_trans_actions
  @_querybuilder_trans_actions
end

._querybuilder_trans_keysObject

Returns the value of attribute _querybuilder_trans_keys.



161
162
163
# File 'lib/querybuilder_rb.rb', line 161

def _querybuilder_trans_keys
  @_querybuilder_trans_keys
end

._querybuilder_trans_targsObject

Returns the value of attribute _querybuilder_trans_targs.



1451
1452
1453
# File 'lib/querybuilder_rb.rb', line 1451

def _querybuilder_trans_targs
  @_querybuilder_trans_targs
end

.querybuilder_en_clause_pObject

Returns the value of attribute querybuilder_en_clause_p.



1942
1943
1944
# File 'lib/querybuilder_rb.rb', line 1942

def querybuilder_en_clause_p
  @querybuilder_en_clause_p
end

.querybuilder_en_expr_pObject

Returns the value of attribute querybuilder_en_expr_p.



1938
1939
1940
# File 'lib/querybuilder_rb.rb', line 1938

def querybuilder_en_expr_p
  @querybuilder_en_expr_p
end

.querybuilder_en_mainObject

Returns the value of attribute querybuilder_en_main.



1946
1947
1948
# File 'lib/querybuilder_rb.rb', line 1946

def querybuilder_en_main
  @querybuilder_en_main
end

.querybuilder_errorObject

Returns the value of attribute querybuilder_error.



1933
1934
1935
# File 'lib/querybuilder_rb.rb', line 1933

def querybuilder_error
  @querybuilder_error
end

.querybuilder_first_finalObject

Returns the value of attribute querybuilder_first_final.



1929
1930
1931
# File 'lib/querybuilder_rb.rb', line 1929

def querybuilder_first_final
  @querybuilder_first_final
end

.querybuilder_startObject

Returns the value of attribute querybuilder_start.



1925
1926
1927
# File 'lib/querybuilder_rb.rb', line 1925

def querybuilder_start
  @querybuilder_start
end

Class Method Details

.apply_op(stack, op, change_last = true) ⇒ Object

Transform the stack to wrap the last element with an operator:

a, b, c

> [a, b, [op, c, d]]



41
42
43
44
45
46
47
48
49
50
# File 'lib/query_builder/parser.rb', line 41

def apply_op(stack, op, change_last = true)
  pop_stack(stack, op)
  last = stack.last
  change_elem = last.last
  last[-1] = [op.to_sym, change_elem]
  if change_last
    stack.push last[-1]
  end
  stack.last
end

.debug_stack(stack, msg = '') ⇒ Object



71
72
73
74
75
76
77
# File 'lib/query_builder/parser.rb', line 71

def debug_stack(stack, msg = '')
  puts "======= #{msg} ======="
  stack.reverse_each do |s|
    puts s.inspect
  end
  puts "======================"
end

.insert(stack, arg) ⇒ Object



52
53
54
55
56
57
58
59
60
# File 'lib/query_builder/parser.rb', line 52

def insert(stack, arg)
  # insert [:relation, "..."]
  # stack: [[:query]]  --> [[:query, [:relation, "..."]], [:relation, "..."]]
  pop_stack(stack, arg.first)
  last = stack.last
  last << arg
  stack.push last.last
  stack.last
end

.parse(arg) ⇒ Object

line 216 “querybuilder_rb.rl”



1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
# File 'lib/querybuilder_rb.rb', line 1953

def self.parse(arg)
  if arg.kind_of?(Array)
    data = "(#{arg.join(') or (')})\n"
  else
    data = "#{arg}\n"
  end
  par_count = 0
  stack = [[:query]]
  last  = stack.last
  str_buf         = ""
  clause_state = :relation
  eof = 0;
  
# line 1967 "querybuilder_rb.rb"
begin
	p ||= 0
	pe ||= data.length
	cs = querybuilder_start
end

# line 230 "querybuilder_rb.rl"
  
# line 1976 "querybuilder_rb.rb"
begin
	_klen, _trans, _keys, _acts, _nacts = nil
	_goto_level = 0
	_resume = 10
	_eof_trans = 15
	_again = 20
	_test_eof = 30
	_out = 40
	while true
	_trigger_goto = false
	if _goto_level <= 0
	if p == pe
		_goto_level = _test_eof
		next
	end
	if cs == 0
		_goto_level = _out
		next
	end
	end
	if _goto_level <= _resume
	_keys = _querybuilder_key_offsets[cs]
	_trans = _querybuilder_index_offsets[cs]
	_klen = _querybuilder_single_lengths[cs]
	_break_match = false
	
	begin
	  if _klen > 0
  _lower = _keys
  _upper = _keys + _klen - 1

  loop do
     break if _upper < _lower
     _mid = _lower + ( (_upper - _lower) >> 1 )

     if data[p] < _querybuilder_trans_keys[_mid]
        _upper = _mid - 1
     elsif data[p] > _querybuilder_trans_keys[_mid]
        _lower = _mid + 1
     else
        _trans += (_mid - _keys)
        _break_match = true
        break
     end
  end # loop
  break if _break_match
  _keys += _klen
  _trans += _klen
	  end
	  _klen = _querybuilder_range_lengths[cs]
	  if _klen > 0
  _lower = _keys
  _upper = _keys + (_klen << 1) - 2
  loop do
     break if _upper < _lower
     _mid = _lower + (((_upper-_lower) >> 1) & ~1)
     if data[p] < _querybuilder_trans_keys[_mid]
       _upper = _mid - 2
     elsif data[p] > _querybuilder_trans_keys[_mid+1]
       _lower = _mid + 2
     else
       _trans += ((_mid - _keys) >> 1)
       _break_match = true
       break
     end
  end # loop
  break if _break_match
  _trans += _klen
	  end
	end while false
	_trans = _querybuilder_indicies[_trans]
	cs = _querybuilder_trans_targs[_trans]
	if _querybuilder_trans_actions[_trans] != 0
		_acts = _querybuilder_trans_actions[_trans]
		_nacts = _querybuilder_actions[_acts]
		_acts += 1
		while _nacts > 0
			_nacts -= 1
			_acts += 1
			case _querybuilder_actions[_acts - 1]
when 0 then
# line 6 "querybuilder_rb.rl"
		begin

  str_buf += data[p].chr
		end
when 1 then
# line 10 "querybuilder_rb.rl"
		begin

  last << [:string, str_buf]
  str_buf = ""
		end
when 2 then
# line 15 "querybuilder_rb.rl"
		begin

  last << [:dstring, str_buf]
  str_buf = ""
		end
when 3 then
# line 20 "querybuilder_rb.rl"
		begin

  last << [:rubyless, str_buf]
  str_buf = ""
		end
when 4 then
# line 25 "querybuilder_rb.rl"
		begin

  last << [:integer, str_buf]
  str_buf = ""
		end
when 5 then
# line 30 "querybuilder_rb.rl"
		begin

  last << [:real, str_buf]
  str_buf = ""
		end
when 6 then
# line 35 "querybuilder_rb.rl"
		begin

  last << [:field, str_buf]
  str_buf = ""
		end
when 7 then
# line 40 "querybuilder_rb.rl"
		begin

  last << [:method, str_buf]
  str_buf = ""
		end
when 8 then
# line 45 "querybuilder_rb.rl"
		begin

  last << [:raw, str_buf]
  str_buf = ""
		end
when 9 then
# line 50 "querybuilder_rb.rl"
		begin

  last = apply_op(stack, :select_one)
  last << str_buf
  str_buf = ""
  # last should be [:select, ...], not the [:select_one] just added.
  stack.pop
  last = stack.last
		end
when 10 then
# line 59 "querybuilder_rb.rl"
		begin

  last = apply_op(stack, :function)
  str_buf = ""
		end
when 11 then
# line 64 "querybuilder_rb.rl"
		begin

  last = apply_op(stack, str_buf.downcase.to_sym, false)
  str_buf = ""
		end
when 12 then
# line 69 "querybuilder_rb.rl"
		begin

  if clause_state == :relation || clause_state == :parenthesis
    last = insert(stack, [:relation, str_buf])
    str_buf = ""
  end
		end
when 13 then
# line 76 "querybuilder_rb.rl"
		begin

  last = apply_op(stack, str_buf.downcase.to_sym)
  str_buf = ""
		end
when 14 then
# line 81 "querybuilder_rb.rl"
		begin

  last = apply_op(stack, :in)
		end
when 15 then
# line 85 "querybuilder_rb.rl"
		begin

  # We need the 'is' operator to avoid confusion with 'in site'.
  last = apply_op(stack, :is)
		end
when 16 then
# line 90 "querybuilder_rb.rl"
		begin

  last = apply_op(stack, :interval)
  last << str_buf
  str_buf = ""
		end
when 17 then
# line 96 "querybuilder_rb.rl"
		begin

  last = apply_op(stack, :filter)
  clause_state = :filter
		end
when 18 then
# line 101 "querybuilder_rb.rl"
		begin

  last = apply_op(stack, :having)
  clause_state = :having
		end
when 19 then
# line 106 "querybuilder_rb.rl"
		begin

  last = apply_op(stack, :select)
  clause_state = :select
		end
when 20 then
# line 111 "querybuilder_rb.rl"
		begin

  # remember current machine state 'cs'
  par_count += 1
  last << [:par, cs]
  stack.push last.last
  last = last.last
  	begin
		cs = 609
		_trigger_goto = true
		_goto_level = _again
		break
	end

		end
when 21 then
# line 120 "querybuilder_rb.rl"
		begin

  pop_stack(stack, :par_close)
  # reset machine state 'cs'
  par_count -= 1
  cs = stack.last.delete_at(1)
  # one more time to remove [:par...] line
  stack.pop
  last = stack.last
  # closing ')' must be parsed twice
  p = p - 1;
		end
when 22 then
# line 132 "querybuilder_rb.rl"
		begin

  # remember current machine state 'cs'
  clause_state = :parenthesis
  last << [:clause_par, cs]
  stack.push last.last
  last = last.last
  	begin
		cs = 714
		_trigger_goto = true
		_goto_level = _again
		break
	end

		end
when 23 then
# line 141 "querybuilder_rb.rl"
		begin

  pop_stack(stack, :clause_par_close)
  clause_state = :relation
  # reset machine state 'cs'
  cs = stack.last.delete_at(1)
  # one more time to remove [:clause_par...] line
  stack.pop
  last = stack.last
  # closing ')' must be parsed twice
  p = p - 1;
		end
when 24 then
# line 153 "querybuilder_rb.rl"
		begin

  last = apply_op(stack, :scope)
  last << str_buf
  str_buf = ""
		end
when 25 then
# line 159 "querybuilder_rb.rl"
		begin

  last = apply_op(stack, :offset)
		end
when 26 then
# line 163 "querybuilder_rb.rl"
		begin

  last << [:param, str_buf]
  str_buf = ""
		end
when 27 then
# line 168 "querybuilder_rb.rl"
		begin

  last = apply_op(stack, :paginate)
		end
when 28 then
# line 172 "querybuilder_rb.rl"
		begin

  last = apply_op(stack, :limit)
  str_buf = ""
		end
when 29 then
# line 177 "querybuilder_rb.rl"
		begin

  last = apply_op(stack, :order)
  str_buf = ""
		end
when 30 then
# line 182 "querybuilder_rb.rl"
		begin

  last = apply_op(stack, :group)
		end
when 31 then
# line 186 "querybuilder_rb.rl"
		begin

  last = apply_op(stack, :from)
  clause_state = :relation
		end
when 32 then
# line 191 "querybuilder_rb.rl"
		begin

  if clause_state == :relation
    last = apply_op(stack, "clause_#{str_buf}".to_sym)
    str_buf = ""
  end
		end
when 33 then
# line 202 "querybuilder_rb.rl"
		begin

  p = p - 3
  p = 0 if p < 0
  raise QueryBuilder::SyntaxError.new("Syntax error near #{data[p..-1].chomp.inspect}.")
		end
# line 2335 "querybuilder_rb.rb"
			end # action switch
		end
	end
	if _trigger_goto
		next
	end
	end
	if _goto_level <= _again
	if cs == 0
		_goto_level = _out
		next
	end
	p += 1
	if p != pe
		_goto_level = _resume
		next
	end
	end
	if _goto_level <= _test_eof
	if p == eof
	__acts = _querybuilder_eof_actions[cs]
	__nacts =  _querybuilder_actions[__acts]
	__acts += 1
	while __nacts > 0
		__nacts -= 1
		__acts += 1
		case _querybuilder_actions[__acts - 1]
when 33 then
# line 202 "querybuilder_rb.rl"
		begin

  p = p - 3
  p = 0 if p < 0
  raise QueryBuilder::SyntaxError.new("Syntax error near #{data[p..-1].chomp.inspect}.")
		end
# line 2371 "querybuilder_rb.rb"
		end # eof action switch
	end
	if _trigger_goto
		next
	end
end
	end
	if _goto_level <= _out
		break
	end
	end
	end

# line 231 "querybuilder_rb.rl"

  if p < pe
    p = p - 3
    p = 0 if p < 0
    raise QueryBuilder::SyntaxError.new("Syntax error near #{data[p..-2].inspect}.")
  end

  if par_count > 0
    raise QueryBuilder::SyntaxError.new("Missing closing parenthesis in #{data[0..-2].inspect}.")
  end
  stack.first
end

.pop_stack(stack, op) ⇒ Object



62
63
64
65
66
67
68
69
# File 'lib/query_builder/parser.rb', line 62

def pop_stack(stack, op)
  #debug_stack(stack, op)
  stack_op = stack.last.first
  while OP_PRECEDENCE[op] <= OP_PRECEDENCE[stack_op]
    stack.pop
    stack_op = stack.last.first
  end
end