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 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
@@ -1,4 +1,4 @@
1
- = querybuilder
1
+ = QueryBuilder
2
2
 
3
3
  * http://github.com/zena/querybuilder/tree/master
4
4
 
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.0'
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 directory.
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
- # DummyQuery: # QueryBuilder class
42
- # abc: # query's relation name
43
- # select: # selected fields
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: # tables used
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(dir)
63
+ def load_custom_queries(directories)
58
64
  klass = nil
59
- if File.directory?(dir)
60
- Dir.foreach(dir) do |file|
61
- next unless file =~ /(.+).yml$/
62
- custom_query_group = $1
63
- definitions = YAML::load(File.read(File.join(dir,file)))
64
- definitions.each do |klass,v|
65
- klass = Module.const_get(klass)
66
- raise ArgumentError.new("invalid class for CustomQueries (#{klass})") unless klass.ancestors.include?(QueryBuilder)
67
- @@custom_queries[klass] ||= {}
68
- @@custom_queries[klass][custom_query_group] ||= {}
69
- klass_queries = @@custom_queries[klass][custom_query_group]
70
- v.each do |k,v|
71
- klass_queries[k] = v
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 #{@main_table}.* FROM #{@main_table} WHERE 0\"" if @tables.empty? # all alternate queries invalid and 'ignore_warnings' set.
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 #{@main_table}.* FROM #{@main_table} WHERE 0" if @tables.empty? # all alternate queries invalid and 'ignore_warnings' set.
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.join =~ / AS #{fld}/
588
- @select.each do |s|
589
- if s =~ /\A(.*) AS #{fld}\Z/
590
- return context == :filter ? "(#{$1})" : fld
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]
@@ -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
- - 'a'
6
- - '34 AS number'
7
- - 'c'
4
+ - a
5
+ - 34 AS number
6
+ - c
8
7
  tables:
9
- - 'test'
8
+ - test
10
9
  where:
11
10
  - '1'
12
11
  - '2'
13
12
  - '3'
14
- order: 'a'
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
@@ -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__), 'custom_queries')
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.0
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-01-26 00:00:00 +01:00
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.2.3
33
+ version: 1.3.0
34
34
  version:
35
35
  - !ruby/object:Gem::Dependency
36
36
  name: hoe