querybuilder 0.8.3 → 0.9.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/History.txt +7 -0
- data/README.rdoc +1 -1
- data/Rakefile +1 -1
- data/lib/query_builder/info.rb +1 -1
- data/lib/query_builder/processor.rb +24 -7
- data/lib/query_builder/query.rb +15 -1
- data/querybuilder.gemspec +5 -5
- data/test/mock/custom_queries/test.yml +18 -3
- data/test/querybuilder_test.rb +15 -1
- metadata +6 -6
data/History.txt
CHANGED
data/README.rdoc
CHANGED
data/Rakefile
CHANGED
@@ -16,7 +16,7 @@ begin
|
|
16
16
|
gem.email = "gaspard@teti.ch"
|
17
17
|
gem.homepage = "http://zenadmin.org/524"
|
18
18
|
gem.authors = ["Gaspard Bucher"]
|
19
|
-
gem.add_dependency "rubyless", ">= 0.
|
19
|
+
gem.add_dependency "rubyless", ">= 0.7.0"
|
20
20
|
gem.add_development_dependency "shoulda", ">= 0"
|
21
21
|
gem.add_development_dependency "yamltest", ">= 0.5.0"
|
22
22
|
gem.extensions << 'lib/extconf.rb'
|
data/lib/query_builder/info.rb
CHANGED
@@ -6,7 +6,7 @@ module QueryBuilder
|
|
6
6
|
|
7
7
|
class << self
|
8
8
|
# class variable
|
9
|
-
attr_accessor :main_table, :main_class, :custom_queries
|
9
|
+
attr_accessor :main_table, :main_class, :custom_queries, :custom_query_files
|
10
10
|
attr_accessor :defaults
|
11
11
|
attr_accessor :before_process_callbacks, :after_process_callbacks
|
12
12
|
|
@@ -68,9 +68,16 @@ module QueryBuilder
|
|
68
68
|
# Once loaded, this 'custom query' can be used in a query like:
|
69
69
|
# "images from abc where a > 54"
|
70
70
|
def load_custom_queries(directories)
|
71
|
+
# lazy loading (evaluation happens on first query)
|
72
|
+
self.custom_query_files ||= []
|
73
|
+
self.custom_query_files << directories
|
74
|
+
end
|
75
|
+
|
76
|
+
def load_custom_queries!
|
77
|
+
return unless list = self.custom_query_files
|
71
78
|
klass = nil
|
72
79
|
self.custom_queries ||= {}
|
73
|
-
Dir.glob(
|
80
|
+
Dir.glob(list.flatten).each do |dir|
|
74
81
|
if File.directory?(dir)
|
75
82
|
Dir.foreach(dir) do |file|
|
76
83
|
next unless file =~ /(.+).yml$/
|
@@ -97,6 +104,7 @@ module QueryBuilder
|
|
97
104
|
end
|
98
105
|
end
|
99
106
|
end
|
107
|
+
self.custom_query_files = nil
|
100
108
|
rescue NameError => err
|
101
109
|
raise ArgumentError.new("Invalid Processor class (#{klass})")
|
102
110
|
end
|
@@ -427,7 +435,7 @@ module QueryBuilder
|
|
427
435
|
|
428
436
|
def process_attr(fld_name)
|
429
437
|
if @rubyless_helper
|
430
|
-
insert_bind(RubyLess.translate(
|
438
|
+
insert_bind(RubyLess.translate(@rubyless_helper, fld_name))
|
431
439
|
else
|
432
440
|
insert_bind(fld_name)
|
433
441
|
end
|
@@ -449,14 +457,14 @@ module QueryBuilder
|
|
449
457
|
|
450
458
|
def process_dstring(string)
|
451
459
|
raise QueryBuilder::SyntaxError.new("Cannot parse rubyless (missing binding context).") unless helper = @rubyless_helper
|
452
|
-
res = RubyLess.translate_string(
|
460
|
+
res = RubyLess.translate_string(helper, string)
|
453
461
|
res.literal ? quote(res.literal) : insert_bind(res)
|
454
462
|
end
|
455
463
|
|
456
464
|
def process_rubyless(string)
|
457
465
|
# compile RubyLess...
|
458
466
|
raise QueryBuilder::SyntaxError.new("Cannot parse rubyless (missing binding context).") unless helper = @rubyless_helper
|
459
|
-
res = RubyLess.translate(
|
467
|
+
res = RubyLess.translate(helper, string)
|
460
468
|
res.literal ? quote(res.literal) : insert_bind(res)
|
461
469
|
end
|
462
470
|
|
@@ -656,13 +664,13 @@ module QueryBuilder
|
|
656
664
|
end
|
657
665
|
end
|
658
666
|
|
659
|
-
def
|
667
|
+
def custom_query_without_loading(relation)
|
660
668
|
return false unless first? && last? # current safety net until "from" is correctly implemented and tested
|
661
669
|
|
662
670
|
custom_queries = self.class.custom_queries[self.class]
|
663
671
|
if custom_queries &&
|
664
672
|
custom_queries[@opts[:custom_query_group]] &&
|
665
|
-
custom_query = custom_queries[@opts[:custom_query_group]][relation]
|
673
|
+
custom_query = custom_queries[@opts[:custom_query_group]][relation.singularize]
|
666
674
|
|
667
675
|
custom_query.each do |k,v|
|
668
676
|
@query.send(:instance_variable_set, "@#{k}", prepare_custom_query_arguments(k.to_sym, v))
|
@@ -675,6 +683,15 @@ module QueryBuilder
|
|
675
683
|
end
|
676
684
|
end
|
677
685
|
|
686
|
+
# Method executed only once, then alias resolves to custom_query_without_loading.
|
687
|
+
def custom_query(*args)
|
688
|
+
self.class.load_custom_queries!
|
689
|
+
self.class.class_eval do
|
690
|
+
alias custom_query custom_query_without_loading
|
691
|
+
end
|
692
|
+
custom_query_without_loading(*args)
|
693
|
+
end
|
694
|
+
|
678
695
|
private
|
679
696
|
|
680
697
|
%W{filter scope limit offset paginate group order}.each do |context|
|
data/lib/query_builder/query.rb
CHANGED
@@ -53,6 +53,20 @@ module QueryBuilder
|
|
53
53
|
@where << filter
|
54
54
|
end
|
55
55
|
|
56
|
+
# Return all explicit selected keys (currently selection is only available in custom queries)
|
57
|
+
# For example, sql such as "SELECT form.*, MAX(form.date) AS last_date" would provice 'last_date' key.
|
58
|
+
def select_keys
|
59
|
+
@select_keys ||= (@select || []).map do |field|
|
60
|
+
if field =~ %r{AS\s+(.+)$}
|
61
|
+
$1
|
62
|
+
elsif field =~ %r{^(\w+\.|)([^\*]+)$}
|
63
|
+
$2
|
64
|
+
else
|
65
|
+
nil
|
66
|
+
end
|
67
|
+
end.compact
|
68
|
+
end
|
69
|
+
|
56
70
|
# Convert query object to a string. This string should then be evaluated.
|
57
71
|
#
|
58
72
|
# ==== Parameters
|
@@ -285,4 +299,4 @@ module QueryBuilder
|
|
285
299
|
end
|
286
300
|
end
|
287
301
|
end
|
288
|
-
end
|
302
|
+
end
|
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.9.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-09-14}
|
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
|
|
@@ -86,16 +86,16 @@ Gem::Specification.new do |s|
|
|
86
86
|
s.specification_version = 3
|
87
87
|
|
88
88
|
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
89
|
-
s.add_runtime_dependency(%q<rubyless>, [">= 0.
|
89
|
+
s.add_runtime_dependency(%q<rubyless>, [">= 0.7.0"])
|
90
90
|
s.add_development_dependency(%q<shoulda>, [">= 0"])
|
91
91
|
s.add_development_dependency(%q<yamltest>, [">= 0.5.0"])
|
92
92
|
else
|
93
|
-
s.add_dependency(%q<rubyless>, [">= 0.
|
93
|
+
s.add_dependency(%q<rubyless>, [">= 0.7.0"])
|
94
94
|
s.add_dependency(%q<shoulda>, [">= 0"])
|
95
95
|
s.add_dependency(%q<yamltest>, [">= 0.5.0"])
|
96
96
|
end
|
97
97
|
else
|
98
|
-
s.add_dependency(%q<rubyless>, [">= 0.
|
98
|
+
s.add_dependency(%q<rubyless>, [">= 0.7.0"])
|
99
99
|
s.add_dependency(%q<shoulda>, [">= 0"])
|
100
100
|
s.add_dependency(%q<yamltest>, [">= 0.5.0"])
|
101
101
|
end
|
@@ -11,17 +11,32 @@ DummyProcessor:
|
|
11
11
|
- '2'
|
12
12
|
- '3'
|
13
13
|
order: a ASC
|
14
|
-
|
14
|
+
|
15
|
+
star:
|
16
|
+
select:
|
17
|
+
- test.*
|
18
|
+
- '*'
|
19
|
+
- a
|
20
|
+
- 34 AS number
|
21
|
+
- c
|
22
|
+
tables:
|
23
|
+
- test
|
24
|
+
where:
|
25
|
+
- '1'
|
26
|
+
- '2'
|
27
|
+
- '3'
|
28
|
+
order: a ASC
|
29
|
+
|
15
30
|
two_table:
|
16
31
|
main_table: 'table_one'
|
17
32
|
select:
|
18
33
|
- x AS x
|
19
34
|
- IF(table_one.y,table_one.y,table_two.z) AS y
|
20
35
|
- table_two.name
|
21
|
-
tables:
|
36
|
+
tables:
|
22
37
|
- table_two
|
23
38
|
- table_one
|
24
|
-
|
39
|
+
|
25
40
|
two_table_main:
|
26
41
|
main_table: foo
|
27
42
|
select:
|
data/test/querybuilder_test.rb
CHANGED
@@ -67,6 +67,20 @@ class DummyQueryBuilder < Test::Unit::TestCase
|
|
67
67
|
end
|
68
68
|
end # Including QueryBuilder
|
69
69
|
|
70
|
+
context 'A query with custom select' do
|
71
|
+
subject do
|
72
|
+
DummyProcessor.new('star where number < 4', :custom_query_group => 'test').query
|
73
|
+
end
|
74
|
+
|
75
|
+
should 'respond to select_keys' do
|
76
|
+
assert_equal %w{a number c}, subject.select_keys
|
77
|
+
end
|
78
|
+
|
79
|
+
should 'not include star keys' do
|
80
|
+
assert !subject.select_keys.include?('*')
|
81
|
+
end
|
82
|
+
end # A query with custom select
|
83
|
+
|
70
84
|
|
71
85
|
def yt_parse(key, source, opts)
|
72
86
|
opts = {:rubyless_helper => self}.merge(Hash[*(opts.map{|k,v| [k.to_sym, v]}.flatten)])
|
@@ -114,4 +128,4 @@ class DummyQueryBuilder < Test::Unit::TestCase
|
|
114
128
|
end
|
115
129
|
=end
|
116
130
|
yt_make
|
117
|
-
end
|
131
|
+
end
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version: 0.
|
7
|
+
- 9
|
8
|
+
- 0
|
9
|
+
version: 0.9.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-09-14 00:00:00 +02:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -26,9 +26,9 @@ dependencies:
|
|
26
26
|
- !ruby/object:Gem::Version
|
27
27
|
segments:
|
28
28
|
- 0
|
29
|
-
-
|
29
|
+
- 7
|
30
30
|
- 0
|
31
|
-
version: 0.
|
31
|
+
version: 0.7.0
|
32
32
|
type: :runtime
|
33
33
|
version_requirements: *id001
|
34
34
|
- !ruby/object:Gem::Dependency
|