nql 0.0.2 → 0.0.3
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.
- data/README.md +54 -54
- data/lib/nql.rb +5 -4
- data/lib/nql/grammar.rb +3 -3
- data/lib/nql/grammar.treetop +2 -2
- data/lib/nql/invalid_expression_error.rb +7 -0
- data/lib/nql/version.rb +1 -1
- data/spec/comparison_parser_spec.rb +2 -2
- data/spec/ransack_spec.rb +4 -4
- data/spec/sql_spec.rb +8 -8
- metadata +14 -13
data/README.md
CHANGED
@@ -1,54 +1,54 @@
|
|
1
|
-
# NQL
|
2
|
-
|
3
|
-
Natural Query Language built on top of ActiveRecord and Ransack
|
4
|
-
|
5
|
-
## Installation
|
6
|
-
|
7
|
-
Add this line to your application's Gemfile:
|
8
|
-
|
9
|
-
gem 'nql'
|
10
|
-
|
11
|
-
And then execute:
|
12
|
-
|
13
|
-
$ bundle
|
14
|
-
|
15
|
-
Or install it yourself as:
|
16
|
-
|
17
|
-
$ gem install nql
|
18
|
-
|
19
|
-
## Supported comparators
|
20
|
-
|
21
|
-
----------------------------------
|
22
|
-
| Symbol | Description |
|
23
|
-
----------------------------------
|
24
|
-
|
|
25
|
-
| = | Equals |
|
26
|
-
| != | Not equals |
|
27
|
-
| > | Grater than |
|
28
|
-
| >= | Grater or equals than |
|
29
|
-
| < | Less than |
|
30
|
-
| <= | Less or equals than |
|
31
|
-
----------------------------------
|
32
|
-
|
33
|
-
|
34
|
-
## Usage
|
35
|
-
|
36
|
-
Converts from natural language to query expression
|
37
|
-
|
38
|
-
q = '(name
|
39
|
-
Country.search(NQL.to_ransack(q)).result.to_sql
|
40
|
-
=> "SELECT coutries.* FROM countries WHERE (countries.name LIKE '%arg%' OR countries.name LIKE '%br%') AND region = 'south'"
|
41
|
-
|
42
|
-
### Joins support
|
43
|
-
|
44
|
-
q = 'cities.name
|
45
|
-
Country.search(NQL.to_ransack(q)).result.to_sql
|
46
|
-
=> "SELECT countries.* FROM countries LEFT OUTER JOIN cities ON countries.id = cities.country_id WHERE cities.name LIKE '%buenos%'"
|
47
|
-
|
48
|
-
## Contributing
|
49
|
-
|
50
|
-
1. Fork it
|
51
|
-
2. Create your feature branch (`git checkout -b my-new-feature`)
|
52
|
-
3. Commit your changes (`git commit -am 'Added some feature'`)
|
53
|
-
4. Push to the branch (`git push origin my-new-feature`)
|
54
|
-
5. Create new Pull Request
|
1
|
+
# NQL
|
2
|
+
|
3
|
+
Natural Query Language built on top of ActiveRecord and Ransack
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'nql'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install nql
|
18
|
+
|
19
|
+
## Supported comparators
|
20
|
+
|
21
|
+
----------------------------------
|
22
|
+
| Symbol | Description |
|
23
|
+
----------------------------------
|
24
|
+
| : | Contains |
|
25
|
+
| = | Equals |
|
26
|
+
| != | Not equals |
|
27
|
+
| > | Grater than |
|
28
|
+
| >= | Grater or equals than |
|
29
|
+
| < | Less than |
|
30
|
+
| <= | Less or equals than |
|
31
|
+
----------------------------------
|
32
|
+
|
33
|
+
|
34
|
+
## Usage
|
35
|
+
|
36
|
+
Converts from natural language to query expression
|
37
|
+
|
38
|
+
q = '(name: arg | name: br) & region = south'
|
39
|
+
Country.search(NQL.to_ransack(q)).result.to_sql
|
40
|
+
=> "SELECT coutries.* FROM countries WHERE (countries.name LIKE '%arg%' OR countries.name LIKE '%br%') AND region = 'south'"
|
41
|
+
|
42
|
+
### Joins support
|
43
|
+
|
44
|
+
q = 'cities.name: buenos'
|
45
|
+
Country.search(NQL.to_ransack(q)).result.to_sql
|
46
|
+
=> "SELECT countries.* FROM countries LEFT OUTER JOIN cities ON countries.id = cities.country_id WHERE cities.name LIKE '%buenos%'"
|
47
|
+
|
48
|
+
## Contributing
|
49
|
+
|
50
|
+
1. Fork it
|
51
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
52
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
53
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
54
|
+
5. Create new Pull Request
|
data/lib/nql.rb
CHANGED
@@ -5,20 +5,21 @@ require 'ransack'
|
|
5
5
|
|
6
6
|
require 'nql/version'
|
7
7
|
require 'nql/grammar'
|
8
|
+
require 'nql/invalid_expression_error'
|
8
9
|
|
9
10
|
module NQL
|
10
11
|
|
11
12
|
def self.to_ransack(query)
|
12
13
|
return nil if query.nil? || query.strip.empty?
|
13
|
-
expression =
|
14
|
-
|
14
|
+
expression = parser.parse(query)
|
15
|
+
raise InvalidExpressionError.new(parser.failure_reason) unless expression
|
15
16
|
expression.to_ransack
|
16
17
|
end
|
17
18
|
|
18
19
|
private
|
19
20
|
|
20
|
-
def self.
|
21
|
-
|
21
|
+
def self.parser
|
22
|
+
@@parser ||= SyntaxParser.new
|
22
23
|
end
|
23
24
|
|
24
25
|
end
|
data/lib/nql/grammar.rb
CHANGED
@@ -393,7 +393,7 @@ module NQL
|
|
393
393
|
'>=' => 'gteq',
|
394
394
|
'<' => 'lt',
|
395
395
|
'<=' => 'lteq',
|
396
|
-
'
|
396
|
+
':' => 'cont'
|
397
397
|
}
|
398
398
|
comparators[text_value]
|
399
399
|
end
|
@@ -473,11 +473,11 @@ module NQL
|
|
473
473
|
if r7
|
474
474
|
r1 = r7
|
475
475
|
else
|
476
|
-
if has_terminal?('
|
476
|
+
if has_terminal?(':', false, index)
|
477
477
|
r8 = instantiate_node(SyntaxNode,input, index...(index + 1))
|
478
478
|
@index += 1
|
479
479
|
else
|
480
|
-
terminal_parse_failure('
|
480
|
+
terminal_parse_failure(':')
|
481
481
|
r8 = nil
|
482
482
|
end
|
483
483
|
if r8
|
data/lib/nql/grammar.treetop
CHANGED
@@ -68,7 +68,7 @@ module NQL
|
|
68
68
|
end
|
69
69
|
|
70
70
|
rule comparator
|
71
|
-
('=' / '!=' / '>' / '>=' / '<' / '<=' / '
|
71
|
+
('=' / '!=' / '>' / '>=' / '<' / '<=' / ':')+ {
|
72
72
|
def to_ransack
|
73
73
|
comparators = {
|
74
74
|
'=' => 'eq',
|
@@ -77,7 +77,7 @@ module NQL
|
|
77
77
|
'>=' => 'gteq',
|
78
78
|
'<' => 'lt',
|
79
79
|
'<=' => 'lteq',
|
80
|
-
'
|
80
|
+
':' => 'cont'
|
81
81
|
}
|
82
82
|
comparators[text_value]
|
83
83
|
end
|
data/lib/nql/version.rb
CHANGED
@@ -55,10 +55,10 @@ describe NQL::SyntaxParser, '-> Comparison' do
|
|
55
55
|
end
|
56
56
|
|
57
57
|
it 'Contains' do
|
58
|
-
tree = parser.parse('var
|
58
|
+
tree = parser.parse('var : value')
|
59
59
|
|
60
60
|
tree.comparison.variable.text_value.should eq 'var'
|
61
|
-
tree.comparison.comparator.text_value.should eq '
|
61
|
+
tree.comparison.comparator.text_value.should eq ':'
|
62
62
|
tree.comparison.value.text_value.should eq 'value'
|
63
63
|
end
|
64
64
|
|
data/spec/ransack_spec.rb
CHANGED
@@ -55,7 +55,7 @@ describe 'Ransack Query' do
|
|
55
55
|
end
|
56
56
|
|
57
57
|
it 'Contains' do
|
58
|
-
q = parser.parse('id
|
58
|
+
q = parser.parse('id : 1234').to_ransack
|
59
59
|
|
60
60
|
q[:c][0].should have_attribute 'id'
|
61
61
|
q[:c][0].should have_predicate 'cont'
|
@@ -87,7 +87,7 @@ describe 'Ransack Query' do
|
|
87
87
|
end
|
88
88
|
|
89
89
|
it 'Or' do
|
90
|
-
q = parser.parse('id < 1234 | name
|
90
|
+
q = parser.parse('id < 1234 | name : abcd').to_ransack
|
91
91
|
|
92
92
|
q[:g][0][:m].should eq 'or'
|
93
93
|
q[:g][0][:c][0].should have_attribute 'id'
|
@@ -99,7 +99,7 @@ describe 'Ransack Query' do
|
|
99
99
|
end
|
100
100
|
|
101
101
|
it 'And then Or' do
|
102
|
-
q = parser.parse('id > 1234 & name = abcd | name
|
102
|
+
q = parser.parse('id > 1234 & name = abcd | name : efgh').to_ransack
|
103
103
|
|
104
104
|
q[:g][0][:m].should eq 'and'
|
105
105
|
q[:g][0][:c][0].should have_attribute 'id'
|
@@ -115,7 +115,7 @@ describe 'Ransack Query' do
|
|
115
115
|
end
|
116
116
|
|
117
117
|
it 'With parentheses' do
|
118
|
-
q = parser.parse('(id > 1234 & name = abcd) | name
|
118
|
+
q = parser.parse('(id > 1234 & name = abcd) | name : efgh').to_ransack
|
119
119
|
|
120
120
|
q[:g][0][:g][0][:m].should eq 'and'
|
121
121
|
q[:g][0][:g][0][:c][0].should have_attribute 'id'
|
data/spec/sql_spec.rb
CHANGED
@@ -41,7 +41,7 @@ describe 'SQL generation' do
|
|
41
41
|
end
|
42
42
|
|
43
43
|
it 'Contains' do
|
44
|
-
q = 'name
|
44
|
+
q = 'name : abcd'
|
45
45
|
Country.search(NQL.to_ransack(q)).result.should produce_sql "SELECT \"countries\".* FROM \"countries\" WHERE (\"countries\".\"name\" LIKE '%abcd%')"
|
46
46
|
end
|
47
47
|
|
@@ -55,17 +55,17 @@ describe 'SQL generation' do
|
|
55
55
|
end
|
56
56
|
|
57
57
|
it 'Or' do
|
58
|
-
q = 'id < 1234 | name
|
58
|
+
q = 'id < 1234 | name : abcd'
|
59
59
|
Country.search(NQL.to_ransack(q)).result.should produce_sql "SELECT \"countries\".* FROM \"countries\" WHERE ((\"countries\".\"id\" < 1234 OR \"countries\".\"name\" LIKE '%abcd%'))"
|
60
60
|
end
|
61
61
|
|
62
62
|
it 'And then Or' do
|
63
|
-
q = 'id > 1234 & name = abcd | name
|
63
|
+
q = 'id > 1234 & name = abcd | name : efgh'
|
64
64
|
Country.search(NQL.to_ransack(q)).result.should produce_sql "SELECT \"countries\".* FROM \"countries\" WHERE ((\"countries\".\"id\" > 1234 AND (\"countries\".\"name\" = 'abcd' OR \"countries\".\"name\" LIKE '%efgh%')))"
|
65
65
|
end
|
66
66
|
|
67
67
|
it 'With parentheses' do
|
68
|
-
q = '(id > 1234 & name = abcd) | name
|
68
|
+
q = '(id > 1234 & name = abcd) | name : efgh'
|
69
69
|
Country.search(NQL.to_ransack(q)).result.should produce_sql "SELECT \"countries\".* FROM \"countries\" WHERE ((\"countries\".\"name\" LIKE '%efgh%' OR (\"countries\".\"id\" > 1234 AND \"countries\".\"name\" = 'abcd')))"
|
70
70
|
end
|
71
71
|
|
@@ -74,17 +74,17 @@ describe 'SQL generation' do
|
|
74
74
|
context 'Model joins' do
|
75
75
|
|
76
76
|
it 'Parent join' do
|
77
|
-
q = 'country.name
|
77
|
+
q = 'country.name : abcd'
|
78
78
|
City.search(NQL.to_ransack(q)).result.should produce_sql "SELECT \"cities\".* FROM \"cities\" LEFT OUTER JOIN \"countries\" ON \"countries\".\"id\" = \"cities\".\"country_id\" WHERE (\"countries\".\"name\" LIKE '%abcd%')"
|
79
79
|
end
|
80
80
|
|
81
81
|
it 'Children join' do
|
82
|
-
q = 'cities.name
|
82
|
+
q = 'cities.name : abcd'
|
83
83
|
Country.search(NQL.to_ransack(q)).result.should produce_sql "SELECT \"countries\".* FROM \"countries\" LEFT OUTER JOIN \"cities\" ON \"cities\".\"country_id\" = \"countries\".\"id\" WHERE (\"cities\".\"name\" LIKE '%abcd%')"
|
84
84
|
end
|
85
85
|
|
86
86
|
it 'Children join distinct' do
|
87
|
-
q = 'cities.name
|
87
|
+
q = 'cities.name : abcd'
|
88
88
|
Country.search(NQL.to_ransack(q)).result(distinct: true).should produce_sql "SELECT DISTINCT \"countries\".* FROM \"countries\" LEFT OUTER JOIN \"cities\" ON \"cities\".\"country_id\" = \"countries\".\"id\" WHERE (\"cities\".\"name\" LIKE '%abcd%')"
|
89
89
|
end
|
90
90
|
|
@@ -109,7 +109,7 @@ describe 'SQL generation' do
|
|
109
109
|
|
110
110
|
it 'Partial expression' do
|
111
111
|
q = 'id ='
|
112
|
-
Country.search(NQL.to_ransack(q)).result.should
|
112
|
+
expect{Country.search(NQL.to_ransack(q)).result}.should raise_exception NQL::InvalidExpressionError
|
113
113
|
end
|
114
114
|
|
115
115
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nql
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -13,7 +13,7 @@ date: 2012-11-09 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: treetop
|
16
|
-
requirement: &
|
16
|
+
requirement: &28678476 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *28678476
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: activerecord
|
27
|
-
requirement: &
|
27
|
+
requirement: &28678152 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: 3.2.0
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *28678152
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: activesupport
|
38
|
-
requirement: &
|
38
|
+
requirement: &28677828 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: 3.2.0
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *28677828
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: ransack
|
49
|
-
requirement: &
|
49
|
+
requirement: &28677600 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: '0'
|
55
55
|
type: :runtime
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *28677600
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: sqlite3
|
60
|
-
requirement: &
|
60
|
+
requirement: &28677324 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: '0'
|
66
66
|
type: :development
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *28677324
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rspec
|
71
|
-
requirement: &
|
71
|
+
requirement: &28677060 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ! '>='
|
@@ -76,7 +76,7 @@ dependencies:
|
|
76
76
|
version: '0'
|
77
77
|
type: :development
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *28677060
|
80
80
|
description: Natural Query Language built on top of ActiveRecord and Ransack
|
81
81
|
email:
|
82
82
|
- gabynaiman@gmail.com
|
@@ -92,6 +92,7 @@ files:
|
|
92
92
|
- lib/nql.rb
|
93
93
|
- lib/nql/grammar.rb
|
94
94
|
- lib/nql/grammar.treetop
|
95
|
+
- lib/nql/invalid_expression_error.rb
|
95
96
|
- lib/nql/version.rb
|
96
97
|
- nql.gemspec
|
97
98
|
- spec/comparison_parser_spec.rb
|