querybuilder 0.5.0 → 0.5.2
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/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
|