rquerypad 0.1.20 → 0.1.21
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/CHANGELOG +3 -0
- data/Rakefile +1 -1
- data/lib/rquerypad.rb +249 -231
- metadata +2 -2
data/CHANGELOG
CHANGED
data/Rakefile
CHANGED
data/lib/rquerypad.rb
CHANGED
@@ -3,15 +3,15 @@ author: Leon Li(scorpio_leon@hotmail.com)
|
|
3
3
|
=end
|
4
4
|
require 'md5'
|
5
5
|
class Rquerypad
|
6
|
-
|
6
|
+
class << self
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
8
|
+
def prepare_with_debug
|
9
|
+
prepare(true)
|
10
|
+
end
|
11
|
+
def prepare(debug = $RQUERYPAD_DEBUG)
|
12
|
+
return nil unless @prepared.nil?
|
13
|
+
@prepared = true
|
14
|
+
ActiveRecord::Base.class_eval %{
|
15
15
|
class << self
|
16
16
|
def group_tables(options)
|
17
17
|
group = [options[:group], scope(:find, :group) ].join(", ")
|
@@ -25,8 +25,8 @@ class Rquerypad
|
|
25
25
|
include_eager_order?(options) || include_eager_conditions?(options) || include_eager_select?(options) || include_eager_group?(options)
|
26
26
|
end
|
27
27
|
end
|
28
|
-
|
29
|
-
|
28
|
+
}
|
29
|
+
ActiveRecord::Base.class_eval %{
|
30
30
|
require "rquerypad"
|
31
31
|
|
32
32
|
class << self
|
@@ -44,7 +44,7 @@ class Rquerypad
|
|
44
44
|
#p "rquerypad_cache[cache_key]: #\{rquerypad_cache[cache_key]\}"
|
45
45
|
if rquerypad_cache[cache_key].nil?
|
46
46
|
#{"p 'process for:', options" if debug}
|
47
|
-
Rquerypad.new(self).improve_options!(options)
|
47
|
+
options = Rquerypad.new(self).improve_options!(options)
|
48
48
|
rquerypad_cache[cache_key] = Marshal.dump(options)
|
49
49
|
#p "rquerypad_cache[cache_key]: #\{rquerypad_cache[cache_key]\}"
|
50
50
|
else
|
@@ -66,9 +66,9 @@ class Rquerypad
|
|
66
66
|
@@rquerypad_cache
|
67
67
|
end
|
68
68
|
end
|
69
|
-
|
69
|
+
}
|
70
70
|
|
71
|
-
|
71
|
+
ActiveRecord::Calculations.class_eval %{
|
72
72
|
require "rquerypad"
|
73
73
|
module ClassMethods
|
74
74
|
@@rquerypad_cache = {}
|
@@ -80,7 +80,7 @@ class Rquerypad
|
|
80
80
|
cache_key = Rquerypad.options_key(self, options)
|
81
81
|
if rquerypad_cache[cache_key].nil?
|
82
82
|
#{"p 'process for:', options" if debug}
|
83
|
-
Rquerypad.new(self).improve_options!(options)
|
83
|
+
options = Rquerypad.new(self).improve_options!(options)
|
84
84
|
rquerypad_cache[cache_key] = Marshal.dump(options)
|
85
85
|
else
|
86
86
|
options = Marshal.load(rquerypad_cache[cache_key])
|
@@ -97,251 +97,269 @@ class Rquerypad
|
|
97
97
|
@@rquerypad_cache
|
98
98
|
end
|
99
99
|
end
|
100
|
-
|
100
|
+
}
|
101
101
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
102
|
+
Hash.class_eval do
|
103
|
+
def single_lt?(other)
|
104
|
+
return false if self == other
|
105
|
+
return true if self.size == 0
|
106
|
+
return false unless other.is_a?(Hash)
|
107
|
+
return false if other.nil? || other.size < self.size
|
108
|
+
return false if self.size != other.size || self.size > 1
|
109
|
+
a = self.to_a[0]
|
110
|
+
o = other.to_a[0]
|
111
|
+
return false if a[0] != o[0]
|
112
|
+
return true unless a[1].is_a?(Hash)
|
113
|
+
a[1].single_lt?(o[1])
|
114
|
+
end
|
115
|
+
def single_gt?(other)
|
116
|
+
return false if self == other
|
117
|
+
return !(single_lt?(other))
|
118
|
+
end
|
119
|
+
end
|
114
120
|
end
|
115
|
-
|
116
|
-
|
117
|
-
|
121
|
+
|
122
|
+
def process_inner_join(sql, inner_joins)
|
123
|
+
inner_joins.each {|i| sql.gsub!(/LEFT OUTER JOIN [`]?#{i}[`]?/, "INNER JOIN #{i}")} unless inner_joins.empty?
|
124
|
+
sql
|
118
125
|
end
|
119
|
-
end
|
120
|
-
end
|
121
126
|
|
122
|
-
|
123
|
-
|
124
|
-
|
127
|
+
def options_key(obj, options)
|
128
|
+
key = obj.to_s + options.to_a.to_s
|
129
|
+
key = MD5.hexdigest(key) if key.length > 100
|
130
|
+
key
|
131
|
+
end
|
125
132
|
end
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
133
|
+
def initialize(obj)
|
134
|
+
@owner = obj
|
135
|
+
@class_name = obj.to_s.scan(/(\w*::)*([^\(]*)/)[0][1]
|
136
|
+
# #@table_name = @class_name.pluralize.underscore
|
137
|
+
@table_name = obj.table_name
|
138
|
+
@tnwithdot = @table_name + "."
|
139
|
+
@new_include = []
|
140
|
+
@old_include = nil
|
141
|
+
@inner_joins = []
|
131
142
|
end
|
132
|
-
end
|
133
|
-
def initialize(obj)
|
134
|
-
@owner = obj
|
135
|
-
@class_name = obj.to_s.scan(/(\w*::)*([^\(]*)/)[0][1]
|
136
|
-
#@table_name = @class_name.pluralize.underscore
|
137
|
-
@table_name = obj.table_name
|
138
|
-
@tnwithdot = @table_name + "."
|
139
|
-
@new_include = []
|
140
|
-
@old_include = nil
|
141
|
-
@inner_joins = []
|
142
|
-
end
|
143
143
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
144
|
+
def improve_options!(option_hash)
|
145
|
+
new_options = {}
|
146
|
+
option_hash.each do |key, value|
|
147
|
+
if value.blank?
|
148
|
+
new_options[key] = value
|
149
|
+
next
|
150
|
+
end
|
151
|
+
key_str = key.to_s
|
152
|
+
if key_str == "conditions"
|
153
|
+
new_options[key] = improve_conditions(value)
|
154
|
+
elsif (key_str == "order" || key_str == "group" || key_str == "group_field")
|
155
|
+
new_options[key] = improve_ordergroup(value).join(", ")
|
156
|
+
else
|
157
|
+
new_options[key] = value
|
158
|
+
if (key_str == "include")
|
159
|
+
@old_include = value
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
return new_options if @new_include.empty?
|
164
|
+
# #generate new include
|
159
165
|
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
if key.to_s == "include"
|
166
|
-
option_hash[key] = @new_include
|
166
|
+
remove_dup_includes
|
167
|
+
unless @new_include.nil?
|
168
|
+
new_options[:include] ||= []
|
169
|
+
new_options[:include] += @new_include
|
170
|
+
new_options[:include].uniq!
|
167
171
|
end
|
168
|
-
|
172
|
+
new_options[:inner_joins] = @inner_joins unless @inner_joins.empty?
|
173
|
+
new_options
|
169
174
|
end
|
170
|
-
option_hash[:inner_joins] = @inner_joins unless @inner_joins.empty?
|
171
|
-
end
|
172
175
|
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
176
|
+
def remove_dup_includes
|
177
|
+
final_includes = []
|
178
|
+
@new_include.each do |ni|
|
179
|
+
next if final_includes.include?(ni)
|
180
|
+
if final_includes.size > 0
|
181
|
+
final_includes.each_index do |i|
|
182
|
+
if ni.is_a?(Hash)
|
183
|
+
if final_includes[i].is_a?(Hash)
|
184
|
+
if final_includes[i].single_lt?(ni)
|
185
|
+
final_includes[i] = ni
|
186
|
+
elsif final_includes[i].single_gt?(ni)
|
187
|
+
else
|
188
|
+
final_includes << ni
|
189
|
+
end
|
190
|
+
elsif ni.entries[0][0].to_s == final_includes[i].to_s
|
191
|
+
final_includes[i] = ni
|
192
|
+
else
|
193
|
+
final_includes << ni
|
194
|
+
end
|
195
|
+
else
|
196
|
+
if final_includes[i].is_a?(Hash)
|
197
|
+
final_includes << ni if final_includes[i].entries[0][0].to_s != ni.to_s
|
198
|
+
else
|
199
|
+
final_includes << ni if final_includes[i].to_s != ni.to_s
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
189
203
|
else
|
190
|
-
|
191
|
-
end
|
192
|
-
else
|
193
|
-
if final_includes[i].is_a?(Hash)
|
194
|
-
final_includes << ni if final_includes[i].entries[0][0].to_s != ni.to_s
|
195
|
-
else
|
196
|
-
final_includes << ni if final_includes[i].to_s != ni.to_s
|
204
|
+
final_includes << ni
|
197
205
|
end
|
198
|
-
end
|
199
206
|
end
|
200
|
-
|
201
|
-
final_includes << ni
|
202
|
-
end
|
207
|
+
@new_include = final_includes
|
203
208
|
end
|
204
|
-
@new_include = final_includes
|
205
|
-
end
|
206
209
|
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
end
|
217
|
-
options.merge!(new_options)
|
218
|
-
else
|
219
|
-
if options.is_a?(String)
|
220
|
-
options = [options]
|
221
|
-
end
|
222
|
-
str = options[0]
|
223
|
-
return nil if str.nil?
|
224
|
-
qp = /['"][^."]*['"]/
|
225
|
-
temp = str.scan(qp)
|
226
|
-
#replace string in quote to avoid unecessary processing
|
227
|
-
str.gsub!(qp, "'[??]'") unless temp.empty?
|
228
|
-
str.gsub!(/(([\w\(\)]+\.)+\w+)[ !><=]/) do |n|
|
229
|
-
#cut last char and abstract association for include
|
230
|
-
if n =~ /^\(/
|
231
|
-
'(' + abstract_association(n[1..-2]) + n[-1, 1]
|
210
|
+
def improve_conditions(options)
|
211
|
+
new_options = nil
|
212
|
+
if options.is_a?(Hash)
|
213
|
+
# #work around frozen issue
|
214
|
+
new_options = {}
|
215
|
+
until options.empty?
|
216
|
+
key, value = options.shift
|
217
|
+
new_options[process_single(key.to_s)] = value
|
218
|
+
end
|
232
219
|
else
|
233
|
-
|
234
|
-
|
220
|
+
if options.is_a?(String)
|
221
|
+
new_options = [options]
|
222
|
+
else
|
223
|
+
new_options = options.dup
|
224
|
+
end
|
225
|
+
str = new_options[0]
|
226
|
+
return nil if str.nil?
|
227
|
+
qp = /['"][^."]*['"]/
|
228
|
+
temp = str.scan(qp)
|
229
|
+
# #replace string in quote to avoid unecessary processing
|
230
|
+
str = str.gsub(qp, "'[??]'") unless temp.empty?
|
231
|
+
str = str.gsub(/(([\w\(\)]+\.)+\w+)[ !><=]/) do |n|
|
232
|
+
# #cut last char and abstract association for include
|
233
|
+
if n =~ /^\(/
|
234
|
+
'(' + abstract_association(n[1..-2]) + n[-1, 1]
|
235
|
+
else
|
236
|
+
abstract_association(n[0..-2]) + n[-1, 1]
|
237
|
+
end
|
235
238
|
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
239
|
+
end
|
240
|
+
# #add @table_name on single field
|
241
|
+
str = str.gsub(/[\.:]?[`"']?\w+[`"']?[\.]?/) {|x| (x =~ /\D+/).nil? || x[-1, 1] == "." || x[0, 1] == ":" || ["and", "or", "is", "null", "not", "like", "in"].include?(x.downcase) ? x : @tnwithdot + x}
|
242
|
+
str = str.gsub(/\.#{@table_name}\./, ".")
|
243
|
+
# #recover string in quote
|
244
|
+
unless temp.empty?
|
245
|
+
i = -1
|
246
|
+
str = str.gsub(/\'\[\?\?\]\'/) do
|
247
|
+
i += 1
|
248
|
+
temp[i]
|
249
|
+
end
|
250
|
+
end
|
251
|
+
new_options[0] = str
|
246
252
|
end
|
247
|
-
|
248
|
-
options[0] = str
|
253
|
+
new_options
|
249
254
|
end
|
250
|
-
options
|
251
|
-
end
|
252
255
|
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
256
|
+
def process_single(key)
|
257
|
+
return key.sub('=', '') if key[0, 1] == '='
|
258
|
+
if key.include?(".")
|
259
|
+
if /^(.+)[ ]/ =~ key
|
260
|
+
key = key.sub("#$1", abstract_association("#$1"))
|
261
|
+
else
|
262
|
+
key = key.sub(/^.+$/, abstract_association(key))
|
263
|
+
end
|
264
|
+
else
|
265
|
+
key = key.sub(/^.+$/, @tnwithdot + key)
|
266
|
+
end
|
267
|
+
key
|
263
268
|
end
|
264
|
-
end
|
265
269
|
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
def abstract_association(str)
|
273
|
-
result = nil
|
274
|
-
owner = @owner
|
275
|
-
names = str.split(".")
|
276
|
-
return str if names.size == 2 && names[0] == @table_name
|
277
|
-
#seperate assocations/tables and field
|
278
|
-
tables, field = names[0..-2], names[-1]
|
279
|
-
owners = []
|
280
|
-
#get relevant owner for each table
|
281
|
-
tables.each_index do |i|
|
282
|
-
#tables[i] = tables[i].pluralize
|
283
|
-
if i == 0
|
284
|
-
owners[i] = owner
|
285
|
-
else
|
286
|
-
tname = cut_end_underscore(tables[i-1])
|
287
|
-
r = owners[i-1].reflections[tname.to_sym].options
|
288
|
-
owners[i] = r[:class_name].nil? ? eval(owners[i-1].to_s.gsub(/\w*$/, "")+tname.singularize.camelize) : eval("#{r[:class_name]}")
|
289
|
-
end
|
290
|
-
end
|
291
|
-
owners.reverse!
|
292
|
-
tables.reverse!
|
293
|
-
tables.each_index do |i|
|
294
|
-
if tables[i][-1, 1] == "_"
|
295
|
-
tables[i].reverse!.sub!("_", "").reverse!
|
296
|
-
@inner_joins << transfer_table_name(tables[i], owners[i])
|
297
|
-
end
|
298
|
-
end
|
299
|
-
#process special id field in a belongs_to association
|
300
|
-
if field == "id"
|
301
|
-
if owners[0].reflections[tables[0].to_sym].macro.to_s == "belongs_to"
|
302
|
-
result = transfer_table_id(tables[0], owners[0])
|
303
|
-
@inner_joins.delete(tables[0]) if @inner_joins.include?(tables[0])
|
304
|
-
unless owners[1].nil?
|
305
|
-
result = transfer_table_name(tables[1], owners[1]) + "." + result
|
270
|
+
def improve_ordergroup(fields)
|
271
|
+
result = []
|
272
|
+
if fields.is_a?(Array)
|
273
|
+
result += fields
|
274
|
+
else
|
275
|
+
result << fields
|
306
276
|
end
|
307
|
-
|
308
|
-
|
309
|
-
return result if tables.empty?
|
310
|
-
end
|
277
|
+
result.each_index {|i| result[i] = process_single(result[i])}
|
278
|
+
result
|
311
279
|
end
|
280
|
+
|
281
|
+
def abstract_association(str)
|
282
|
+
result = nil
|
283
|
+
owner = @owner
|
284
|
+
names = str.split(".")
|
285
|
+
return str if names.size == 2 && names[0] == @table_name
|
286
|
+
# #seperate assocations/tables and field
|
287
|
+
tables, field = names[0..-2], names[-1]
|
288
|
+
owners = []
|
289
|
+
# #get relevant owner for each table
|
290
|
+
tables.each_index do |i|
|
291
|
+
# #tables[i] = tables[i].pluralize
|
292
|
+
if i == 0
|
293
|
+
owners[i] = owner
|
294
|
+
else
|
295
|
+
tname = cut_end_underscore(tables[i-1])
|
296
|
+
r = owners[i-1].reflections[tname.to_sym].options
|
297
|
+
owners[i] = r[:class_name].nil? ? eval(owners[i-1].to_s.gsub(/\w*$/, "")+tname.singularize.camelize) : eval("#{r[:class_name]}")
|
298
|
+
end
|
299
|
+
end
|
300
|
+
owners.reverse!
|
301
|
+
tables.reverse!
|
302
|
+
tables.each_index do |i|
|
303
|
+
if tables[i][-1, 1] == "_"
|
304
|
+
tables[i].reverse!.sub!("_", "").reverse!
|
305
|
+
@inner_joins << transfer_table_name(tables[i], owners[i])
|
306
|
+
end
|
307
|
+
end
|
308
|
+
# #process special id field in a belongs_to association
|
309
|
+
if field == "id"
|
310
|
+
if owners[0].reflections[tables[0].to_sym].macro.to_s == "belongs_to"
|
311
|
+
result = transfer_table_id(tables[0], owners[0])
|
312
|
+
@inner_joins.delete(tables[0]) if @inner_joins.include?(tables[0])
|
313
|
+
unless owners[1].nil?
|
314
|
+
result = transfer_table_name(tables[1], owners[1]) + "." + result
|
315
|
+
end
|
316
|
+
tables.delete_at(0)
|
317
|
+
owners.delete_at(0)
|
318
|
+
return result if tables.empty?
|
319
|
+
end
|
320
|
+
end
|
312
321
|
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
322
|
+
# #get include
|
323
|
+
if tables.length == 1 && tables[0] != @table_name
|
324
|
+
@new_include << tables[0].to_sym unless @new_include.include?(tables[0].to_sym)
|
325
|
+
else
|
326
|
+
tables_clone = tables[0..-1]
|
327
|
+
value = tables_clone.shift.to_sym
|
328
|
+
until tables_clone.empty?
|
329
|
+
hashes = {}
|
330
|
+
hashes[tables_clone.shift.to_sym] = value
|
331
|
+
value = hashes
|
332
|
+
end
|
333
|
+
@new_include << hashes unless hashes.nil? || @new_include.include?(hashes)
|
334
|
+
end
|
335
|
+
result ||= transfer_table_name(tables[0], owners[0]) + "." + field
|
327
336
|
|
328
|
-
|
337
|
+
end
|
338
|
+
|
339
|
+
def raise_error(name, owner)
|
340
|
+
error_message = "Rquerypad error\n"
|
341
|
+
error_message << "owner.reflections:\n"
|
342
|
+
error_message << owner.reflections.inspect
|
343
|
+
error_message << '\n\nnot found by key:' << name.to_sym.to_s
|
344
|
+
raise error_message
|
345
|
+
end
|
329
346
|
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
347
|
+
def transfer_table_name(name, owner = @owner)
|
348
|
+
raise_error(name, owner) if owner.reflections[name.to_sym].nil?
|
349
|
+
owner.reflections[name.to_sym].class_name.gsub(/([\w]+::)*/, "").pluralize.underscore
|
350
|
+
end
|
334
351
|
|
335
|
-
|
336
|
-
|
337
|
-
|
352
|
+
def transfer_table_id(name, owner = @owner)
|
353
|
+
raise_error(name, owner) if owner.reflections[name.to_sym].nil?
|
354
|
+
owner.reflections[name.to_sym].class_name.gsub(/([\w]+::)*/, "").underscore + "_id"
|
355
|
+
end
|
338
356
|
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
357
|
+
def cut_end_underscore(str)
|
358
|
+
str = str.reverse.sub("_", "").reverse if str[-1, 1] == "_"
|
359
|
+
str
|
360
|
+
end
|
343
361
|
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
end
|
362
|
+
def cut_end_underscore!(str)
|
363
|
+
str.reverse!.sub!("_", "").reverse! if str[-1, 1] == "_"
|
364
|
+
end
|
365
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rquerypad
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.21
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Leon Li
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-04-15 00:00:00 +08:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|