rql_parser 0.0.1alpha3 → 0.0.1alpha4
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/.rubocop.yml +8 -0
- data/CHANGELOG.md +13 -0
- data/Gemfile +2 -2
- data/Gemfile.lock +16 -1
- data/README.md +10 -5
- data/Rakefile +2 -2
- data/bin/console +3 -3
- data/lib/rql_parser/base_interaction.rb +1 -0
- data/lib/rql_parser/services/format.rb +46 -0
- data/lib/rql_parser/services/from_params.rb +21 -0
- data/lib/rql_parser/services/parse.rb +151 -0
- data/lib/rql_parser/version.rb +1 -1
- data/lib/rql_parser.rb +23 -2
- data/rql_parser.gemspec +21 -24
- metadata +21 -6
- data/lib/rql_parser/format.rb +0 -44
- data/lib/rql_parser/from_params.rb +0 -21
- data/lib/rql_parser/parse.rb +0 -153
- /data/lib/rql_parser/{rules.ebnf → _grammar.ebnf} +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 75d3efb4c2d93963bc05ad192108c57e964d3224b11d5bf0291bd69a2f652ffe
|
4
|
+
data.tar.gz: 99270a824bf63557ce93e29b1db68491f971c5189119b8431356b0cb2444cafc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7598c3cd3007ac838fce30b144f0a3c181313a95855496697d538efbb608b9096779d8a06f6ea2d2fbece42128c65ac4a70aec9b39e6d6cfb8fe3603b079500b
|
7
|
+
data.tar.gz: acc40e93395fcbd2012fa7961c291d46bee87eaa75969155f0cfa8797cca99f94fe9a0c1a25e4d5955148acfba0bcd591dbf86a47222bd8bc78201290da38643
|
data/.rubocop.yml
ADDED
data/CHANGELOG.md
CHANGED
data/Gemfile
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
source
|
1
|
+
source 'https://rubygems.org'
|
2
2
|
|
3
|
-
git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
|
3
|
+
git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
|
4
4
|
|
5
5
|
# Specify your gem's dependencies in rql_parser.gemspec
|
6
6
|
gemspec
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
rql_parser (0.0.
|
4
|
+
rql_parser (0.0.1alpha3)
|
5
5
|
active_interaction (~> 3.6.0)
|
6
6
|
|
7
7
|
GEM
|
@@ -17,10 +17,24 @@ GEM
|
|
17
17
|
minitest (~> 5.1)
|
18
18
|
tzinfo (~> 1.1)
|
19
19
|
concurrent-ruby (1.1.4)
|
20
|
+
diff-lcs (1.3)
|
20
21
|
i18n (1.3.0)
|
21
22
|
concurrent-ruby (~> 1.0)
|
22
23
|
minitest (5.11.3)
|
23
24
|
rake (10.5.0)
|
25
|
+
rspec (3.8.0)
|
26
|
+
rspec-core (~> 3.8.0)
|
27
|
+
rspec-expectations (~> 3.8.0)
|
28
|
+
rspec-mocks (~> 3.8.0)
|
29
|
+
rspec-core (3.8.0)
|
30
|
+
rspec-support (~> 3.8.0)
|
31
|
+
rspec-expectations (3.8.2)
|
32
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
33
|
+
rspec-support (~> 3.8.0)
|
34
|
+
rspec-mocks (3.8.0)
|
35
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
36
|
+
rspec-support (~> 3.8.0)
|
37
|
+
rspec-support (3.8.0)
|
24
38
|
thread_safe (0.3.6)
|
25
39
|
tzinfo (1.2.5)
|
26
40
|
thread_safe (~> 0.1)
|
@@ -32,6 +46,7 @@ DEPENDENCIES
|
|
32
46
|
bundler (~> 1.17)
|
33
47
|
rake (~> 10.0)
|
34
48
|
rql_parser!
|
49
|
+
rspec (~> 3.8.0)
|
35
50
|
|
36
51
|
BUNDLED WITH
|
37
52
|
1.17.1
|
data/README.md
CHANGED
@@ -18,14 +18,19 @@ Or install it yourself as:
|
|
18
18
|
|
19
19
|
## Usage
|
20
20
|
|
21
|
-
See [ActiveInteraction](https://github.com/AaronLasseigne/active_interaction)
|
21
|
+
See [ActiveInteraction](https://github.com/AaronLasseigne/active_interaction), as it is used as a base for the gem
|
22
22
|
|
23
23
|
```ruby
|
24
|
-
#
|
25
|
-
output = RqlParser
|
26
|
-
#
|
24
|
+
# In controller:
|
25
|
+
output = RqlParser.from_params(params.to_unsafe_hash)
|
26
|
+
# To raise an error instead of returning an object:
|
27
|
+
output = RqlParser.from_params!(params.to_unsafe_hash)
|
28
|
+
|
29
|
+
# Parse RQL instead of params:
|
27
30
|
rql = 'eq(hello,world)&ruby=eq=awesome' # your RQL query here
|
28
|
-
output = RqlParser
|
31
|
+
output = RqlParser.parse(rql)
|
32
|
+
# To raise an error instead of returning an object:
|
33
|
+
output = RqlParser.parse!(rql)
|
29
34
|
```
|
30
35
|
|
31
36
|
`output.result` yields a binary tree representing the query.
|
data/Rakefile
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
require
|
2
|
-
task :
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
task default: :spec
|
data/bin/console
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'rql_parser'
|
5
5
|
|
6
6
|
# You can add fixtures and/or initialization code here to make experimenting
|
7
7
|
# with your gem easier. You can also use a different console, if you like.
|
@@ -10,5 +10,5 @@ require "rql_parser"
|
|
10
10
|
# require "pry"
|
11
11
|
# Pry.start
|
12
12
|
|
13
|
-
require
|
13
|
+
require 'irb'
|
14
14
|
IRB.start(__FILE__)
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module RqlParser
|
2
|
+
module Services
|
3
|
+
# Formats input into parser-understandable string
|
4
|
+
class Format < BaseInteraction
|
5
|
+
string :rql
|
6
|
+
|
7
|
+
RQL_FORMAT = /\A[0-9A-Za-z_()|;&,+\-!=<> ]+\z/.freeze
|
8
|
+
|
9
|
+
validates :rql, format: { with: RQL_FORMAT, message: 'has invalid format' }
|
10
|
+
|
11
|
+
def execute
|
12
|
+
res = remove_whitespace(rql)
|
13
|
+
replace_shorthands(res) unless errors.any?
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def remove_whitespace(rql)
|
19
|
+
if /[0-9a-zA-Z] [0-9a-zA-Z(]/.match?(rql)
|
20
|
+
errors.add(:rql, 'has invalid whitespace')
|
21
|
+
else
|
22
|
+
rql.delete(' ')
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def replace_shorthands(rql)
|
27
|
+
res = without_shorthands(rql)
|
28
|
+
if /[!<>=]/.match?(res)
|
29
|
+
errors.add(:rql, 'has invalid shorthands')
|
30
|
+
else
|
31
|
+
res
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def without_shorthands(rql)
|
36
|
+
rql.gsub(/([0-9A-Za-z_]+)=(eq|ne|lt|le|gt|ge)=([0-9A-Za-z_]+)/, '\2(\1,\3)')
|
37
|
+
.gsub(/([0-9A-Za-z_]+)!=([0-9A-Za-z_]+)/, 'ne(\1,\2)')
|
38
|
+
.gsub(/([0-9A-Za-z_]+)<([0-9A-Za-z_]+)/, 'lt(\1,\2)')
|
39
|
+
.gsub(/([0-9A-Za-z_]+)<=([0-9A-Za-z_]+)/, 'le(\1,\2)')
|
40
|
+
.gsub(/([0-9A-Za-z_]+)>([0-9A-Za-z_]+)/, 'gt(\1,\2)')
|
41
|
+
.gsub(/([0-9A-Za-z_]+)>=([0-9A-Za-z_]+)/, 'ge(\1,\2)')
|
42
|
+
.gsub(/([0-9A-Za-z_]+)=([0-9A-Za-z_]+)/, 'eq(\1,\2)')
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RqlParser
|
4
|
+
module Services
|
5
|
+
class FromParams < BaseInteraction
|
6
|
+
hash :params, strip: false
|
7
|
+
|
8
|
+
def execute
|
9
|
+
perform(Parse.run(rql: rql))
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def rql
|
15
|
+
params.except(:controller, :action).map do |k, v|
|
16
|
+
[k, v].compact.join('=')
|
17
|
+
end.join('&')
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,151 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RqlParser
|
4
|
+
module Services
|
5
|
+
class Parse < BaseInteraction
|
6
|
+
string :rql
|
7
|
+
|
8
|
+
def execute
|
9
|
+
formatted = perform(Format.run(inputs))
|
10
|
+
expression(formatted) || errors.add(:rql) unless errors.any?
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def expression(str)
|
16
|
+
group(str) || or_expression(str)
|
17
|
+
end
|
18
|
+
|
19
|
+
def group(str)
|
20
|
+
res = false
|
21
|
+
if /\A\(.+\)\z/.match?(str)
|
22
|
+
res = or_expression(str[1..-2])
|
23
|
+
if res
|
24
|
+
res = { type: :group, args: res } if res[:args].size > 1
|
25
|
+
end
|
26
|
+
end
|
27
|
+
res
|
28
|
+
end
|
29
|
+
|
30
|
+
def or_expression(str)
|
31
|
+
res = []
|
32
|
+
split = str.split(/[;|]/)
|
33
|
+
temp = ''
|
34
|
+
while split.any?
|
35
|
+
temp += split.shift
|
36
|
+
temp_and_exp = and_expression(temp)
|
37
|
+
if temp_and_exp
|
38
|
+
res.push(temp_and_exp)
|
39
|
+
temp = ''
|
40
|
+
else
|
41
|
+
temp += '|'
|
42
|
+
end
|
43
|
+
end
|
44
|
+
return false if temp.present?
|
45
|
+
|
46
|
+
res.size > 1 ? { type: :function, identifier: 'or', args: res } : res.first
|
47
|
+
end
|
48
|
+
|
49
|
+
def and_expression(str)
|
50
|
+
res = []
|
51
|
+
split = str.split(/,/)
|
52
|
+
temp = ''
|
53
|
+
while split.any?
|
54
|
+
temp += split.shift
|
55
|
+
temp_and_exp = function(temp) || group(temp) || and_strict(temp)
|
56
|
+
if temp_and_exp
|
57
|
+
res.push(temp_and_exp)
|
58
|
+
temp = ''
|
59
|
+
else
|
60
|
+
temp += ','
|
61
|
+
end
|
62
|
+
end
|
63
|
+
return false if temp.present?
|
64
|
+
|
65
|
+
res.size > 1 ? { type: :function, identifier: 'and', args: res } : res.first
|
66
|
+
end
|
67
|
+
|
68
|
+
def and_strict(str)
|
69
|
+
res = []
|
70
|
+
split = str.split(/&/)
|
71
|
+
temp = ''
|
72
|
+
while split.any?
|
73
|
+
temp += split.shift
|
74
|
+
temp_and_exp = function(temp) || group(temp)
|
75
|
+
if temp_and_exp
|
76
|
+
res.push(temp_and_exp)
|
77
|
+
temp = ''
|
78
|
+
else
|
79
|
+
temp += ','
|
80
|
+
end
|
81
|
+
end
|
82
|
+
return false if temp.present?
|
83
|
+
|
84
|
+
res.size > 1 ? { type: :function, identifier: 'and', args: res } : res.first
|
85
|
+
end
|
86
|
+
|
87
|
+
def function(str)
|
88
|
+
res = false
|
89
|
+
if /\A[a-z]+\(.+\)\z/.match?(str)
|
90
|
+
identifier = str.match(/\A([a-z]+)/)[1]
|
91
|
+
args = str.match(/\A[a-z]+\((.+)\)\z/)[1]
|
92
|
+
temp_args = args(args)
|
93
|
+
res = { type: :function, identifier: identifier, args: temp_args } if temp_args
|
94
|
+
end
|
95
|
+
res
|
96
|
+
end
|
97
|
+
|
98
|
+
def args(str)
|
99
|
+
res = []
|
100
|
+
split = str.split(',')
|
101
|
+
temp = ''
|
102
|
+
while split.any?
|
103
|
+
temp += split.shift
|
104
|
+
temp_arg = arg(temp)
|
105
|
+
if temp_arg
|
106
|
+
res.push(temp_arg)
|
107
|
+
temp = ''
|
108
|
+
else
|
109
|
+
temp += ','
|
110
|
+
end
|
111
|
+
end
|
112
|
+
return false if temp.present?
|
113
|
+
|
114
|
+
res
|
115
|
+
end
|
116
|
+
|
117
|
+
def arg(str)
|
118
|
+
expression(str) || array_of_values(str) || value(str)
|
119
|
+
end
|
120
|
+
|
121
|
+
def array_of_values(str)
|
122
|
+
return false unless /\A\(.+\)\z/.match?(str)
|
123
|
+
|
124
|
+
res = []
|
125
|
+
split = str[1..-2].split(',')
|
126
|
+
temp = ''
|
127
|
+
while split.any?
|
128
|
+
temp += split.shift
|
129
|
+
temp_arg = value(temp)
|
130
|
+
if temp_arg
|
131
|
+
res.push(temp_arg)
|
132
|
+
temp = ''
|
133
|
+
else
|
134
|
+
temp += ','
|
135
|
+
end
|
136
|
+
end
|
137
|
+
return false if temp.present?
|
138
|
+
|
139
|
+
{ arg_array: res }
|
140
|
+
end
|
141
|
+
|
142
|
+
def value(str)
|
143
|
+
if str.match?(/\A[_0-9a-zA-Z]+\z/)
|
144
|
+
{ arg: str }
|
145
|
+
else
|
146
|
+
false
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
data/lib/rql_parser/version.rb
CHANGED
data/lib/rql_parser.rb
CHANGED
@@ -1,5 +1,26 @@
|
|
1
1
|
require 'active_interaction'
|
2
2
|
|
3
|
-
module
|
3
|
+
# Base module of the parser
|
4
|
+
module RqlParser
|
5
|
+
def self.from_params(params)
|
6
|
+
Services::FromParams.run(params)
|
7
|
+
end
|
4
8
|
|
5
|
-
|
9
|
+
def self.from_params!(params)
|
10
|
+
Services::FromParams.run!(params)
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.parse(rql)
|
14
|
+
Services::Parse.run(rql)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.parse!(rql)
|
18
|
+
Services::Parse.run!(rql)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
require 'rql_parser/version'
|
23
|
+
require 'rql_parser/base_interaction'
|
24
|
+
require 'rql_parser/services/from_params'
|
25
|
+
require 'rql_parser/services/format'
|
26
|
+
require 'rql_parser/services/parse'
|
data/rql_parser.gemspec
CHANGED
@@ -1,40 +1,37 @@
|
|
1
|
-
|
2
|
-
lib = File.expand_path("../lib", __FILE__)
|
1
|
+
lib = File.expand_path('lib', __dir__)
|
3
2
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require
|
3
|
+
require 'rql_parser/version'
|
5
4
|
|
6
5
|
Gem::Specification.new do |spec|
|
7
|
-
spec.name =
|
6
|
+
spec.name = 'rql_parser'
|
8
7
|
spec.version = RqlParser::VERSION
|
9
|
-
spec.authors = [
|
10
|
-
spec.email = [
|
8
|
+
spec.authors = ['Aliaksei Kharkou']
|
9
|
+
spec.email = ['Aliaksei.Kharkou@itechart-group.com']
|
11
10
|
|
12
|
-
spec.summary =
|
13
|
-
spec.description =
|
14
|
-
spec.homepage =
|
15
|
-
spec.license =
|
11
|
+
spec.summary = 'RqlParser is a gem for using RQL as valid params'
|
12
|
+
spec.description = 'RqlParser is a gem for using RQL as valid params'
|
13
|
+
spec.homepage = 'https://github.com/deorigosa-work/rql-parser'
|
14
|
+
spec.license = 'MIT'
|
16
15
|
|
17
16
|
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
18
17
|
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
raise "RubyGems 2.0 or newer is required to protect against " \
|
25
|
-
"public gem pushes."
|
26
|
-
end
|
18
|
+
raise 'RubyGems 2.0 or newer is required to protect against public gem pushes.' unless spec.respond_to?(:metadata)
|
19
|
+
|
20
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
21
|
+
spec.metadata['source_code_uri'] = 'https://github.com/deorigosa-work/rql-parser'
|
22
|
+
spec.metadata['changelog_uri'] = 'https://github.com/deorigosa-work/rql-parser/CHANGELOG.md'
|
27
23
|
|
28
24
|
# Specify which files should be added to the gem when it is released.
|
29
25
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
30
|
-
spec.files
|
26
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
31
27
|
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
32
28
|
end
|
33
|
-
spec.bindir =
|
29
|
+
spec.bindir = 'exe'
|
34
30
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
35
|
-
spec.require_paths = [
|
31
|
+
spec.require_paths = ['lib']
|
36
32
|
|
37
|
-
spec.add_dependency
|
38
|
-
spec.add_development_dependency
|
39
|
-
spec.add_development_dependency
|
33
|
+
spec.add_dependency 'active_interaction', '~> 3.6.0'
|
34
|
+
spec.add_development_dependency 'bundler', '~> 1.17'
|
35
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
36
|
+
spec.add_development_dependency 'rspec', '~> 3.8.0'
|
40
37
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rql_parser
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.1alpha4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aliaksei Kharkou
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-12-
|
11
|
+
date: 2018-12-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: active_interaction
|
@@ -52,6 +52,20 @@ dependencies:
|
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '10.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 3.8.0
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 3.8.0
|
55
69
|
description: RqlParser is a gem for using RQL as valid params
|
56
70
|
email:
|
57
71
|
- Aliaksei.Kharkou@itechart-group.com
|
@@ -60,6 +74,7 @@ extensions: []
|
|
60
74
|
extra_rdoc_files: []
|
61
75
|
files:
|
62
76
|
- ".gitignore"
|
77
|
+
- ".rubocop.yml"
|
63
78
|
- CHANGELOG.md
|
64
79
|
- CODE_OF_CONDUCT.md
|
65
80
|
- Gemfile
|
@@ -70,11 +85,11 @@ files:
|
|
70
85
|
- bin/console
|
71
86
|
- bin/setup
|
72
87
|
- lib/rql_parser.rb
|
88
|
+
- lib/rql_parser/_grammar.ebnf
|
73
89
|
- lib/rql_parser/base_interaction.rb
|
74
|
-
- lib/rql_parser/format.rb
|
75
|
-
- lib/rql_parser/from_params.rb
|
76
|
-
- lib/rql_parser/parse.rb
|
77
|
-
- lib/rql_parser/rules.ebnf
|
90
|
+
- lib/rql_parser/services/format.rb
|
91
|
+
- lib/rql_parser/services/from_params.rb
|
92
|
+
- lib/rql_parser/services/parse.rb
|
78
93
|
- lib/rql_parser/version.rb
|
79
94
|
- rql_parser.gemspec
|
80
95
|
homepage: https://github.com/deorigosa-work/rql-parser
|
data/lib/rql_parser/format.rb
DELETED
@@ -1,44 +0,0 @@
|
|
1
|
-
module RqlParser
|
2
|
-
class Format < BaseInteraction
|
3
|
-
string :rql
|
4
|
-
|
5
|
-
RQL_FORMAT = /\A[0-9A-Za-z_()|&,+\-!=<> ]+\z/.freeze
|
6
|
-
|
7
|
-
validates :rql, format: { with: RQL_FORMAT }
|
8
|
-
|
9
|
-
def execute
|
10
|
-
res = remove_whitespace(rql)
|
11
|
-
replace_shorthands(res)
|
12
|
-
end
|
13
|
-
|
14
|
-
private
|
15
|
-
|
16
|
-
def remove_whitespace(rql)
|
17
|
-
if /[0-9a-zA-Z] [0-9a-zA-Z(]/.match?(rql)
|
18
|
-
errors.add(:rql_parser, 'has invalid whitespace')
|
19
|
-
else
|
20
|
-
rql.delete(' ')
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def replace_shorthands(rql)
|
25
|
-
res = without_shorthands(rql)
|
26
|
-
if /[!<>=]/.match?(res)
|
27
|
-
errors.add(:rql_parser, 'has invalid shorthands')
|
28
|
-
else
|
29
|
-
res
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
def without_shorthands(rql)
|
34
|
-
rql.gsub(/([0-9A-Za-z_]+)=(eq|ne|lt|le|gt|ge)=([0-9A-Za-z_]+)/,
|
35
|
-
'\2(\1,\3)')
|
36
|
-
.gsub(/([0-9A-Za-z_]+)!=([0-9A-Za-z_]+)/, 'ne(\1,\2)')
|
37
|
-
.gsub(/([0-9A-Za-z_]+)<([0-9A-Za-z_]+)/, 'lt(\1,\2)')
|
38
|
-
.gsub(/([0-9A-Za-z_]+)<=([0-9A-Za-z_]+)/, 'le(\1,\2)')
|
39
|
-
.gsub(/([0-9A-Za-z_]+)>([0-9A-Za-z_]+)/, 'gt(\1,\2)')
|
40
|
-
.gsub(/([0-9A-Za-z_]+)>=([0-9A-Za-z_]+)/, 'ge(\1,\2)')
|
41
|
-
.gsub(/([0-9A-Za-z_]+)=([0-9A-Za-z_]+)/, 'eq(\1,\2)')
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
@@ -1,21 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module RqlParser
|
4
|
-
#
|
5
|
-
# some doc
|
6
|
-
class FromParams < BaseInteraction
|
7
|
-
hash :params, strip: false
|
8
|
-
|
9
|
-
def execute
|
10
|
-
perform RqlParser::Parse.run(rql: to_rql(params))
|
11
|
-
end
|
12
|
-
|
13
|
-
private
|
14
|
-
|
15
|
-
def to_rql(params)
|
16
|
-
params.except(:controller, :action).map do |k, v|
|
17
|
-
[k, v].compact.join('=')
|
18
|
-
end.join('&')
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
data/lib/rql_parser/parse.rb
DELETED
@@ -1,153 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module RqlParser
|
4
|
-
class Parse < BaseInteraction
|
5
|
-
string :rql
|
6
|
-
|
7
|
-
def execute
|
8
|
-
formatted = perform(Format.run(inputs))
|
9
|
-
expression(formatted) || errors.add(:rql) unless errors.any?
|
10
|
-
end
|
11
|
-
|
12
|
-
private
|
13
|
-
|
14
|
-
def expression(str)
|
15
|
-
group(str) || or_expression(str)
|
16
|
-
end
|
17
|
-
|
18
|
-
def group(str)
|
19
|
-
res = false
|
20
|
-
if /\A\(.+\)\z/.match?(str)
|
21
|
-
res = or_expression(str[1..-2])
|
22
|
-
if res
|
23
|
-
res = { type: :group, args: res } if res[:args].size > 1
|
24
|
-
end
|
25
|
-
end
|
26
|
-
res
|
27
|
-
end
|
28
|
-
|
29
|
-
def or_expression(str)
|
30
|
-
res = []
|
31
|
-
split = str.split(/[|;]/)
|
32
|
-
temp = ''
|
33
|
-
while split.any?
|
34
|
-
temp += split.shift
|
35
|
-
temp_and_exp = and_expression(temp)
|
36
|
-
if temp_and_exp
|
37
|
-
res.push(temp_and_exp)
|
38
|
-
temp = ''
|
39
|
-
else
|
40
|
-
temp += ';'
|
41
|
-
end
|
42
|
-
end
|
43
|
-
return false if temp.present?
|
44
|
-
|
45
|
-
res.size > 1 ? { type: :function, identifier: 'or', args: res } : res.first
|
46
|
-
end
|
47
|
-
|
48
|
-
def and_expression(str)
|
49
|
-
res = []
|
50
|
-
split = str.split(/,/)
|
51
|
-
temp = ''
|
52
|
-
while split.any?
|
53
|
-
temp += split.shift
|
54
|
-
temp_and_exp = function(temp) || group(temp) || and_strict(temp)
|
55
|
-
if temp_and_exp
|
56
|
-
res.push(temp_and_exp)
|
57
|
-
temp = ''
|
58
|
-
else
|
59
|
-
temp += ','
|
60
|
-
end
|
61
|
-
end
|
62
|
-
return false if temp.present?
|
63
|
-
|
64
|
-
res.size > 1 ? { type: :function, identifier: 'and', args: res } : res.first
|
65
|
-
end
|
66
|
-
|
67
|
-
def and_strict(str)
|
68
|
-
res = []
|
69
|
-
split = str.split(/&/)
|
70
|
-
temp = ''
|
71
|
-
while split.any?
|
72
|
-
temp += split.shift
|
73
|
-
temp_and_exp = function(temp) || group(temp)
|
74
|
-
if temp_and_exp
|
75
|
-
res.push(temp_and_exp)
|
76
|
-
temp = ''
|
77
|
-
else
|
78
|
-
temp += ','
|
79
|
-
end
|
80
|
-
end
|
81
|
-
return false if temp.present?
|
82
|
-
|
83
|
-
res.size > 1 ? { type: :function, identifier: 'and', args: res } : res.first
|
84
|
-
end
|
85
|
-
|
86
|
-
def function(str)
|
87
|
-
res = false
|
88
|
-
if /\A[a-z]+\(.+\)\z/.match?(str)
|
89
|
-
identifier = str.match(/\A([a-z]+)/)[1]
|
90
|
-
args = str.match(/\A[a-z]+\((.+)\)\z/)[1]
|
91
|
-
temp_args = args(args)
|
92
|
-
if temp_args
|
93
|
-
res = { type: :function, identifier: identifier, args: temp_args }
|
94
|
-
else
|
95
|
-
false
|
96
|
-
end
|
97
|
-
end
|
98
|
-
res
|
99
|
-
end
|
100
|
-
|
101
|
-
def args(str)
|
102
|
-
res = []
|
103
|
-
split = str.split(',')
|
104
|
-
temp = ''
|
105
|
-
while split.any?
|
106
|
-
temp += split.shift
|
107
|
-
temp_arg = arg(temp)
|
108
|
-
if temp_arg
|
109
|
-
res.push(temp_arg)
|
110
|
-
temp = ''
|
111
|
-
else
|
112
|
-
temp += ','
|
113
|
-
end
|
114
|
-
end
|
115
|
-
return false if temp.present?
|
116
|
-
|
117
|
-
res
|
118
|
-
end
|
119
|
-
|
120
|
-
def arg(str)
|
121
|
-
expression(str) || array_of_values(str) || value(str)
|
122
|
-
end
|
123
|
-
|
124
|
-
def array_of_values(str)
|
125
|
-
return false unless /\A\(.+\)\z/.match?(str)
|
126
|
-
|
127
|
-
res = []
|
128
|
-
split = str[1..-2].split(',')
|
129
|
-
temp = ''
|
130
|
-
while split.any?
|
131
|
-
temp += split.shift
|
132
|
-
temp_arg = value(temp)
|
133
|
-
if temp_arg
|
134
|
-
res.push(temp_arg)
|
135
|
-
temp = ''
|
136
|
-
else
|
137
|
-
temp += ','
|
138
|
-
end
|
139
|
-
end
|
140
|
-
return false if temp.present?
|
141
|
-
|
142
|
-
{ arg_array: res }
|
143
|
-
end
|
144
|
-
|
145
|
-
def value(str)
|
146
|
-
if str.match?(/\A[_0-9a-zA-Z]+\z/)
|
147
|
-
{ arg: str }
|
148
|
-
else
|
149
|
-
false
|
150
|
-
end
|
151
|
-
end
|
152
|
-
end
|
153
|
-
end
|
File without changes
|