querybuilder 0.5.9 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- 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%')}"
|