querybuilder 0.5.0 → 0.5.2
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +12 -1
- data/README.rdoc +1 -1
- data/lib/QueryBuilder.rb +40 -31
- data/test/QueryBuilder/basic.yml +0 -6
- data/test/QueryBuilder/filters.yml +1 -1
- data/test/mock/custom_queries/test.yml +23 -6
- data/test/mock/dummy_query.rb +1 -1
- metadata +3 -3
data/History.txt
CHANGED
@@ -1,4 +1,15 @@
|
|
1
|
+
== 0.5.2 2009-04-03
|
2
|
+
|
3
|
+
* 1 minor enhancement:
|
4
|
+
* Added support for main_table option in custom queries
|
5
|
+
* More tests for custom queries
|
6
|
+
|
7
|
+
== 0.5.1 2009-03-03
|
8
|
+
|
9
|
+
* 1 minor enhancement:
|
10
|
+
* Added support for glob directories in load_custom_queries
|
11
|
+
|
1
12
|
== 0.5.0 2009-01-23
|
2
13
|
|
3
14
|
* 1 major enhancement:
|
4
|
-
* Initial release (extraction from zena: http://zenadmin.org)
|
15
|
+
* Initial release (extraction from zena: http://zenadmin.org)
|
data/README.rdoc
CHANGED
data/lib/QueryBuilder.rb
CHANGED
@@ -10,7 +10,7 @@ Syntax of a query is "RELATION [where ...|] [in ...|from SUB_QUERY|]".
|
|
10
10
|
=end
|
11
11
|
class QueryBuilder
|
12
12
|
attr_reader :tables, :where, :errors, :join_tables, :distinct, :final_parser, :page_size
|
13
|
-
VERSION = '0.5.
|
13
|
+
VERSION = '0.5.2'
|
14
14
|
|
15
15
|
@@main_table = {}
|
16
16
|
@@main_class = {}
|
@@ -28,24 +28,30 @@ class QueryBuilder
|
|
28
28
|
@@main_class[self] = main_class.to_s
|
29
29
|
end
|
30
30
|
|
31
|
-
# Load prepared SQL definitions from a
|
31
|
+
# Load prepared SQL definitions from a set of directories. If the file does not contain "host" or "hosts" keys,
|
32
|
+
# the filename is used as host.
|
32
33
|
#
|
33
34
|
# ==== Parameters
|
34
35
|
# query<String>:: Path to list of custom queries yaml files.
|
35
36
|
#
|
36
37
|
# ==== Examples
|
37
|
-
# DummyQuery.load_custom_queries("/path/to/directory")
|
38
|
+
# DummyQuery.load_custom_queries("/path/to/some/*/directory")
|
38
39
|
#
|
39
40
|
# The format of a custom query definition is:
|
40
41
|
#
|
41
|
-
#
|
42
|
-
#
|
43
|
-
#
|
42
|
+
# hosts:
|
43
|
+
# - test.host
|
44
|
+
# DummyQuery: # QueryBuilder class
|
45
|
+
# abc: # query's relation name
|
46
|
+
# select: # selected fields
|
44
47
|
# - 'a'
|
45
48
|
# - '34 AS number'
|
46
49
|
# - 'c'
|
47
|
-
# tables:
|
50
|
+
# tables: # tables used
|
48
51
|
# - 'test'
|
52
|
+
# join_tables: # joins
|
53
|
+
# test:
|
54
|
+
# - LEFT JOIN other ON other.test_id = test.id
|
49
55
|
# where: # filters
|
50
56
|
# - '1'
|
51
57
|
# - '2'
|
@@ -54,21 +60,26 @@ class QueryBuilder
|
|
54
60
|
#
|
55
61
|
# Once loaded, this 'custom query' can be used in a query like:
|
56
62
|
# "images from abc where a > 54"
|
57
|
-
def load_custom_queries(
|
63
|
+
def load_custom_queries(directories)
|
58
64
|
klass = nil
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
65
|
+
Dir.glob(directories).each do |dir|
|
66
|
+
if File.directory?(dir)
|
67
|
+
Dir.foreach(dir) do |file|
|
68
|
+
next unless file =~ /(.+).yml$/
|
69
|
+
custom_query_groups = $1
|
70
|
+
definitions = YAML::load(File.read(File.join(dir,file)))
|
71
|
+
custom_query_groups = [definitions.delete('groups') || definitions.delete('group') || custom_query_groups].flatten
|
72
|
+
definitions.each do |klass,v|
|
73
|
+
klass = Module.const_get(klass)
|
74
|
+
raise ArgumentError.new("invalid class for CustomQueries (#{klass})") unless klass.ancestors.include?(QueryBuilder)
|
75
|
+
@@custom_queries[klass] ||= {}
|
76
|
+
custom_query_groups.each do |custom_query_group|
|
77
|
+
@@custom_queries[klass][custom_query_group] ||= {}
|
78
|
+
klass_queries = @@custom_queries[klass][custom_query_group]
|
79
|
+
v.each do |k,v|
|
80
|
+
klass_queries[k] = v
|
81
|
+
end
|
82
|
+
end
|
72
83
|
end
|
73
84
|
end
|
74
85
|
end
|
@@ -132,7 +143,7 @@ class QueryBuilder
|
|
132
143
|
# => "[\"SELECT COUNT(*) FROM objects WHERE objects.project_id = ?\", project_id]"
|
133
144
|
def to_s(type = :find)
|
134
145
|
return nil if !valid?
|
135
|
-
return "\"SELECT #{
|
146
|
+
return "\"SELECT #{main_table}.* FROM #{main_table} WHERE 0\"" if @tables.empty? # all alternate queries invalid and 'ignore_warnings' set.
|
136
147
|
statement, bind_values = build_statement(type)
|
137
148
|
bind_values.empty? ? "\"#{statement}\"" : "[#{[["\"#{statement}\""] + bind_values].join(', ')}]"
|
138
149
|
end
|
@@ -155,7 +166,7 @@ class QueryBuilder
|
|
155
166
|
# => "SELECT COUNT(*) FROM objects WHERE objects.project_id = 12489"
|
156
167
|
def sql(bindings, type = :find)
|
157
168
|
return nil if !valid?
|
158
|
-
return "SELECT #{
|
169
|
+
return "SELECT #{main_table}.* FROM #{main_table} WHERE 0" if @tables.empty? # all alternate queries invalid and 'ignore_warnings' set.
|
159
170
|
statement, bind_values = build_statement(type)
|
160
171
|
connection = get_connection(bindings)
|
161
172
|
statement.gsub('?') { eval_bound_value(bind_values.shift, connection, bindings) }
|
@@ -204,7 +215,7 @@ class QueryBuilder
|
|
204
215
|
end
|
205
216
|
|
206
217
|
def main_table
|
207
|
-
@@main_table[self.class]
|
218
|
+
@main_table || @@main_table[self.class]
|
208
219
|
end
|
209
220
|
|
210
221
|
def parse_part(part, is_last)
|
@@ -584,12 +595,12 @@ class QueryBuilder
|
|
584
595
|
def field_or_attr(fld, table_name = table, context = nil)
|
585
596
|
if fld =~ /^\d+$/
|
586
597
|
return fld
|
587
|
-
elsif @select.
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
end
|
598
|
+
elsif !(list = @select.select {|e| e =~ /\A#{fld}\Z|AS #{fld}|\.#{fld}\Z/}).empty?
|
599
|
+
res = list.first
|
600
|
+
if res =~ /\A(.*) AS #{fld}\Z/
|
601
|
+
res = $1
|
592
602
|
end
|
603
|
+
return context == :filter ? "(#{res})" : res
|
593
604
|
elsif table_name
|
594
605
|
map_field(fld, table_name, context)
|
595
606
|
else
|
@@ -848,8 +859,6 @@ class QueryBuilder
|
|
848
859
|
|
849
860
|
@errors = []
|
850
861
|
|
851
|
-
@main_table ||= 'objects'
|
852
|
-
|
853
862
|
@select = []
|
854
863
|
|
855
864
|
@ignore_warnings = opts[:ignore_warnings]
|
data/test/QueryBuilder/basic.yml
CHANGED
@@ -55,12 +55,6 @@ recipients_or_objects:
|
|
55
55
|
- "objects"
|
56
56
|
res: "[\"SELECT objects.* FROM objects,links 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]"
|
57
57
|
|
58
|
-
custom_query:
|
59
|
-
context:
|
60
|
-
custom_query_group: test
|
61
|
-
src: "abc"
|
62
|
-
res: "\"SELECT a,34 AS number,c FROM test WHERE 3 AND 2 AND 1 ORDER BY a\""
|
63
|
-
|
64
58
|
count_sql:
|
65
59
|
src: "objects in project"
|
66
60
|
count: "[\"SELECT COUNT(*) FROM objects WHERE objects.project_id = ?\", project_id]"
|
@@ -24,7 +24,7 @@ custom_query_having:
|
|
24
24
|
context:
|
25
25
|
custom_query_group: test
|
26
26
|
src: "abc where number > 12"
|
27
|
-
res: "\"SELECT a,34 AS number,c FROM test WHERE (34) > 12 AND 3 AND 2 AND 1 ORDER BY a\""
|
27
|
+
res: "\"SELECT a,34 AS number,c FROM test WHERE (34) > 12 AND 3 AND 2 AND 1 ORDER BY a ASC\""
|
28
28
|
|
29
29
|
equation_in_filter:
|
30
30
|
src: "objects where event_at > REF_DATE + custom_a months"
|
@@ -1,14 +1,31 @@
|
|
1
1
|
DummyQuery:
|
2
|
-
# form_dates
|
3
2
|
abc:
|
4
3
|
select:
|
5
|
-
-
|
6
|
-
-
|
7
|
-
-
|
4
|
+
- a
|
5
|
+
- 34 AS number
|
6
|
+
- c
|
8
7
|
tables:
|
9
|
-
-
|
8
|
+
- test
|
10
9
|
where:
|
11
10
|
- '1'
|
12
11
|
- '2'
|
13
12
|
- '3'
|
14
|
-
order:
|
13
|
+
order: a ASC
|
14
|
+
|
15
|
+
two_table:
|
16
|
+
select:
|
17
|
+
- x
|
18
|
+
- IF(table_one.y,table_one.y,table_two.z) AS y
|
19
|
+
- table_two.name
|
20
|
+
tables:
|
21
|
+
- table_one
|
22
|
+
- table_two
|
23
|
+
|
24
|
+
two_table_main:
|
25
|
+
main_table: foo
|
26
|
+
select:
|
27
|
+
- x
|
28
|
+
tables:
|
29
|
+
- table_one
|
30
|
+
- foo
|
31
|
+
- table_two
|
data/test/mock/dummy_query.rb
CHANGED
@@ -2,7 +2,7 @@ class DummyQuery < QueryBuilder
|
|
2
2
|
set_main_table 'objects'
|
3
3
|
set_main_class 'DummyQueryClass'
|
4
4
|
|
5
|
-
load_custom_queries File.join(File.dirname(__FILE__), '
|
5
|
+
load_custom_queries File.join(File.dirname(__FILE__), '*')
|
6
6
|
|
7
7
|
# Build joins and filters from a relation.
|
8
8
|
def parse_relation(rel, context)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: querybuilder
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gaspard Bucher
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-04-03 00:00:00 +02:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -30,7 +30,7 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 1.
|
33
|
+
version: 1.3.0
|
34
34
|
version:
|
35
35
|
- !ruby/object:Gem::Dependency
|
36
36
|
name: hoe
|