i_dig_sql 2.0.0 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +10 -19
- data/VERSION +1 -1
- data/bin/test +38 -1
- data/i_dig_sql.gemspec +8 -4
- data/lib/i_dig_sql.rb +388 -65
- data/lib/i_dig_sql/H.rb +43 -0
- data/specs/0000-I_Dig_Sql.rb +84 -0
- data/specs/0001-new.rb +20 -0
- data/specs/0010-vars.rb +38 -0
- data/specs/0011-to_pair.rb +15 -0
- data/specs/0020-to_sql.rb +31 -0
- data/specs/0030-funcs.rb +40 -0
- data/specs/helpers.rb +51 -0
- metadata +74 -12
- data/englishy_sql.rb +0 -98
- data/specs/i_dig_sql.rb +0 -203
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5a72cee2c11ff760fcb5227b539fa976a39dfb56
|
4
|
+
data.tar.gz: a418aba79878b9361f980f137c7be1b108e3ee74
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1e7ef6053d12c991ab562da0c882bc510babae4c315e108e7bb34c67855e998106ea51ccc1f5c4384a88d9f5c0fdbaf8b2f183539d1c3a40b208b4be73431de5
|
7
|
+
data.tar.gz: 43c7bca10bbb494ab492e7ad1852ecbd992ba80b96832056bf6760b7f8c2a533023faeb8df91ab595bf30e04c38081d927367ad522f269245b1f6b5c8f113aae
|
data/README.md
CHANGED
@@ -1,29 +1,19 @@
|
|
1
1
|
# I\_Dig\_Sql
|
2
2
|
|
3
|
-
My way of managing SQL fragments using Ruby.
|
4
3
|
|
5
|
-
|
4
|
+
I'm still learning how to write decent SQL queries
|
5
|
+
in Postgresql 9.4. I'm using this to manage
|
6
|
+
sub-queries in complicated SQL queries.
|
6
7
|
|
7
|
-
You
|
8
|
-
|
8
|
+
You won't find this useful and I am too lazy/busy
|
9
|
+
to write decent documentation for something
|
10
|
+
no one but me will use for esoteric purposes.
|
11
|
+
|
12
|
+
Instead, this to for SQL + Ruby:
|
9
13
|
|
10
14
|
* [Arel](http://github.com/rails/arel).
|
11
15
|
* K'bam [https://github.com/vilnius-leopold/kbam](https://github.com/vilnius-leopold/kbam)
|
12
|
-
|
13
|
-
# History
|
14
|
-
|
15
|
-
I had trouble maintaining BIG sql queries.
|
16
|
-
|
17
|
-
I tried many things.
|
18
|
-
|
19
|
-
The best way (within my preferences)
|
20
|
-
was to use sub-queries, CTEs, avoid joins as much as possible,
|
21
|
-
and this gem to manage SQL fragments and CTEs.
|
22
|
-
|
23
|
-
Naturally, you would want to use prepared statements, compiled wat-cha-me-call-its,
|
24
|
-
functions, views, thing-ma-jig-ers, and other tools available in your RDBMS.
|
25
|
-
|
26
|
-
So this gem is for lazy, stupid people like me.
|
16
|
+
* Sequel [http://sequel.jeremyevans.net/rdoc/files/doc/querying_rdoc.html](http://sequel.jeremyevans.net/rdoc/files/doc/querying_rdoc.html)
|
27
17
|
|
28
18
|
# Usage
|
29
19
|
|
@@ -52,6 +42,7 @@ Please note that none of this is ready yet.
|
|
52
42
|
^
|
53
43
|
|
54
44
|
sql.to_sql
|
45
|
+
|
55
46
|
```
|
56
47
|
|
57
48
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
3.0.0
|
data/bin/test
CHANGED
@@ -2,9 +2,46 @@
|
|
2
2
|
# -*- bash -*-
|
3
3
|
#
|
4
4
|
#
|
5
|
+
x="$1"
|
5
6
|
set -u -e -o pipefail
|
6
7
|
|
8
|
+
if [[ "$x" == "watch" ]]; then
|
9
|
+
shift
|
7
10
|
|
8
|
-
|
11
|
+
echo ""
|
12
|
+
echo "=== Watching: $@"
|
13
|
+
|
14
|
+
echo -e "\n=== Running test:"
|
15
|
+
bin/test "$@" || echo ""
|
16
|
+
|
17
|
+
inotifywait -q -m -e close_write,close --exclude .git/ -r . | while read CHANGE
|
18
|
+
do
|
19
|
+
|
20
|
+
dir=$(echo "$CHANGE" | cut -d' ' -f 1)
|
21
|
+
op=$(echo "$CHANGE" | cut -d' ' -f 2)
|
22
|
+
file=$(echo "$CHANGE" | cut -d' ' -f 3)
|
23
|
+
path="${dir}$file"
|
24
|
+
|
25
|
+
if [[ "$op" == *CLOSE_WRITE* && $file == *.rb* ]]; then
|
26
|
+
echo -e "\n=== Running test:"
|
27
|
+
bin/test "$@" || echo ""
|
28
|
+
fi
|
29
|
+
|
30
|
+
done # === do
|
31
|
+
|
32
|
+
echo ""
|
33
|
+
exit 0
|
34
|
+
fi # === if watch
|
35
|
+
|
36
|
+
files="$(echo specs/*-$x.rb)"
|
37
|
+
if [[ -f "$files" ]]; then
|
38
|
+
shift
|
39
|
+
else
|
40
|
+
files="$(echo specs/*-*.rb)"
|
41
|
+
fi
|
42
|
+
|
43
|
+
|
44
|
+
|
45
|
+
bundle exec bacon -rpry -ri_dig_sql specs/helpers.rb $files "$@"
|
9
46
|
|
10
47
|
|
data/i_dig_sql.gemspec
CHANGED
@@ -21,8 +21,12 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
22
22
|
spec.require_paths = ["lib"]
|
23
23
|
|
24
|
-
spec.add_development_dependency "bundler"
|
25
|
-
spec.add_development_dependency "bacon"
|
26
|
-
spec.add_development_dependency "Bacon_Colored"
|
27
|
-
spec.add_development_dependency "pry"
|
24
|
+
spec.add_development_dependency "bundler" , "> 1.5"
|
25
|
+
spec.add_development_dependency "bacon" , '> 1.0'
|
26
|
+
spec.add_development_dependency "Bacon_Colored" , '> 0'
|
27
|
+
spec.add_development_dependency "pry" , '> 0'
|
28
|
+
spec.add_development_dependency "awesome_print" , '> 0'
|
29
|
+
spec.add_development_dependency "anbt-sql-formatter" , '> 0'
|
30
|
+
spec.add_development_dependency "rouge" , '> 0.0.0'
|
31
|
+
spec.add_development_dependency "unindent" , '> 0.0.0'
|
28
32
|
end
|
data/lib/i_dig_sql.rb
CHANGED
@@ -1,124 +1,447 @@
|
|
1
1
|
|
2
|
+
require "i_dig_sql/H"
|
3
|
+
|
2
4
|
class I_Dig_Sql
|
3
5
|
|
4
6
|
include Enumerable
|
7
|
+
|
5
8
|
HAS_VAR = /(\{\{|\<\<)[^\}\>]+(\}\}|\>\>)/
|
9
|
+
SELECT_FROM_REG = /SELECT.+FROM.+/
|
10
|
+
|
11
|
+
|
12
|
+
ALL_UNDERSCORE = /\A[_]+\Z/
|
13
|
+
COMBO_LEFT_RIGHT = [:left, :left, :right, :right]
|
14
|
+
COMBO_OUT_IN = [:out, :in, :out, :in]
|
6
15
|
|
7
16
|
Duplicate = Class.new RuntimeError
|
8
17
|
|
9
18
|
class << self
|
10
19
|
end # === class self ===
|
11
20
|
|
12
|
-
|
21
|
+
attr_reader :digs, :WITHS, :data
|
22
|
+
def initialize *args
|
23
|
+
@WITH = nil
|
24
|
+
@FRAGMENT = nil
|
25
|
+
@SQL = nil
|
26
|
+
@WITHS = []
|
13
27
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
28
|
+
@digs = []
|
29
|
+
@data = H.new(:allow_update)
|
30
|
+
.merge!(
|
31
|
+
:name => nil,
|
32
|
+
:raw => nil,
|
33
|
+
:vars => H.new,
|
34
|
+
:procs => H.new
|
35
|
+
)
|
18
36
|
|
19
|
-
|
20
|
-
if has_key?(name) && self[name] != val
|
21
|
-
fail ArgumentError, "Key already set: #{name.inspect}"
|
22
|
-
end
|
37
|
+
args.each { |a|
|
23
38
|
|
24
|
-
|
25
|
-
end
|
39
|
+
case a
|
26
40
|
|
27
|
-
|
28
|
-
|
29
|
-
h.each { |k,v|
|
30
|
-
self[k] = v
|
31
|
-
}
|
32
|
-
}
|
33
|
-
self
|
34
|
-
end
|
41
|
+
when Symbol
|
42
|
+
@data[:name] = a
|
35
43
|
|
36
|
-
|
44
|
+
when I_Dig_Sql
|
45
|
+
@digs << a
|
46
|
+
|
47
|
+
when String
|
48
|
+
@data.merge!(:raw=>a)
|
49
|
+
|
50
|
+
when Hash, H
|
51
|
+
if a.has_key?(:raw)
|
52
|
+
@data.merge! a
|
53
|
+
else
|
54
|
+
@data[:vars].merge! a
|
55
|
+
end
|
56
|
+
|
57
|
+
else
|
58
|
+
fail ArgumentError, "Unknown arg: #{a.inspect}"
|
59
|
+
|
60
|
+
end # === case
|
37
61
|
|
38
|
-
attr_reader :sqls, :vars
|
39
|
-
def initialize *args
|
40
|
-
@digs = args.select { |a|
|
41
|
-
a.is_a? I_Dig_Sql
|
42
62
|
}
|
43
63
|
|
44
|
-
|
45
|
-
|
64
|
+
end # === def initialize
|
65
|
+
|
66
|
+
%w{name raw vars}.each { |k|
|
67
|
+
eval <<-EOF.strip, nil, __FILE__, __LINE__
|
68
|
+
def #{k}
|
69
|
+
@data[:#{k}]
|
70
|
+
end
|
71
|
+
EOF
|
72
|
+
}
|
73
|
+
|
74
|
+
def vars!
|
75
|
+
vars = H.new.merge!(@data[:vars])
|
76
|
+
|
77
|
+
@digs.reverse.inject(vars) { |memo, dig|
|
78
|
+
if dig != self
|
79
|
+
memo.merge! dig.vars
|
80
|
+
end
|
81
|
+
memo
|
82
|
+
}
|
83
|
+
end
|
84
|
+
|
85
|
+
def has_key? name
|
86
|
+
!!(search name)
|
87
|
+
end
|
46
88
|
|
47
|
-
|
48
|
-
|
89
|
+
def search name
|
90
|
+
fail ArgumentError, "No name specified: #{name.inspect}" if !name
|
91
|
+
return self if self.name == name
|
92
|
+
found = false
|
93
|
+
if @data[:procs].has_key?(name)
|
94
|
+
return @data[:procs][name]
|
95
|
+
end
|
49
96
|
|
50
|
-
@
|
97
|
+
@digs.reverse.detect { |d|
|
98
|
+
found = if d.name == name
|
99
|
+
d
|
100
|
+
elsif d.data[:procs].has_key?(name)
|
101
|
+
d.data[:procs][name]
|
102
|
+
else
|
103
|
+
d.digs.detect { |deep|
|
104
|
+
found = deep if deep.name == name
|
105
|
+
found = deep.data[:procs][name] if deep.data[:procs].has_key?(name)
|
106
|
+
found
|
107
|
+
}
|
108
|
+
end
|
109
|
+
}
|
110
|
+
found
|
51
111
|
end
|
52
112
|
|
53
113
|
def [] name
|
54
|
-
|
114
|
+
found = search(name)
|
115
|
+
fail ArgumentError, "SQL not found for: #{name.inspect}" unless found
|
116
|
+
found
|
55
117
|
end
|
56
118
|
|
57
119
|
def []= name, val
|
58
|
-
|
120
|
+
fail ArgumentError, "Name already taken: #{name.inspect}" if has_key?(name)
|
121
|
+
|
122
|
+
case val
|
123
|
+
when String
|
124
|
+
@digs << I_Dig_Sql.new(self, name, val)
|
125
|
+
|
126
|
+
when Hash, H
|
127
|
+
case
|
128
|
+
when val[:name] == :DEFAULT
|
129
|
+
@digs << I_Dig_Sql.new(:DEFAULT, val)
|
130
|
+
when val[:raw]
|
131
|
+
@data.merge! val
|
132
|
+
else
|
133
|
+
@digs << I_Dig_Sql.new(self, name, val)
|
134
|
+
end
|
135
|
+
|
136
|
+
when I_Dig_Sql
|
137
|
+
@digs << val
|
138
|
+
|
139
|
+
when Proc
|
140
|
+
@data[:procs][name] = val
|
141
|
+
|
142
|
+
else
|
143
|
+
fail ArgumentError, "Unknown class: #{name.inspect} -> #{val.class}"
|
144
|
+
|
145
|
+
end # === case
|
59
146
|
end
|
60
147
|
|
61
148
|
def each
|
149
|
+
digs = @digs.reverse
|
150
|
+
digs.unshift self
|
62
151
|
if block_given?
|
63
|
-
|
152
|
+
digs.each { |d| yield d.name, d }
|
64
153
|
else
|
65
|
-
|
154
|
+
digs.each
|
66
155
|
end
|
67
156
|
end
|
68
157
|
|
158
|
+
|
69
159
|
def << str
|
70
|
-
@
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
end
|
76
|
-
)
|
160
|
+
(@data[:raw] ||= "") << str
|
161
|
+
end
|
162
|
+
|
163
|
+
def has_raw?
|
164
|
+
!!(@data[:raw] && !@data[:raw].strip.empty?)
|
77
165
|
end
|
78
166
|
|
79
167
|
def to_pair
|
80
|
-
[to_sql, vars]
|
168
|
+
[to_sql, vars!]
|
169
|
+
end
|
170
|
+
|
171
|
+
def to_meta *args
|
172
|
+
compile *args
|
173
|
+
end
|
174
|
+
|
175
|
+
def to_sql *args
|
176
|
+
compile(*args)[:SQL]
|
177
|
+
end
|
178
|
+
|
179
|
+
%w{ FRAGMENT SQL }.each { |k|
|
180
|
+
eval <<-EOF.strip, nil, __FILE__, __LINE__ + 1
|
181
|
+
def #{k}
|
182
|
+
return @#{k} if @SQL
|
183
|
+
to_meta[:#{k}]
|
184
|
+
end
|
185
|
+
EOF
|
186
|
+
}
|
187
|
+
|
188
|
+
private # ==========================================
|
189
|
+
|
190
|
+
def prefix_raw sym
|
191
|
+
"raw_#{sym.to_s.split('_').first}".to_sym
|
81
192
|
end
|
82
193
|
|
83
|
-
def
|
84
|
-
|
85
|
-
|
194
|
+
def prefix sym
|
195
|
+
sym.to_s.split('_').first.to_sym
|
196
|
+
end
|
197
|
+
|
198
|
+
protected(
|
199
|
+
def table_name one, two = nil
|
200
|
+
if two
|
201
|
+
k = two
|
202
|
+
link_name = one
|
203
|
+
else
|
204
|
+
k = one
|
205
|
+
link_name = nil
|
206
|
+
end
|
207
|
+
|
208
|
+
case
|
209
|
+
when [:out_ftable, :in_ftable].include?(k)
|
210
|
+
"#{real_table}_#{ meta[prefix(k)] }_#{meta[k]}"
|
211
|
+
|
212
|
+
when link? && link_name && @data[link_name][:inner_join].include?(k)
|
213
|
+
"#{self.name}_#{@data[link_name][:name]}_#{k}"
|
214
|
+
|
215
|
+
else
|
216
|
+
fail ArgumentError, "Unknown key for table name: #{k.inspect}"
|
217
|
+
end
|
218
|
+
end
|
219
|
+
) # === protected
|
220
|
+
|
221
|
+
#
|
222
|
+
# Examples:
|
223
|
+
#
|
224
|
+
# field :in, :owner_id
|
225
|
+
# field :screen_name, :screen_name
|
226
|
+
# field :in
|
227
|
+
# field :raw_in
|
228
|
+
#
|
229
|
+
protected(
|
230
|
+
def field *args
|
231
|
+
|
232
|
+
case args
|
233
|
+
when [:out], [:in]
|
234
|
+
"#{name}.#{data[args.last][:name]}"
|
235
|
+
when [:raw, :out], [:raw, :in]
|
236
|
+
"#{name}.#{self[:DEFAULT].data[args.last]}"
|
237
|
+
when [:owner_id], [:type_id]
|
238
|
+
"#{name}.#{args.first}"
|
239
|
+
else
|
240
|
+
fail ArgumentError, "Unknown args: #{args.inspect}"
|
241
|
+
end # === case
|
242
|
+
|
243
|
+
end # === def field
|
244
|
+
)
|
86
245
|
|
87
|
-
|
246
|
+
protected def compile target = nil
|
247
|
+
return(self[target].compile) if target && target != name
|
248
|
+
|
249
|
+
if !@SQL
|
250
|
+
compile_raw
|
251
|
+
end
|
252
|
+
|
253
|
+
{FRAGMENT: @FRAGMENT, SQL: @SQL, WITH: @WITH, VARS: vars!}
|
254
|
+
end # === def to_sql
|
255
|
+
|
256
|
+
def compile_raw
|
257
|
+
@data[:raw].freeze
|
258
|
+
|
259
|
+
s = @FRAGMENT = @data[:raw].dup
|
260
|
+
|
261
|
+
while s[HAS_VAR]
|
88
262
|
s.gsub!(/\{\{\s?([a-zA-Z0-9\_]+)\s?\}\}/) do |match|
|
89
263
|
key = $1.to_sym
|
90
|
-
|
264
|
+
@WITHS << key
|
91
265
|
key
|
92
266
|
end
|
93
267
|
|
94
268
|
s.gsub!(/\<\<\s?([a-zA-Z0-9\_\-\ \*]+)\s?\>\>/) do |match|
|
95
269
|
tokens = $1.split
|
96
|
-
key = tokens.pop.to_sym
|
97
|
-
field = tokens.empty? ? nil : tokens.join(' ')
|
98
270
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
271
|
+
key = tokens.last.to_sym
|
272
|
+
|
273
|
+
if has_key?(key)
|
274
|
+
|
275
|
+
tokens.pop
|
276
|
+
target = self[key]
|
277
|
+
|
278
|
+
if target.is_a?(Proc)
|
279
|
+
target.call self, *tokens
|
280
|
+
else
|
281
|
+
field = tokens.empty? ? nil : tokens.join(' ')
|
282
|
+
|
283
|
+
if field
|
284
|
+
@WITHS << key
|
285
|
+
tokens.pop
|
286
|
+
"SELECT #{field} FROM #{key}"
|
287
|
+
else
|
288
|
+
target.to_sql
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
elsif has_key?(tokens.first.to_sym)
|
293
|
+
self[tokens.shift.to_sym].call self, *tokens
|
294
|
+
|
103
295
|
else
|
104
|
-
|
105
|
-
|
296
|
+
fail ArgumentError, "Not found: #{$1}"
|
297
|
+
|
298
|
+
end # === if has_key?
|
106
299
|
end
|
300
|
+
end # === while s HAS_VAR
|
301
|
+
|
302
|
+
@WITH = if @WITHS.empty?
|
303
|
+
""
|
304
|
+
else
|
305
|
+
%^WITH\n #{WITH()}\n\n^
|
306
|
+
end
|
307
|
+
|
308
|
+
@SQL = (@WITH + @FRAGMENT).strip
|
309
|
+
end # === fragments_to_raw
|
310
|
+
|
311
|
+
def WITH
|
312
|
+
withs = @WITHS.dup
|
313
|
+
maps = []
|
314
|
+
done = {}
|
315
|
+
while name = withs.shift
|
316
|
+
next if done[name]
|
317
|
+
if name == :DEFAULT || !self.has_key?(name)
|
318
|
+
done[name] = true
|
319
|
+
next
|
320
|
+
end
|
321
|
+
|
322
|
+
fragment = self[name].FRAGMENT
|
323
|
+
fragment.gsub!(/^/, " ") if ENV['IS_DEV']
|
324
|
+
maps << "#{name} AS (\n#{fragment}\n )"
|
325
|
+
withs.concat self[name].WITHS
|
326
|
+
done[name] = true
|
327
|
+
end # === while name
|
328
|
+
|
329
|
+
maps.join ",\n "
|
330
|
+
end
|
331
|
+
|
332
|
+
def WHERE
|
333
|
+
wheres = @data[:WHERE].dup
|
334
|
+
|
335
|
+
if link? && name != :block
|
336
|
+
wheres << "#{field :type_id} = :#{name.to_s.upcase}_TYPE_ID"
|
337
|
+
|
338
|
+
pattern = [ data[:out][:inner_join], data[:in][:inner_join] ]
|
339
|
+
left, mid = data[:out][:inner_join]
|
340
|
+
right, _ = *data[:in][:inner_join]
|
341
|
+
|
342
|
+
|
343
|
+
case
|
344
|
+
when [[:screen_name], [:screen_name]], [[:screen_name, :computer],[:screen_name]]
|
345
|
+
# do nothing
|
346
|
+
else
|
347
|
+
fail "Programmer Error: Permissions not implemented for: #{pattern.inspect}"
|
348
|
+
end # === case
|
349
|
+
|
350
|
+
if left == :screen_name && right == :screen_name
|
351
|
+
default = self[:DEFAULT]
|
352
|
+
block = self[:block]
|
353
|
+
blocked = block.table_name(:out, :screen_name)
|
354
|
+
victim = block.table_name(:in, :screen_name)
|
355
|
+
f_in = table_name :in, :screen_name
|
356
|
+
f_out = table_name :out, :screen_name
|
357
|
+
|
358
|
+
wheres << %^
|
359
|
+
NOT EXISTS (
|
360
|
+
SELECT 1
|
361
|
+
FROM #{block.real_table} AS block
|
362
|
+
WHERE
|
363
|
+
(
|
364
|
+
block.type_id = :BLOCK_SCREEN_TYPE_ID
|
365
|
+
AND (
|
366
|
+
(
|
367
|
+
#{f_out}.owner_id = #{block.field :out}
|
368
|
+
AND
|
369
|
+
#{f_in}.owner_id = #{victim}.owner_id
|
370
|
+
)
|
371
|
+
OR
|
372
|
+
(
|
373
|
+
#{field :raw, :in} = #{block.field :out}
|
374
|
+
AND
|
375
|
+
#{blocked}.owner_id = #{victim}.owner_id
|
376
|
+
)
|
377
|
+
)
|
378
|
+
)
|
379
|
+
OR
|
380
|
+
(
|
381
|
+
block.type_id = :BLOCK_OWNER_TYPE_ID
|
382
|
+
AND (
|
383
|
+
(
|
384
|
+
#{f_out}.owner_id = #{blocked}.owner_id
|
385
|
+
AND
|
386
|
+
#{f_in}.owner_id = #{victim}.owner_id
|
387
|
+
)
|
388
|
+
OR
|
389
|
+
(
|
390
|
+
#{f_in}.owner_id = #{blocked}.owner_id
|
391
|
+
AND
|
392
|
+
#{f_out}.owner_id = #{victim}.owner_id
|
393
|
+
)
|
394
|
+
) -- AND
|
395
|
+
)
|
396
|
+
) -- NOT EXISTS
|
397
|
+
^
|
398
|
+
end # === if :screen_name, :screen_name
|
399
|
+
|
400
|
+
if mid == :computer
|
401
|
+
asql(wheres.last)
|
402
|
+
fail "COMPUTER not ready"
|
403
|
+
end
|
404
|
+
|
405
|
+
end # === if link?
|
406
|
+
|
407
|
+
if @data.has_key?(:OF)
|
408
|
+
table = self[@data[:FROM].first]
|
409
|
+
wheres << "#{table.field(:out)} = #{@data[:OF].first}"
|
107
410
|
end
|
108
411
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
412
|
+
if false && @data[:NOT_EXISTS]
|
413
|
+
block = self[meta[:not_exists]]
|
414
|
+
w = ""
|
415
|
+
w << %^ NOT EXISTS (\n^
|
416
|
+
w << %^ SELECT 1\n^
|
417
|
+
w << %^ FROM #{meta[:not_exists]}\n^
|
418
|
+
w << %^ WHERE\n^
|
419
|
+
|
420
|
+
conds = []
|
421
|
+
block[:where].each { |block_meta|
|
422
|
+
type_id = block_meta.first
|
423
|
+
c = ""
|
424
|
+
c << %^ (\n^
|
425
|
+
c << " #{field meta, block_meta[1][1], block_meta[1][2]} = #{field block, block_meta[2][1], block_meta[2][2]}\n"
|
426
|
+
c << " AND\n"
|
427
|
+
c << " #{meta[:not_exists]}.type_id = :#{type_id}_TYPE_ID\n"
|
428
|
+
c << " AND\n"
|
429
|
+
c << " #{field meta, block_meta[3][1], block_meta[3][2]} = #{field block, block_meta[4][1], block_meta[4][2]}\n"
|
430
|
+
c << %^ )\n^
|
431
|
+
conds << c
|
432
|
+
}
|
433
|
+
|
434
|
+
w << conds.join(" OR\n")
|
435
|
+
sql[:WHERE] << w
|
436
|
+
end
|
437
|
+
|
438
|
+
|
439
|
+
return nil if wheres.empty?
|
440
|
+
wheres.join " AND "
|
120
441
|
end
|
121
442
|
|
443
|
+
# === END: Rendering DSL ==========================================
|
444
|
+
|
122
445
|
end # === class I_Dig_Sql ===
|
123
446
|
|
124
447
|
|