querybuilder 0.5.9 → 0.7.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 +29 -25
- data/Manifest.txt +20 -9
- data/README.rdoc +73 -10
- data/Rakefile +62 -30
- data/lib/extconf.rb +3 -0
- data/lib/query_builder.rb +39 -898
- data/lib/query_builder/error.rb +7 -0
- data/lib/query_builder/info.rb +3 -0
- data/lib/query_builder/parser.rb +80 -0
- data/lib/query_builder/processor.rb +714 -0
- data/lib/query_builder/query.rb +273 -0
- data/lib/querybuilder_ext.c +1870 -0
- data/lib/querybuilder_ext.rl +418 -0
- data/lib/querybuilder_rb.rb +1686 -0
- data/lib/querybuilder_rb.rl +214 -0
- data/lib/querybuilder_syntax.rl +47 -0
- data/old_QueryBuilder.rb +946 -0
- data/querybuilder.gemspec +42 -15
- data/tasks/build.rake +20 -0
- data/test/dummy_test.rb +21 -0
- data/test/mock/custom_queries/test.yml +5 -4
- data/test/mock/dummy.rb +9 -0
- data/test/mock/dummy_processor.rb +160 -0
- data/test/mock/queries/bar.yml +1 -1
- data/test/mock/queries/foo.yml +2 -2
- data/test/mock/user_processor.rb +34 -0
- data/test/query_test.rb +38 -0
- data/test/querybuilder/basic.yml +91 -0
- data/test/{query_builder → querybuilder}/custom.yml +11 -11
- data/test/querybuilder/errors.yml +32 -0
- data/test/querybuilder/filters.yml +115 -0
- data/test/querybuilder/group.yml +7 -0
- data/test/querybuilder/joins.yml +37 -0
- data/test/querybuilder/mixed.yml +18 -0
- data/test/querybuilder/rubyless.yml +15 -0
- data/test/querybuilder_test.rb +111 -0
- data/test/test_helper.rb +8 -3
- metadata +66 -19
- data/test/mock/dummy_query.rb +0 -114
- data/test/mock/user_query.rb +0 -55
- data/test/query_builder/basic.yml +0 -60
- data/test/query_builder/errors.yml +0 -50
- data/test/query_builder/filters.yml +0 -43
- data/test/query_builder/joins.yml +0 -25
- data/test/query_builder/mixed.yml +0 -12
- data/test/query_builder_test.rb +0 -36
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.7.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-05-27}
|
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
|
|
@@ -25,35 +25,56 @@ Gem::Specification.new do |s|
|
|
25
25
|
"Manifest.txt",
|
26
26
|
"README.rdoc",
|
27
27
|
"Rakefile",
|
28
|
+
"lib/extconf.rb",
|
28
29
|
"lib/query_builder.rb",
|
30
|
+
"lib/query_builder/error.rb",
|
31
|
+
"lib/query_builder/info.rb",
|
32
|
+
"lib/query_builder/parser.rb",
|
33
|
+
"lib/query_builder/processor.rb",
|
34
|
+
"lib/query_builder/query.rb",
|
29
35
|
"lib/querybuilder.rb",
|
36
|
+
"lib/querybuilder_ext.c",
|
37
|
+
"lib/querybuilder_ext.rl",
|
38
|
+
"lib/querybuilder_rb.rb",
|
39
|
+
"lib/querybuilder_rb.rl",
|
40
|
+
"lib/querybuilder_syntax.rl",
|
41
|
+
"old_QueryBuilder.rb",
|
30
42
|
"querybuilder.gemspec",
|
31
43
|
"script/console",
|
32
44
|
"script/destroy",
|
33
45
|
"script/generate",
|
46
|
+
"tasks/build.rake",
|
47
|
+
"test/dummy_test.rb",
|
34
48
|
"test/mock/custom_queries/test.yml",
|
35
|
-
"test/mock/
|
49
|
+
"test/mock/dummy.rb",
|
50
|
+
"test/mock/dummy_processor.rb",
|
36
51
|
"test/mock/queries/bar.yml",
|
37
52
|
"test/mock/queries/foo.yml",
|
38
|
-
"test/mock/
|
39
|
-
"test/
|
40
|
-
"test/
|
41
|
-
"test/
|
42
|
-
"test/
|
43
|
-
"test/
|
44
|
-
"test/
|
45
|
-
"test/
|
53
|
+
"test/mock/user_processor.rb",
|
54
|
+
"test/query_test.rb",
|
55
|
+
"test/querybuilder/basic.yml",
|
56
|
+
"test/querybuilder/custom.yml",
|
57
|
+
"test/querybuilder/errors.yml",
|
58
|
+
"test/querybuilder/filters.yml",
|
59
|
+
"test/querybuilder/group.yml",
|
60
|
+
"test/querybuilder/joins.yml",
|
61
|
+
"test/querybuilder/mixed.yml",
|
62
|
+
"test/querybuilder/rubyless.yml",
|
63
|
+
"test/querybuilder_test.rb",
|
46
64
|
"test/test_helper.rb"
|
47
65
|
]
|
48
66
|
s.homepage = %q{http://zenadmin.org/524}
|
49
67
|
s.rdoc_options = ["--charset=UTF-8"]
|
50
68
|
s.require_paths = ["lib"]
|
51
69
|
s.rubygems_version = %q{1.3.6}
|
52
|
-
s.summary = %q{QueryBuilder is an interpreter for the "pseudo sql" language}
|
70
|
+
s.summary = %q{QueryBuilder is an interpreter for the "pseudo sql" language.}
|
53
71
|
s.test_files = [
|
54
|
-
"test/
|
55
|
-
"test/mock/
|
56
|
-
"test/
|
72
|
+
"test/dummy_test.rb",
|
73
|
+
"test/mock/dummy.rb",
|
74
|
+
"test/mock/dummy_processor.rb",
|
75
|
+
"test/mock/user_processor.rb",
|
76
|
+
"test/query_test.rb",
|
77
|
+
"test/querybuilder_test.rb",
|
57
78
|
"test/test_helper.rb"
|
58
79
|
]
|
59
80
|
|
@@ -62,11 +83,17 @@ Gem::Specification.new do |s|
|
|
62
83
|
s.specification_version = 3
|
63
84
|
|
64
85
|
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
86
|
+
s.add_runtime_dependency(%q<rubyless>, [">= 0.5.0"])
|
87
|
+
s.add_development_dependency(%q<shoulda>, [">= 0"])
|
65
88
|
s.add_development_dependency(%q<yamltest>, [">= 0.5.0"])
|
66
89
|
else
|
90
|
+
s.add_dependency(%q<rubyless>, [">= 0.5.0"])
|
91
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
67
92
|
s.add_dependency(%q<yamltest>, [">= 0.5.0"])
|
68
93
|
end
|
69
94
|
else
|
95
|
+
s.add_dependency(%q<rubyless>, [">= 0.5.0"])
|
96
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
70
97
|
s.add_dependency(%q<yamltest>, [">= 0.5.0"])
|
71
98
|
end
|
72
99
|
end
|
data/tasks/build.rake
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
|
2
|
+
desc "Build native extension"
|
3
|
+
task :build => [:build_rb, :build_ext] do
|
4
|
+
end
|
5
|
+
|
6
|
+
task :build_rb do
|
7
|
+
`cd lib && ragel -R querybuilder_rb.rl`
|
8
|
+
end
|
9
|
+
|
10
|
+
task :build_ext => [:ragel_ext, :extconf] do
|
11
|
+
`cd lib && make`
|
12
|
+
end
|
13
|
+
|
14
|
+
task :extconf do
|
15
|
+
`cd lib && ruby extconf.rb`
|
16
|
+
end
|
17
|
+
|
18
|
+
task :ragel_ext do
|
19
|
+
`cd lib && ragel querybuilder_ext.rl`
|
20
|
+
end
|
data/test/dummy_test.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class DummyTest < Test::Unit::TestCase
|
4
|
+
Query = QueryBuilder::Query
|
5
|
+
|
6
|
+
context 'A class with QueryBuilder included' do
|
7
|
+
|
8
|
+
subject do
|
9
|
+
Dummy
|
10
|
+
end
|
11
|
+
|
12
|
+
should 'return compiler class on query_compiler' do
|
13
|
+
assert_equal DummyProcessor, subject.query_compiler
|
14
|
+
end
|
15
|
+
|
16
|
+
should 'return a Query object on build_query' do
|
17
|
+
assert_kind_of Query, subject.build_query(:all, 'objects')
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
DummyProcessor:
|
2
2
|
abc:
|
3
3
|
select:
|
4
4
|
- a
|
@@ -13,13 +13,14 @@ DummyQuery:
|
|
13
13
|
order: a ASC
|
14
14
|
|
15
15
|
two_table:
|
16
|
+
main_table: 'table_one'
|
16
17
|
select:
|
17
|
-
- x
|
18
|
+
- x AS x
|
18
19
|
- IF(table_one.y,table_one.y,table_two.z) AS y
|
19
20
|
- table_two.name
|
20
|
-
tables:
|
21
|
-
- table_one
|
21
|
+
tables:
|
22
22
|
- table_two
|
23
|
+
- table_one
|
23
24
|
|
24
25
|
two_table_main:
|
25
26
|
main_table: foo
|
data/test/mock/dummy.rb
ADDED
@@ -0,0 +1,160 @@
|
|
1
|
+
class DummyProcessor < QueryBuilder::Processor
|
2
|
+
set_main_table 'objects'
|
3
|
+
set_main_class 'DummyClass'
|
4
|
+
set_default :scope, 'self'
|
5
|
+
after_process :insert_after_filter
|
6
|
+
load_custom_queries File.join(File.dirname(__FILE__), '*')
|
7
|
+
|
8
|
+
# Scope current context with previous context.
|
9
|
+
# For example:
|
10
|
+
# current previous
|
11
|
+
# ['parent_id', 'id'] ==> no1.parent_id = nodes.id
|
12
|
+
def scope_fields(scope)
|
13
|
+
case scope
|
14
|
+
when 'self'
|
15
|
+
['parent_id', 'id']
|
16
|
+
when 'parent'
|
17
|
+
last? ? ['parent_id', 'parent_id'] : ['parent_id', 'id']
|
18
|
+
when 'project'
|
19
|
+
last? ? ['project_id', 'project_id'] : ['project_id', 'id']
|
20
|
+
when 'site', main_table
|
21
|
+
# not an error, but do not scope
|
22
|
+
[]
|
23
|
+
else
|
24
|
+
# error
|
25
|
+
nil
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Overwrite this and take care to check for valid fields.
|
30
|
+
def process_field(fld_name)
|
31
|
+
if ['id', 'parent_id', 'project_id', 'section_id', 'kpath', 'name', 'event_at', 'custom_a'].include?(fld_name)
|
32
|
+
"#{table}.#{fld_name}"
|
33
|
+
elsif fld_name == 'REF_DATE'
|
34
|
+
context[:ref_date] ? insert_bind(context[:ref_date]) : 'now()'
|
35
|
+
else
|
36
|
+
super # raises an error
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# We do special things with 'class ='
|
41
|
+
def process_equal(left, right)
|
42
|
+
if left == [:field, 'class'] && right[0] == :string
|
43
|
+
case right.last
|
44
|
+
when 'Client'
|
45
|
+
kpath = 'NRCC'
|
46
|
+
else
|
47
|
+
raise QueryBuilder::SyntaxError.new("Unknown class #{right.last.inspect}.")
|
48
|
+
end
|
49
|
+
"#{field_or_attr('kpath')} LIKE #{insert_bind((kpath + '%').inspect)}"
|
50
|
+
else
|
51
|
+
super
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# We do special things with 'class ='
|
56
|
+
def process_match(left, right)
|
57
|
+
end
|
58
|
+
|
59
|
+
def process_function(arg, method)
|
60
|
+
method, arg = process(method), process(arg)
|
61
|
+
|
62
|
+
case method
|
63
|
+
when 'year'
|
64
|
+
"strftime('%Y',#{arg})"
|
65
|
+
else
|
66
|
+
super
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# ******** And maybe overwrite these **********
|
71
|
+
def parse_custom_query_argument(key, value)
|
72
|
+
return nil unless value
|
73
|
+
super(key, value.gsub('REF_DATE', context[:ref_date] ? insert_bind(context[:ref_date]) : 'now()'))
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
# Change class
|
78
|
+
def class_relation(relation)
|
79
|
+
case relation
|
80
|
+
when 'users'
|
81
|
+
change_processor 'UserProcessor'
|
82
|
+
add_table('users')
|
83
|
+
add_filter "#{table('users')}.node_id = #{field_or_attr('id', table(self.class.main_table))}"
|
84
|
+
return true
|
85
|
+
else
|
86
|
+
return nil
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# Moving to another context without a join table
|
91
|
+
def context_relation(relation)
|
92
|
+
case relation
|
93
|
+
when 'self'
|
94
|
+
fields = ['id', 'id']
|
95
|
+
when 'parent'
|
96
|
+
fields = ['id', 'parent_id']
|
97
|
+
when 'project'
|
98
|
+
fields = ['id', 'project_id']
|
99
|
+
else
|
100
|
+
return nil
|
101
|
+
end
|
102
|
+
|
103
|
+
add_table(main_table)
|
104
|
+
add_filter "#{field_or_attr(fields[0])} = #{field_or_attr(fields[1], table(main_table, -1))}"
|
105
|
+
end
|
106
|
+
|
107
|
+
# Filtering of objects in scope
|
108
|
+
def filter_relation(relation)
|
109
|
+
case relation
|
110
|
+
when 'letters'
|
111
|
+
add_table(main_table)
|
112
|
+
add_filter "#{table}.kpath LIKE #{quote('NNL%')}"
|
113
|
+
when 'clients'
|
114
|
+
add_table(main_table)
|
115
|
+
add_filter "#{table}.kpath LIKE #{quote("NRCC%")}"
|
116
|
+
when main_table, 'children'
|
117
|
+
# no filter
|
118
|
+
add_table(main_table)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# Moving to another context through 'joins'
|
123
|
+
def join_relation(relation)
|
124
|
+
case relation
|
125
|
+
when 'recipients'
|
126
|
+
fields = ['source_id', 4, 'target_id']
|
127
|
+
when 'icons'
|
128
|
+
fields = ['target_id', 5, 'source_id']
|
129
|
+
when 'tags'
|
130
|
+
# just to test joins
|
131
|
+
add_table(main_table)
|
132
|
+
needs_join_table('objects', 'INNER', 'tags', 'TABLE1.id = TABLE2.node_id')
|
133
|
+
return true
|
134
|
+
else
|
135
|
+
return false
|
136
|
+
end
|
137
|
+
|
138
|
+
add_table(main_table)
|
139
|
+
add_table('links')
|
140
|
+
# source --> target
|
141
|
+
add_filter "#{table('links')}.#{fields[0]} = #{field_or_attr('id', table(main_table,-1))}"
|
142
|
+
add_filter "#{table('links')}.relation_id = #{fields[1]}"
|
143
|
+
add_filter "#{field_or_attr('id')} = #{table('links')}.#{fields[2]}"
|
144
|
+
end
|
145
|
+
|
146
|
+
def insert_after_filter
|
147
|
+
if after_filter = context[:after_filter]
|
148
|
+
add_filter after_filter
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
|
154
|
+
class DummyClass
|
155
|
+
# Mock connection and quoting
|
156
|
+
def self.connection; self; end
|
157
|
+
def self.quote(obj)
|
158
|
+
obj.kind_of?(String) ? "'#{obj}'" : obj
|
159
|
+
end
|
160
|
+
end
|
data/test/mock/queries/bar.yml
CHANGED
data/test/mock/queries/foo.yml
CHANGED
@@ -0,0 +1,34 @@
|
|
1
|
+
class TestUser
|
2
|
+
def self.connection; self; end
|
3
|
+
def self.quote(obj)
|
4
|
+
obj.kind_of?(String) ? "'#{obj}'" : obj
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
class UserProcessor < QueryBuilder::Processor
|
9
|
+
set_main_table 'users'
|
10
|
+
set_main_class 'TestUser'
|
11
|
+
set_default :order, 'name asc, first_name asc'
|
12
|
+
set_default :context, 'self'
|
13
|
+
|
14
|
+
def process_relation(relation)
|
15
|
+
case relation
|
16
|
+
when 'objects'
|
17
|
+
this.apply_scope(default[:scope]) if context[:last]
|
18
|
+
add_table('objects')
|
19
|
+
@query.add_filter "#{table('objects')}.id = #{field_or_attr('node_id')}"
|
20
|
+
change_processor 'DummyProcessor'
|
21
|
+
else
|
22
|
+
return nil
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Overwrite this and take car to check for valid fields.
|
27
|
+
def process_field(field_name)
|
28
|
+
if ['id', 'name', 'first_name', 'node_id'].include?(field_name)
|
29
|
+
"#{table}.#{field_name}"
|
30
|
+
else
|
31
|
+
super # raises
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/test/query_test.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class QueryTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
context 'An empty query object' do
|
6
|
+
subject do
|
7
|
+
QueryBuilder::Query.new(QueryBuilder::Processor)
|
8
|
+
end
|
9
|
+
|
10
|
+
should 'respond to rebuild_tables' do
|
11
|
+
subject.tables = ['foo', 'bar']
|
12
|
+
subject.rebuild_tables!
|
13
|
+
h = {'foo' => ['foo'], 'bar' => ['bar']}
|
14
|
+
assert_equal h, subject.table_alias
|
15
|
+
end
|
16
|
+
|
17
|
+
should 'respond to rebuild_attributes_hash' do
|
18
|
+
subject.select = ['1 as one', 'two', '(20 - (weight / (height * height))) AS bmi_nrm']
|
19
|
+
subject.rebuild_attributes_hash!
|
20
|
+
h = {"bmi_nrm"=>"(20 - (weight / (height * height)))"}
|
21
|
+
assert_equal h, subject.attributes_alias
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'A query returned from a processor' do
|
26
|
+
subject do
|
27
|
+
DummyProcessor.new('objects').query
|
28
|
+
end
|
29
|
+
|
30
|
+
should 'return a string representing an array with find SQL and parameters string on to_s' do
|
31
|
+
assert_equal "[%Q{SELECT objects.* FROM objects WHERE objects.parent_id = ?}, id]", subject.to_s
|
32
|
+
end
|
33
|
+
|
34
|
+
should 'return a string representing an array with count SQL and parameters string on to_s count' do
|
35
|
+
assert_equal "[%Q{SELECT COUNT(*) FROM objects WHERE objects.parent_id = ?}, id]", subject.to_s(:count)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
empty:
|
2
|
+
src: ""
|
3
|
+
sxp: "[:query]"
|
4
|
+
res: "[%Q{SELECT objects.* FROM objects WHERE objects.parent_id = ?}, id]"
|
5
|
+
|
6
|
+
objects:
|
7
|
+
sxp: '[:query, [:relation, "objects"]]'
|
8
|
+
res: "[%Q{SELECT objects.* FROM objects WHERE objects.parent_id = ?}, id]"
|
9
|
+
|
10
|
+
objects_in_project:
|
11
|
+
sxp: '[:query, [:scope, [:relation, "objects"], "project"]]'
|
12
|
+
res: "[%Q{SELECT objects.* FROM objects WHERE objects.project_id = ?}, project_id]"
|
13
|
+
|
14
|
+
objects_in_site:
|
15
|
+
res: "%Q{SELECT objects.* FROM objects}"
|
16
|
+
|
17
|
+
recipients:
|
18
|
+
sxp: '[:query, [:relation, "recipients"]]'
|
19
|
+
res: "[%Q{SELECT objects.* FROM links,objects WHERE objects.id = links.target_id AND links.relation_id = 4 AND links.source_id = ?}, id]"
|
20
|
+
sql: "SELECT objects.* FROM links,objects WHERE objects.id = links.target_id AND links.relation_id = 4 AND links.source_id = 123"
|
21
|
+
|
22
|
+
letters_in_project:
|
23
|
+
sxp: '[:query, [:scope, [:relation, "letters"], "project"]]'
|
24
|
+
res: "[%Q{SELECT objects.* FROM objects WHERE objects.kpath LIKE 'NNL%' AND objects.project_id = ?}, project_id]"
|
25
|
+
|
26
|
+
parent:
|
27
|
+
res: "[%Q{SELECT objects.* FROM objects WHERE objects.id = ?}, parent_id]"
|
28
|
+
|
29
|
+
order_single_table:
|
30
|
+
src: "objects in project order by name ASC"
|
31
|
+
sxp: '[:query, [:order, [:scope, [:relation, "objects"], "project"], [:asc, [:field, "name"]]]]'
|
32
|
+
res: "[%Q{SELECT objects.* FROM objects WHERE objects.project_id = ? ORDER BY objects.name ASC}, project_id]"
|
33
|
+
|
34
|
+
order_many_tables:
|
35
|
+
src: "recipients order by name"
|
36
|
+
res: "[%Q{SELECT objects.* FROM links,objects WHERE objects.id = links.target_id AND links.relation_id = 4 AND links.source_id = ? ORDER BY objects.name}, id]"
|
37
|
+
|
38
|
+
order_many_params:
|
39
|
+
src: "objects in project order by name, id desc"
|
40
|
+
sxp: '[:query, [:order, [:scope, [:relation, "objects"], "project"], [:field, "name"], [:desc, [:field, "id"]]]]'
|
41
|
+
res: "[%Q{SELECT objects.* FROM objects WHERE objects.project_id = ? ORDER BY objects.name, objects.id DESC}, project_id]"
|
42
|
+
|
43
|
+
order_without_scope:
|
44
|
+
src: "objects order by name asc"
|
45
|
+
res: "[%Q{SELECT objects.* FROM objects WHERE objects.parent_id = ? ORDER BY objects.name ASC}, id]"
|
46
|
+
|
47
|
+
limit:
|
48
|
+
src: "objects in project limit 2"
|
49
|
+
sxp: '[:query, [:limit, [:scope, [:relation, "objects"], "project"], [:integer, "2"]]]'
|
50
|
+
res: "[%Q{SELECT objects.* FROM objects WHERE objects.project_id = ? LIMIT 2}, project_id]"
|
51
|
+
|
52
|
+
limit_with_order:
|
53
|
+
src: "objects in project order by name desc limit 10"
|
54
|
+
res: "[%Q{SELECT objects.* FROM objects WHERE objects.project_id = ? ORDER BY objects.name DESC LIMIT 10}, project_id]"
|
55
|
+
|
56
|
+
offset_in_limit:
|
57
|
+
src: "objects in project limit 3,2"
|
58
|
+
res: "[%Q{SELECT objects.* FROM objects WHERE objects.project_id = ? LIMIT 2 OFFSET 3}, project_id]"
|
59
|
+
|
60
|
+
offset:
|
61
|
+
src: "objects in project limit 2 offset 3"
|
62
|
+
sxp: '[:query, [:offset, [:limit, [:scope, [:relation, "objects"], "project"], [:integer, "2"]], [:integer, "3"]]]'
|
63
|
+
res: "[%Q{SELECT objects.* FROM objects WHERE objects.project_id = ? LIMIT 2 OFFSET 3}, project_id]"
|
64
|
+
|
65
|
+
paginate:
|
66
|
+
src: "objects in site limit 2 paginate p"
|
67
|
+
sxp: '[:query, [:paginate, [:limit, [:scope, [:relation, "objects"], "site"], [:integer, "2"]], [:param, "p"]]]'
|
68
|
+
res: "[%Q{SELECT objects.* FROM objects LIMIT 2 OFFSET ?}, ((p.to_i > 0 ? p.to_i : 1)-1)*2]"
|
69
|
+
|
70
|
+
recipients_or_objects:
|
71
|
+
src: recipients or objects
|
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]"
|
74
|
+
|
75
|
+
recipients_or_objects_or_letters:
|
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]"
|
78
|
+
|
79
|
+
or_clause_with_filter:
|
80
|
+
src: "(recipients where name = 'foo') or objects"
|
81
|
+
sxp: '[:query, [:clause_or, [:clause_par, [:filter, [:relation, "recipients"], [:"=", [:field, "name"], [:string, "foo"]]]], [:relation, "objects"]]]'
|
82
|
+
|
83
|
+
count_sql:
|
84
|
+
src: "objects in project"
|
85
|
+
count: "[%Q{SELECT COUNT(*) FROM objects WHERE objects.project_id = ?}, project_id]"
|
86
|
+
|
87
|
+
after_process_callback:
|
88
|
+
context:
|
89
|
+
after_filter: '(1 = 1)'
|
90
|
+
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%')}"
|