logical_query_parser 0.1.0
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 +7 -0
- data/.gitignore +10 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/CODE_OF_CONDUCT.md +49 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +124 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/logical_query.rb +889 -0
- data/lib/logical_query.treetop +62 -0
- data/lib/logical_query_parser/nodes/active_record.rb +73 -0
- data/lib/logical_query_parser/nodes/base.rb +34 -0
- data/lib/logical_query_parser/version.rb +3 -0
- data/lib/logical_query_parser.rb +18 -0
- data/logical_query_parser.gemspec +30 -0
- metadata +160 -0
@@ -0,0 +1,62 @@
|
|
1
|
+
grammar LogicalQuery
|
2
|
+
rule exp
|
3
|
+
any:(cond / exp_paren / literal_seq / literal) <ExpNode>
|
4
|
+
end
|
5
|
+
|
6
|
+
rule exp_paren
|
7
|
+
lparen sp* exp sp* rparen <ExpParenNode>
|
8
|
+
end
|
9
|
+
|
10
|
+
rule cond
|
11
|
+
lexp:(exp_paren / literal) sp+ logic:(land / lor) sp+ rexp:exp <CondNode>
|
12
|
+
end
|
13
|
+
|
14
|
+
rule literal_seq
|
15
|
+
lliteral:literal sp+ rliteral:(literal_seq / literal) <LiteralSeqNode>
|
16
|
+
end
|
17
|
+
|
18
|
+
rule literal
|
19
|
+
negative:negative* word <LiteralNode>
|
20
|
+
end
|
21
|
+
|
22
|
+
rule word
|
23
|
+
(quoted_word / unquoted_word) <WordNode>
|
24
|
+
end
|
25
|
+
|
26
|
+
rule quoted_word
|
27
|
+
'"' ('\"' / !'"' .)* '"'
|
28
|
+
end
|
29
|
+
|
30
|
+
rule unquoted_word
|
31
|
+
atom+
|
32
|
+
end
|
33
|
+
|
34
|
+
rule land
|
35
|
+
('AND' / 'and') <AndNode>
|
36
|
+
end
|
37
|
+
|
38
|
+
rule lor
|
39
|
+
('OR' / 'or') <OrNode>
|
40
|
+
end
|
41
|
+
|
42
|
+
rule lparen
|
43
|
+
'(' <LParenNode>
|
44
|
+
end
|
45
|
+
|
46
|
+
rule rparen
|
47
|
+
')' <RParenNode>
|
48
|
+
end
|
49
|
+
|
50
|
+
rule negative
|
51
|
+
('-' / '-' / '-') <NegativeNode>
|
52
|
+
end
|
53
|
+
|
54
|
+
rule sp
|
55
|
+
' ' / ' '
|
56
|
+
end
|
57
|
+
|
58
|
+
rule atom
|
59
|
+
!(lparen / rparen / negative / sp) .
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module LogicalQuery
|
2
|
+
module ExpNode
|
3
|
+
def to_sql(opts = {}, sql = '')
|
4
|
+
any.to_sql(opts, sql)
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
module ExpParenNode
|
9
|
+
def to_sql(opts, sql = '')
|
10
|
+
lparen.to_sql(opts, sql)
|
11
|
+
exp.to_sql(opts, sql)
|
12
|
+
rparen.to_sql(opts, sql)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
module CondNode
|
17
|
+
def to_sql(opts, sql = '')
|
18
|
+
lexp.to_sql(opts, sql)
|
19
|
+
logic.to_sql(opts, sql)
|
20
|
+
rexp.to_sql(opts, sql)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
module LParenNode
|
25
|
+
def to_sql(opts, sql = '')
|
26
|
+
sql << '('
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
module RParenNode
|
31
|
+
def to_sql(opts, sql = '')
|
32
|
+
sql << ')'
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
module AndNode
|
37
|
+
def to_sql(opts, sql = '')
|
38
|
+
sql << ' AND '
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
module OrNode
|
43
|
+
def to_sql(opts, sql = '')
|
44
|
+
sql << ' OR '
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
module LiteralSeqNode
|
49
|
+
def to_sql(opts, sql = '')
|
50
|
+
lliteral.to_sql(opts, sql)
|
51
|
+
sql << ' AND '
|
52
|
+
rliteral.to_sql(opts, sql)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
module LiteralNode
|
57
|
+
def to_sql(opts, sql = '')
|
58
|
+
operator, logic = negative.elements.size > 0 ? [:does_not_match, :and] : [:matches, :or]
|
59
|
+
unquoted = LogicalQuery.unquote(word.text_value)
|
60
|
+
|
61
|
+
arel_table = opts[:model].arel_table
|
62
|
+
relations = opts[:columns].map { |c| arel_table[c].send(operator, "%#{unquoted}%") }.reduce(logic)
|
63
|
+
sql << relations.to_sql
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
class << self
|
68
|
+
def unquote(str)
|
69
|
+
str = str[1..-2].to_s.gsub(/\\(.)/, '\1') if str[0] == '"' && str[-1] == '"'
|
70
|
+
str
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module LogicalQuery
|
2
|
+
module ExpNode
|
3
|
+
end
|
4
|
+
|
5
|
+
module ExpParenNode
|
6
|
+
end
|
7
|
+
|
8
|
+
module CondNode
|
9
|
+
end
|
10
|
+
|
11
|
+
module LiteralSeqNode
|
12
|
+
end
|
13
|
+
|
14
|
+
module LiteralNode
|
15
|
+
end
|
16
|
+
|
17
|
+
module WordNode
|
18
|
+
end
|
19
|
+
|
20
|
+
module AndNode
|
21
|
+
end
|
22
|
+
|
23
|
+
module OrNode
|
24
|
+
end
|
25
|
+
|
26
|
+
module LParenNode
|
27
|
+
end
|
28
|
+
|
29
|
+
module RParenNode
|
30
|
+
end
|
31
|
+
|
32
|
+
module NegativeNode
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'treetop'
|
2
|
+
require 'logical_query'
|
3
|
+
require 'logical_query_parser/version'
|
4
|
+
require 'logical_query_parser/nodes/base'
|
5
|
+
require 'logical_query_parser/nodes/active_record' if defined? ActiveRecord::Base
|
6
|
+
|
7
|
+
class LogicalQueryParser < Treetop::Runtime::CompiledParser
|
8
|
+
class << self
|
9
|
+
def walk_tree(node, &block)
|
10
|
+
yield node
|
11
|
+
unless node.elements.nil?
|
12
|
+
node.elements.each do |element|
|
13
|
+
walk_tree(element, &block)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'logical_query_parser/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "logical_query_parser"
|
8
|
+
spec.version = LogicalQuery::VERSION
|
9
|
+
spec.authors = ["Yoshikazu Kaneta"]
|
10
|
+
spec.email = ["kaneta@sitebridge.co.jp"]
|
11
|
+
|
12
|
+
spec.summary = %q{A parser for a logical query string.}
|
13
|
+
spec.description = %q{A parser to generate a tree structure from a logical query string using treetop.}
|
14
|
+
spec.homepage = "https://github.com/kanety/logical_query_parser"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
18
|
+
spec.bindir = "exe"
|
19
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
22
|
+
spec.add_dependency "treetop", "~> 1.6.8"
|
23
|
+
|
24
|
+
spec.add_development_dependency "bundler", "~> 1.12"
|
25
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
26
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
27
|
+
spec.add_development_dependency "simplecov", "~> 0.12.0"
|
28
|
+
spec.add_development_dependency "activerecord", ">= 4.2"
|
29
|
+
spec.add_development_dependency "sqlite3"
|
30
|
+
end
|
metadata
ADDED
@@ -0,0 +1,160 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: logical_query_parser
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Yoshikazu Kaneta
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-10-12 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: treetop
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.6.8
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.6.8
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.12'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.12'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '10.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
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.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.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: simplecov
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 0.12.0
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 0.12.0
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: activerecord
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '4.2'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '4.2'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: sqlite3
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
description: A parser to generate a tree structure from a logical query string using
|
112
|
+
treetop.
|
113
|
+
email:
|
114
|
+
- kaneta@sitebridge.co.jp
|
115
|
+
executables: []
|
116
|
+
extensions: []
|
117
|
+
extra_rdoc_files: []
|
118
|
+
files:
|
119
|
+
- ".gitignore"
|
120
|
+
- ".rspec"
|
121
|
+
- ".travis.yml"
|
122
|
+
- CODE_OF_CONDUCT.md
|
123
|
+
- Gemfile
|
124
|
+
- LICENSE.txt
|
125
|
+
- README.md
|
126
|
+
- Rakefile
|
127
|
+
- bin/console
|
128
|
+
- bin/setup
|
129
|
+
- lib/logical_query.rb
|
130
|
+
- lib/logical_query.treetop
|
131
|
+
- lib/logical_query_parser.rb
|
132
|
+
- lib/logical_query_parser/nodes/active_record.rb
|
133
|
+
- lib/logical_query_parser/nodes/base.rb
|
134
|
+
- lib/logical_query_parser/version.rb
|
135
|
+
- logical_query_parser.gemspec
|
136
|
+
homepage: https://github.com/kanety/logical_query_parser
|
137
|
+
licenses:
|
138
|
+
- MIT
|
139
|
+
metadata: {}
|
140
|
+
post_install_message:
|
141
|
+
rdoc_options: []
|
142
|
+
require_paths:
|
143
|
+
- lib
|
144
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
145
|
+
requirements:
|
146
|
+
- - ">="
|
147
|
+
- !ruby/object:Gem::Version
|
148
|
+
version: '0'
|
149
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
150
|
+
requirements:
|
151
|
+
- - ">="
|
152
|
+
- !ruby/object:Gem::Version
|
153
|
+
version: '0'
|
154
|
+
requirements: []
|
155
|
+
rubyforge_project:
|
156
|
+
rubygems_version: 2.5.1
|
157
|
+
signing_key:
|
158
|
+
specification_version: 4
|
159
|
+
summary: A parser for a logical query string.
|
160
|
+
test_files: []
|