querybuilder 0.7.0 → 0.8.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.
- data/.gitignore +2 -1
- data/History.txt +8 -0
- data/Rakefile +3 -2
- data/lib/query_builder/info.rb +1 -1
- data/lib/query_builder/processor.rb +84 -13
- data/lib/query_builder/query.rb +32 -17
- data/lib/querybuilder_ext.c +937 -902
- data/lib/querybuilder_ext.rl +9 -1
- data/lib/querybuilder_rb.rb +704 -679
- data/lib/querybuilder_rb.rl +8 -1
- data/lib/querybuilder_syntax.rl +1 -1
- data/{tasks → lib/tasks}/build.rake +0 -0
- data/querybuilder.gemspec +6 -4
- data/test/database.rb +20 -0
- data/test/mock/dummy_processor.rb +17 -0
- data/test/querybuilder/basic.yml +4 -3
- data/test/querybuilder/errors.yml +9 -0
- data/test/querybuilder/filters.yml +10 -2
- data/test/querybuilder/joins.yml +5 -0
- data/test/test_helper.rb +1 -0
- metadata +6 -4
data/lib/querybuilder_rb.rl
CHANGED
@@ -87,6 +87,7 @@ module QueryBuilder
|
|
87
87
|
|
88
88
|
action goto_expr_p {
|
89
89
|
# remember current machine state 'cs'
|
90
|
+
par_count += 1
|
90
91
|
last << [:par, cs]
|
91
92
|
stack.push last.last
|
92
93
|
last = last.last
|
@@ -96,6 +97,7 @@ module QueryBuilder
|
|
96
97
|
action expr_close {
|
97
98
|
pop_stack(stack, :par_close)
|
98
99
|
# reset machine state 'cs'
|
100
|
+
par_count -= 1
|
99
101
|
cs = stack.last.delete_at(1)
|
100
102
|
# one more time to remove [:par...] line
|
101
103
|
stack.pop
|
@@ -195,6 +197,7 @@ module QueryBuilder
|
|
195
197
|
else
|
196
198
|
data = "#{arg}\n"
|
197
199
|
end
|
200
|
+
par_count = 0
|
198
201
|
stack = [[:query]]
|
199
202
|
last = stack.last
|
200
203
|
str_buf = ""
|
@@ -206,7 +209,11 @@ module QueryBuilder
|
|
206
209
|
if p < pe
|
207
210
|
p = p - 3
|
208
211
|
p = 0 if p < 0
|
209
|
-
raise QueryBuilder::SyntaxError.new("Syntax error near #{data[p..-
|
212
|
+
raise QueryBuilder::SyntaxError.new("Syntax error near #{data[p..-2].inspect}.")
|
213
|
+
end
|
214
|
+
|
215
|
+
if par_count > 0
|
216
|
+
raise QueryBuilder::SyntaxError.new("Missing closing parenthesis in #{data[0..-2].inspect}.")
|
210
217
|
end
|
211
218
|
stack.first
|
212
219
|
end
|
data/lib/querybuilder_syntax.rl
CHANGED
@@ -8,7 +8,7 @@
|
|
8
8
|
# The where CLAUSE can contain the following operators
|
9
9
|
|
10
10
|
ws = ' ' | '\t' | '\n';
|
11
|
-
var = ws* ([a-zA-Z_]+) $str_a;
|
11
|
+
var = ws* ([a-zA-Z_:]+) $str_a;
|
12
12
|
dquote = ([^"\\] | '\n') $str_a | ('\\' (any | '\n') $str_a);
|
13
13
|
squote = ([^'\\] | '\n') $str_a | ('\\' (any | '\n') $str_a);
|
14
14
|
string = ws* ("'" squote* "'" >string | '"' dquote* '"' >dstring);
|
File without changes
|
data/querybuilder.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{querybuilder}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.8.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Gaspard Bucher"]
|
12
|
-
s.date = %q{2010-
|
12
|
+
s.date = %q{2010-07-22}
|
13
13
|
s.description = %q{QueryBuilder is an interpreter for the "pseudo sql" language. This language
|
14
14
|
can be used for two purposes:
|
15
15
|
|
@@ -38,12 +38,13 @@ Gem::Specification.new do |s|
|
|
38
38
|
"lib/querybuilder_rb.rb",
|
39
39
|
"lib/querybuilder_rb.rl",
|
40
40
|
"lib/querybuilder_syntax.rl",
|
41
|
+
"lib/tasks/build.rake",
|
41
42
|
"old_QueryBuilder.rb",
|
42
43
|
"querybuilder.gemspec",
|
43
44
|
"script/console",
|
44
45
|
"script/destroy",
|
45
46
|
"script/generate",
|
46
|
-
"
|
47
|
+
"test/database.rb",
|
47
48
|
"test/dummy_test.rb",
|
48
49
|
"test/mock/custom_queries/test.yml",
|
49
50
|
"test/mock/dummy.rb",
|
@@ -69,7 +70,8 @@ Gem::Specification.new do |s|
|
|
69
70
|
s.rubygems_version = %q{1.3.6}
|
70
71
|
s.summary = %q{QueryBuilder is an interpreter for the "pseudo sql" language.}
|
71
72
|
s.test_files = [
|
72
|
-
"test/
|
73
|
+
"test/database.rb",
|
74
|
+
"test/dummy_test.rb",
|
73
75
|
"test/mock/dummy.rb",
|
74
76
|
"test/mock/dummy_processor.rb",
|
75
77
|
"test/mock/user_processor.rb",
|
data/test/database.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
|
3
|
+
begin
|
4
|
+
class QueryBuilderTestMigration < ActiveRecord::Migration
|
5
|
+
def self.down
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.up
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
ActiveRecord::Base.establish_connection(:adapter=>'sqlite3', :database=>':memory:')
|
13
|
+
log_path = Pathname(__FILE__).dirname + '../log/test.log'
|
14
|
+
Dir.mkdir(log_path.dirname) unless File.exist?(log_path.dirname)
|
15
|
+
ActiveRecord::Base.logger = Logger.new(File.open(log_path, 'wb'))
|
16
|
+
ActiveRecord::Migration.verbose = false
|
17
|
+
#PropertyMigration.migrate(:down)
|
18
|
+
QueryBuilderTestMigration.migrate(:up)
|
19
|
+
ActiveRecord::Migration.verbose = true
|
20
|
+
end
|
@@ -32,11 +32,28 @@ class DummyProcessor < QueryBuilder::Processor
|
|
32
32
|
"#{table}.#{fld_name}"
|
33
33
|
elsif fld_name == 'REF_DATE'
|
34
34
|
context[:ref_date] ? insert_bind(context[:ref_date]) : 'now()'
|
35
|
+
elsif fld_name == 'index'
|
36
|
+
add_table('index')
|
37
|
+
add_filter "#{table('index')}.node_id = #{field_or_attr('id', table(self.class.main_table))}"
|
38
|
+
"#{table('index')}.value"
|
35
39
|
else
|
36
40
|
super # raises an error
|
37
41
|
end
|
38
42
|
end
|
39
43
|
|
44
|
+
def resolve_missing_table(query, table_alias, table_name)
|
45
|
+
case table_name
|
46
|
+
when 'index'
|
47
|
+
query.where.insert 0, "#{table_alias}.id = 0"
|
48
|
+
when 'links'
|
49
|
+
query.where.insert 0, "#{table_alias}.id = 0"
|
50
|
+
else
|
51
|
+
# Raise an error
|
52
|
+
super
|
53
|
+
end
|
54
|
+
# do nothing
|
55
|
+
end
|
56
|
+
|
40
57
|
# We do special things with 'class ='
|
41
58
|
def process_equal(left, right)
|
42
59
|
if left == [:field, 'class'] && right[0] == :string
|
data/test/querybuilder/basic.yml
CHANGED
@@ -70,11 +70,12 @@ paginate:
|
|
70
70
|
recipients_or_objects:
|
71
71
|
src: recipients or objects
|
72
72
|
sxp: '[:query, [:clause_or, [:relation, "recipients"], [:relation, "objects"]]]'
|
73
|
-
res: "[%Q{SELECT objects.* FROM links,objects WHERE ((objects.id = links.target_id AND links.relation_id = 4 AND links.source_id = ?) OR objects.parent_id = ?) GROUP BY objects.id}, id, id]"
|
73
|
+
res: "[%Q{SELECT objects.* FROM links,objects WHERE ((objects.id = links.target_id AND links.relation_id = 4 AND links.source_id = ?) OR (objects.parent_id = ? AND links.id = 0)) GROUP BY objects.id}, id, id]"
|
74
74
|
|
75
75
|
recipients_or_objects_or_letters:
|
76
76
|
src: recipients or objects or letters
|
77
|
-
res: "[%Q{SELECT objects.* FROM links,objects WHERE ((objects.id = links.target_id AND links.relation_id = 4 AND links.source_id = ?) OR objects.parent_id = ? OR (objects.kpath LIKE 'NNL%' AND objects.parent_id = ?)) GROUP BY objects.id}, id, id, id]"
|
77
|
+
res: "[%Q{SELECT objects.* FROM links,objects WHERE ((objects.id = links.target_id AND links.relation_id = 4 AND links.source_id = ?) OR (links.id = 0 AND objects.parent_id = ?) OR (links.id = 0 AND objects.kpath LIKE 'NNL%' AND objects.parent_id = ?)) GROUP BY objects.id}, id, id, id]"
|
78
|
+
res: "[%Q{SELECT objects.* FROM links,objects WHERE ((objects.id = links.target_id AND links.relation_id = 4 AND links.source_id = ?) OR (objects.parent_id = ? AND links.id = 0) OR (objects.kpath LIKE 'NNL%' AND objects.parent_id = ? AND links.id = 0)) GROUP BY objects.id}, id, id, id]"
|
78
79
|
|
79
80
|
or_clause_with_filter:
|
80
81
|
src: "(recipients where name = 'foo') or objects"
|
@@ -88,4 +89,4 @@ after_process_callback:
|
|
88
89
|
context:
|
89
90
|
after_filter: '(1 = 1)'
|
90
91
|
src: "objects where name like 'a%' or name like 'b%' in site"
|
91
|
-
res: "%Q{SELECT objects.* FROM objects WHERE (1 = 1) AND (objects.name LIKE 'a%' OR objects.name LIKE 'b%')}"
|
92
|
+
res: "%Q{SELECT objects.* FROM objects WHERE (1 = 1) AND (objects.name LIKE 'a%' OR objects.name LIKE 'b%') GROUP BY id}"
|
@@ -30,3 +30,12 @@ or_clause_with_filter:
|
|
30
30
|
src: "recipients where name = 'foo' or objects"
|
31
31
|
sxp: '[:query, [:filter, [:relation, "recipients"], [:or, [:"=", [:field, "name"], [:string, "foo"]], [:field, "objects"]]]]'
|
32
32
|
res: "Unknown field 'objects'."
|
33
|
+
|
34
|
+
|
35
|
+
unmatched_open_par:
|
36
|
+
src: "objects where event_at is null or (name is not null"
|
37
|
+
res: "Missing closing parenthesis in \"objects where event_at is null or (name is not null\"."
|
38
|
+
|
39
|
+
unmatched_close_par:
|
40
|
+
src: "objects where event_at is null )"
|
41
|
+
res: "Syntax error near \"ll )\"."
|
@@ -83,7 +83,15 @@ equation_with_date_interval:
|
|
83
83
|
equation_and_or_par:
|
84
84
|
src: "objects where event_at > '2006-04-01' or name like 'foo%'"
|
85
85
|
sxp: '[:query, [:filter, [:relation, "objects"], [:or, [:>, [:field, "event_at"], [:string, "2006-04-01"]], [:like, [:field, "name"], [:string, "foo%"]]]]]'
|
86
|
-
res: "[%Q{SELECT objects.* FROM objects WHERE (objects.event_at > '2006-04-01' OR objects.name LIKE 'foo%') AND objects.parent_id = ?}, id]"
|
86
|
+
res: "[%Q{SELECT objects.* FROM objects WHERE (objects.event_at > '2006-04-01' OR objects.name LIKE 'foo%') AND objects.parent_id = ? GROUP BY id}, id]"
|
87
|
+
|
88
|
+
or_with_same_tables:
|
89
|
+
src: "objects where index = 5 or index = 7"
|
90
|
+
res: "[%Q{SELECT objects.* FROM index,objects WHERE ((index.value = 5 AND index.node_id = objects.id) OR (index.value = 7 AND index.node_id = objects.id)) AND objects.parent_id = ? GROUP BY objects.id}, id]"
|
91
|
+
|
92
|
+
or_with_missing_table:
|
93
|
+
src: "objects where index = 5 or 7"
|
94
|
+
res: "[%Q{SELECT objects.* FROM index,objects WHERE ((index.value = 5 AND index.node_id = objects.id) OR (7 AND index.id = 0)) AND objects.parent_id = ? GROUP BY objects.id}, id]"
|
87
95
|
|
88
96
|
equation_par:
|
89
97
|
src: "objects where (1 > 2 or 2 > 3) and 4 = 5 "
|
@@ -112,4 +120,4 @@ functions:
|
|
112
120
|
filter_empty_literal:
|
113
121
|
src: "objects where \"\" = ''"
|
114
122
|
sxp: '[:query, [:filter, [:relation, "objects"], [:"=", [:dstring, ""], [:string, ""]]]]'
|
115
|
-
sql: "SELECT objects.* FROM objects WHERE '' = '' AND objects.parent_id = 123"
|
123
|
+
sql: "SELECT objects.* FROM objects WHERE '' = '' AND objects.parent_id = 123"
|
data/test/querybuilder/joins.yml
CHANGED
@@ -26,6 +26,11 @@ tags:
|
|
26
26
|
complex_from_with_scopes:
|
27
27
|
src: "letters where name = 'foo' in project from letters in section"
|
28
28
|
sxp: '[:query, [:from, [:scope, [:filter, [:relation, "letters"], [:"=", [:field, "name"], [:string, "foo"]]], "project"], [:scope, [:relation, "letters"], "section"]]]'
|
29
|
+
|
30
|
+
complex_from_with_scopes_and_typed_scope:
|
31
|
+
# instead of 'project', we give it a class with 'jobs:project'
|
32
|
+
src: "letters where name = 'foo' in jobs:project from letters in section"
|
33
|
+
sxp: '[:query, [:from, [:scope, [:filter, [:relation, "letters"], [:"=", [:field, "name"], [:string, "foo"]]], "jobs:project"], [:scope, [:relation, "letters"], "section"]]]'
|
29
34
|
|
30
35
|
letters_in_project_from_letters:
|
31
36
|
sxp: '[:query, [:from, [:scope, [:relation, "letters"], "project"], [:relation, "letters"]]]'
|
data/test/test_helper.rb
CHANGED
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
7
|
+
- 8
|
8
8
|
- 0
|
9
|
-
version: 0.
|
9
|
+
version: 0.8.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Gaspard Bucher
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-
|
17
|
+
date: 2010-07-22 00:00:00 +02:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -89,12 +89,13 @@ files:
|
|
89
89
|
- lib/querybuilder_rb.rb
|
90
90
|
- lib/querybuilder_rb.rl
|
91
91
|
- lib/querybuilder_syntax.rl
|
92
|
+
- lib/tasks/build.rake
|
92
93
|
- old_QueryBuilder.rb
|
93
94
|
- querybuilder.gemspec
|
94
95
|
- script/console
|
95
96
|
- script/destroy
|
96
97
|
- script/generate
|
97
|
-
-
|
98
|
+
- test/database.rb
|
98
99
|
- test/dummy_test.rb
|
99
100
|
- test/mock/custom_queries/test.yml
|
100
101
|
- test/mock/dummy.rb
|
@@ -144,6 +145,7 @@ signing_key:
|
|
144
145
|
specification_version: 3
|
145
146
|
summary: QueryBuilder is an interpreter for the "pseudo sql" language.
|
146
147
|
test_files:
|
148
|
+
- test/database.rb
|
147
149
|
- test/dummy_test.rb
|
148
150
|
- test/mock/dummy.rb
|
149
151
|
- test/mock/dummy_processor.rb
|