sqlstmt 0.1.28 → 0.2.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.
- checksums.yaml +4 -4
- data/lib/sqlstmt/error.rb +1 -5
- data/lib/sqlstmt/sqlstmt.rb +343 -0
- data/lib/sqlstmt.rb +1 -4
- data/test/delete_test.rb +14 -0
- data/test/helper.rb +2 -0
- data/test/{insert_select.dt.rb → insert_select_test.rb} +15 -19
- data/test/select_test.rb +42 -0
- data/test/{to_sql.dt.rb → to_sql_test.rb} +2 -7
- data/test/{update.dt.rb → update_test.rb} +17 -21
- metadata +16 -49
- data/lib/sqlstmt/delete.rb +0 -35
- data/lib/sqlstmt/from_query.rb +0 -52
- data/lib/sqlstmt/insert_select.rb +0 -48
- data/lib/sqlstmt/insert_values.rb +0 -37
- data/lib/sqlstmt/query.rb +0 -110
- data/lib/sqlstmt/select.rb +0 -48
- data/lib/sqlstmt/update.rb +0 -36
- data/lib/sqlstmt/value_util.rb +0 -14
- data/test/delete.dt.rb +0 -18
- data/test/select.dt.rb +0 -53
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2b7746931f2110ac0ed453789e2374c05b4233ee
|
4
|
+
data.tar.gz: 46c5f8f2a3baa4023d08541c47eb7f45a7fd9cb1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0d5a0ad3df986f73d4729334bab6353b3b77372f1bb78d65f2a5ff5ae626cc5a3a616f5be7ebe32887ea059da6452dbd5e8c1c9a9cf37a71df88ac77f5b9a08d
|
7
|
+
data.tar.gz: 840fdd50d95167f638d5fbb78e5fedeb72d42910a45781b3a50af50feb968121b790d9c7a954de653ee3d408deda9782cd18ac49e80d5fef1659dce94082dfbe
|
data/lib/sqlstmt/error.rb
CHANGED
@@ -0,0 +1,343 @@
|
|
1
|
+
require 'sqlstmt/error'
|
2
|
+
require 'sqlstmt/to_sql'
|
3
|
+
|
4
|
+
class SqlStmt
|
5
|
+
attr_reader :fields, :tables, :joins, :wheres
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@stmt_type = nil
|
9
|
+
@tables = []
|
10
|
+
@joins = []
|
11
|
+
@wheres = []
|
12
|
+
@where_behavior = :require
|
13
|
+
@fields = []
|
14
|
+
@values = []
|
15
|
+
@group_by = nil
|
16
|
+
@order_by = nil
|
17
|
+
@limit = nil
|
18
|
+
@having = []
|
19
|
+
@into_table = nil
|
20
|
+
@rows = []
|
21
|
+
@tables_to_delete = []
|
22
|
+
@distinct = nil
|
23
|
+
@straight_join = nil
|
24
|
+
@replace = nil
|
25
|
+
@ignore = ''
|
26
|
+
@outfile = ''
|
27
|
+
end
|
28
|
+
|
29
|
+
def initialize_copy(orig)
|
30
|
+
super
|
31
|
+
@tables = @tables.dup
|
32
|
+
@joins = @joins.dup
|
33
|
+
@wheres = @wheres.dup
|
34
|
+
@fields = @fields.dup
|
35
|
+
@values = @values.dup
|
36
|
+
@having = @having.dup
|
37
|
+
@rows = @rows.dup
|
38
|
+
end
|
39
|
+
|
40
|
+
###### pick statement type
|
41
|
+
|
42
|
+
def select
|
43
|
+
ensure_no_statement_type
|
44
|
+
@stmt_type = 'select'
|
45
|
+
return self
|
46
|
+
end
|
47
|
+
|
48
|
+
def update
|
49
|
+
ensure_no_statement_type
|
50
|
+
@stmt_type = 'update'
|
51
|
+
return self
|
52
|
+
end
|
53
|
+
|
54
|
+
def insert
|
55
|
+
ensure_no_statement_type
|
56
|
+
@stmt_type = 'insert'
|
57
|
+
return self
|
58
|
+
end
|
59
|
+
|
60
|
+
def delete(*tables)
|
61
|
+
ensure_no_statement_type
|
62
|
+
@stmt_type = 'delete'
|
63
|
+
@tables_to_delete = tables
|
64
|
+
return self
|
65
|
+
end
|
66
|
+
|
67
|
+
###### common operations
|
68
|
+
|
69
|
+
def table(table)
|
70
|
+
@tables << table
|
71
|
+
return self
|
72
|
+
end
|
73
|
+
|
74
|
+
def join(table, *exprs)
|
75
|
+
return add_join('JOIN', table, exprs)
|
76
|
+
end
|
77
|
+
|
78
|
+
def left_join(table, *exprs)
|
79
|
+
return add_join('LEFT JOIN', table, exprs)
|
80
|
+
end
|
81
|
+
|
82
|
+
def where(*expr)
|
83
|
+
@wheres.concat(expr)
|
84
|
+
return self
|
85
|
+
end
|
86
|
+
|
87
|
+
def no_where
|
88
|
+
@where_behavior = :exclude
|
89
|
+
return self
|
90
|
+
end
|
91
|
+
|
92
|
+
def optional_where
|
93
|
+
@where_behavior = :optional
|
94
|
+
return self
|
95
|
+
end
|
96
|
+
|
97
|
+
def get(*exprs)
|
98
|
+
@fields.concat(exprs)
|
99
|
+
return self
|
100
|
+
end
|
101
|
+
|
102
|
+
def set(field, value)
|
103
|
+
raise "trying to include field #{field} again" if @fields.include?(field)
|
104
|
+
@fields << field
|
105
|
+
value = value.is_a?(String) ? value : value.to_sql
|
106
|
+
@values << value
|
107
|
+
return self
|
108
|
+
end
|
109
|
+
|
110
|
+
def setq(field, value)
|
111
|
+
return set(field, value.to_sql)
|
112
|
+
end
|
113
|
+
|
114
|
+
def group_by(expr)
|
115
|
+
@group_by = expr
|
116
|
+
return self
|
117
|
+
end
|
118
|
+
|
119
|
+
def order_by(expr)
|
120
|
+
@order_by = expr
|
121
|
+
return self
|
122
|
+
end
|
123
|
+
|
124
|
+
def limit(clause)
|
125
|
+
@limit = clause
|
126
|
+
return self
|
127
|
+
end
|
128
|
+
|
129
|
+
def having(*expr)
|
130
|
+
@having.concat(expr)
|
131
|
+
return self
|
132
|
+
end
|
133
|
+
|
134
|
+
# used with INSERT statements only
|
135
|
+
def into(into_table)
|
136
|
+
@into_table = into_table
|
137
|
+
return self
|
138
|
+
end
|
139
|
+
|
140
|
+
# used with INSERT VALUES statements only
|
141
|
+
def add_row(row)
|
142
|
+
@rows << row
|
143
|
+
end
|
144
|
+
|
145
|
+
def to_s
|
146
|
+
verify_minimum_requirements
|
147
|
+
return build_stmt
|
148
|
+
end
|
149
|
+
alias_method :to_sql, :to_s
|
150
|
+
|
151
|
+
###### less commonly used methods
|
152
|
+
|
153
|
+
def distinct
|
154
|
+
@distinct = true
|
155
|
+
return self
|
156
|
+
end
|
157
|
+
|
158
|
+
def straight_join
|
159
|
+
@straight_join = true
|
160
|
+
return self
|
161
|
+
end
|
162
|
+
|
163
|
+
def replace
|
164
|
+
@replace = true
|
165
|
+
return self
|
166
|
+
end
|
167
|
+
|
168
|
+
def ignore
|
169
|
+
@ignore = 'IGNORE '
|
170
|
+
return self
|
171
|
+
end
|
172
|
+
|
173
|
+
def outfile(str)
|
174
|
+
@outfile = " INTO OUTFILE #{str}"
|
175
|
+
return self
|
176
|
+
end
|
177
|
+
|
178
|
+
###### methods to analyze what the statement contains
|
179
|
+
def includes_table?(table_to_find)
|
180
|
+
retval = @tables.find { |table| table_names_match?(table, table_to_find) }
|
181
|
+
retval ||= @joins.find { |_, table, _| table_names_match?(table, table_to_find) }
|
182
|
+
return retval
|
183
|
+
end
|
184
|
+
|
185
|
+
###### transition only mechanisms
|
186
|
+
def field(*args)
|
187
|
+
if ['update','insert'].include?(@stmt_type)
|
188
|
+
set(args[0], args[1])
|
189
|
+
else
|
190
|
+
get(*args)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
alias_method :fieldq, :setq
|
194
|
+
|
195
|
+
def optional_join(table, expr)
|
196
|
+
unless includes_table?(table)
|
197
|
+
join(table, expr)
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
private
|
202
|
+
def ensure_no_statement_type
|
203
|
+
if @stmt_type
|
204
|
+
raise "statement type already set to #{@stmt_type}"
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
def add_join(keyword, table, exprs)
|
209
|
+
@joins << [keyword, table, "ON #{exprs.join(' AND ')}"]
|
210
|
+
return self
|
211
|
+
end
|
212
|
+
|
213
|
+
def table_names_match?(fullstr, tofind)
|
214
|
+
if tofind.index(' ') || !fullstr.index(' ')
|
215
|
+
return fullstr == tofind
|
216
|
+
end
|
217
|
+
orig_name, _, tblas = fullstr.partition(' ')
|
218
|
+
return (orig_name == tofind) || (tblas == tofind)
|
219
|
+
end
|
220
|
+
|
221
|
+
###### the remainder of the methods are for verifying and building the completed statement string
|
222
|
+
|
223
|
+
def verify_minimum_requirements
|
224
|
+
if !@stmt_type
|
225
|
+
raise SqlStmtError, "unable to build sql - must specify statement type"
|
226
|
+
elsif (@where_behavior == :require) && @wheres.empty?
|
227
|
+
raise SqlStmtError, "unable to build sql - must call :where, :no_where, or :optional_where"
|
228
|
+
elsif (@where_behavior == :exclude) && !@wheres.empty?
|
229
|
+
raise SqlStmtError, "unable to build sql - :where and :no_where must not both be called, consider :optional_where instead"
|
230
|
+
end
|
231
|
+
|
232
|
+
if ['select','insert','delete'].include?(@stmt_type)
|
233
|
+
raise SqlStmtError, "unable to build sql - must call :table or :join (or one if it's variants)" if @tables.empty? && @joins.empty?
|
234
|
+
raise SqlStmtError, "unable to build sql - must call :table if using :join (or one if it's variants)" if @tables.empty? && !@joins.empty?
|
235
|
+
end
|
236
|
+
|
237
|
+
if @stmt_type == 'select'
|
238
|
+
raise SqlStmtError, "unable to build sql - must call :field" if @fields.empty?
|
239
|
+
end
|
240
|
+
|
241
|
+
if @stmt_type == 'insert_values'
|
242
|
+
raise SqlStmtError, "unable to build sql - must call :into" if @into_table.nil?
|
243
|
+
raise SqlStmtError, "unable to build sql - must call :field or :fieldq" if @fields.empty?
|
244
|
+
end
|
245
|
+
|
246
|
+
if @stmt_type == 'insert_select'
|
247
|
+
raise SqlStmtError, "unable to build sql - must call :into" if @into_table.nil?
|
248
|
+
raise SqlStmtError, "unable to build sql - must call :field or :fieldq" if @fields.empty?
|
249
|
+
end
|
250
|
+
|
251
|
+
if @stmt_type == 'update'
|
252
|
+
raise SqlStmtError, "unable to build sql - must call :table" if @tables.empty?
|
253
|
+
raise SqlStmtError, "unable to build sql - must call :field or :fieldq" if @fields.empty?
|
254
|
+
end
|
255
|
+
|
256
|
+
if @stmt_type == 'delete'
|
257
|
+
combined_table_count = @tables.size + @joins.size
|
258
|
+
raise SqlStmtError, "unable to build sql - must call :from when including multiple tables" if @tables_to_delete.empty? && (combined_table_count > 1)
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
def build_stmt
|
263
|
+
method_name = "build_stmt_#{@stmt_type}"
|
264
|
+
return send(method_name)
|
265
|
+
end
|
266
|
+
|
267
|
+
def build_stmt_select
|
268
|
+
straight_join_str = @straight_join ? 'STRAIGHT_JOIN ' : ''
|
269
|
+
distinct_str = @distinct ? 'DISTINCT ' : ''
|
270
|
+
select_str = @fields.join(',')
|
271
|
+
return "SELECT #{straight_join_str}#{distinct_str}#{select_str}#{build_from_clause}#{@outfile}"
|
272
|
+
end
|
273
|
+
|
274
|
+
def build_stmt_update
|
275
|
+
limit_clause = simple_clause('LIMIT', @limit)
|
276
|
+
return "UPDATE #{build_table_list}#{build_join_clause} SET #{build_set_clause}#{build_where_clause}#{limit_clause}"
|
277
|
+
end
|
278
|
+
|
279
|
+
def build_stmt_insert
|
280
|
+
if !@fields.empty? && !@rows.empty?
|
281
|
+
raise "unable to use INSERT SELECT and INSERT VALUES together, may only call :set or :add_row, but not both"
|
282
|
+
end
|
283
|
+
|
284
|
+
keyword = @replace ? 'REPLACE' : 'INSERT'
|
285
|
+
field_list = @fields.join(',')
|
286
|
+
value_list = @values.join(',')
|
287
|
+
start_str = "#{keyword} #{@ignore}INTO #{@into_table} (#{field_list}) "
|
288
|
+
|
289
|
+
if @rows.empty?
|
290
|
+
distinct_str = @distinct ? 'DISTINCT ' : ''
|
291
|
+
return "#{start_str}SELECT #{distinct_str}#{value_list}#{build_from_clause}"
|
292
|
+
else
|
293
|
+
raise "DISTINCT not supported when inserting values" if @distinct
|
294
|
+
return "#{start_str}VALUES (#{value_list})"
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
def build_stmt_delete
|
299
|
+
if @tables_to_delete.empty?
|
300
|
+
table_clause = ''
|
301
|
+
else
|
302
|
+
table_clause = ' ' + @tables_to_delete.join(',')
|
303
|
+
end
|
304
|
+
return "DELETE#{table_clause}#{build_from_clause}"
|
305
|
+
end
|
306
|
+
|
307
|
+
def build_from_clause
|
308
|
+
join_clause = build_join_clause
|
309
|
+
group_clause = simple_clause('GROUP BY', @group_by)
|
310
|
+
order_clause = simple_clause('ORDER BY', @order_by)
|
311
|
+
limit_clause = simple_clause('LIMIT', @limit)
|
312
|
+
having_clause = @having.empty? ? '' : " HAVING #{@having.join(' AND ')}"
|
313
|
+
return " FROM #{build_table_list}#{join_clause}#{build_where_clause}#{group_clause}#{having_clause}#{order_clause}#{limit_clause}"
|
314
|
+
end
|
315
|
+
|
316
|
+
def build_set_clause
|
317
|
+
set_exprs = []
|
318
|
+
@fields.each_with_index do |field, index|
|
319
|
+
set_exprs << "#{field} = #{@values[index]}"
|
320
|
+
end
|
321
|
+
return set_exprs.join(', ')
|
322
|
+
end
|
323
|
+
|
324
|
+
def build_table_list
|
325
|
+
return @tables.join(',')
|
326
|
+
end
|
327
|
+
|
328
|
+
def simple_clause(keywords, value)
|
329
|
+
return value ? " #{keywords} #{value}" : ''
|
330
|
+
end
|
331
|
+
|
332
|
+
def build_join_clause
|
333
|
+
if @joins.empty?
|
334
|
+
return ''
|
335
|
+
else
|
336
|
+
return ' ' + @joins.map {|ary| ary.join(' ')}.uniq.join(' ')
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
def build_where_clause
|
341
|
+
return @wheres.empty? ? '' : " WHERE #{@wheres.join(' AND ')}"
|
342
|
+
end
|
343
|
+
end
|
data/lib/sqlstmt.rb
CHANGED
data/test/delete_test.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require_relative 'helper'
|
2
|
+
|
3
|
+
class TestDelete < Minitest::Test
|
4
|
+
def test_minimum_requirements
|
5
|
+
assert_raises(SqlStmtError) { SqlStmt.new.delete.table('target').to_s }
|
6
|
+
end
|
7
|
+
|
8
|
+
def test_simple
|
9
|
+
assert_equal('DELETE t FROM target t,other_table o', SqlStmt.new.delete('t').table('target t').table('other_table o').no_where.to_s)
|
10
|
+
assert_equal('DELETE t,o FROM t JOIN o ON t.id=o.id', SqlStmt.new.delete('t', 'o').table('t').join('o','t.id=o.id').no_where.to_s)
|
11
|
+
assert_equal('DELETE FROM target', SqlStmt.new.delete.table('target').no_where.to_s)
|
12
|
+
assert_equal('DELETE FROM target WHERE target_id = 1', SqlStmt.new.delete.table('target').where('target_id = 1').to_s)
|
13
|
+
end
|
14
|
+
end
|
data/test/helper.rb
ADDED
@@ -1,31 +1,29 @@
|
|
1
|
-
|
1
|
+
require_relative 'helper'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
class TestInsertSelect < DohTest::TestGroup
|
3
|
+
class TestInsertSelect < Minitest::Test
|
6
4
|
def test_minimum_requirements
|
7
|
-
assert_raises(
|
8
|
-
assert_raises(
|
9
|
-
assert_raises(
|
5
|
+
assert_raises(SqlStmtError) { SqlStmt.new.insert.into('target').to_s }
|
6
|
+
assert_raises(SqlStmtError) { SqlStmt.new.insert.into('target').no_where.to_s }
|
7
|
+
assert_raises(SqlStmtError) { SqlStmt.new.insert.into('target').no_where.set('blah', 'blee').to_s }
|
10
8
|
end
|
11
9
|
|
12
10
|
def test_simple
|
13
|
-
assert_equal('INSERT INTO target (blah) SELECT blee FROM source',
|
14
|
-
assert_equal('INSERT INTO target (blah) SELECT blee FROM source WHERE source_id = 1',
|
11
|
+
assert_equal('INSERT INTO target (blah) SELECT blee FROM source', SqlStmt.new.insert.into('target').table('source').set('blah', 'blee').no_where.to_s)
|
12
|
+
assert_equal('INSERT INTO target (blah) SELECT blee FROM source WHERE source_id = 1', SqlStmt.new.insert.into('target').table('source').set('blah', 'blee').where('source_id = 1').to_s)
|
15
13
|
end
|
16
14
|
|
17
15
|
def test_dup
|
18
|
-
shared_builder = SqlStmt
|
16
|
+
shared_builder = SqlStmt.new.insert.into('target')
|
19
17
|
first_builder = shared_builder
|
20
18
|
other_builder = shared_builder.dup
|
21
19
|
|
22
20
|
first_builder.where('status="bad"')
|
23
|
-
first_builder.
|
21
|
+
first_builder.set('created_at', 'NOW()')
|
24
22
|
first_builder.table('some_tbl s')
|
25
23
|
|
26
24
|
other_builder.no_where
|
27
|
-
other_builder.
|
28
|
-
other_builder.
|
25
|
+
other_builder.set('info', 'o.info')
|
26
|
+
other_builder.set('created_at', 'then')
|
29
27
|
other_builder.table('other_tbl o')
|
30
28
|
|
31
29
|
assert_equal('INSERT INTO target (created_at) SELECT NOW() FROM some_tbl s WHERE status="bad"', first_builder.to_s)
|
@@ -33,9 +31,9 @@ class TestInsertSelect < DohTest::TestGroup
|
|
33
31
|
end
|
34
32
|
|
35
33
|
def test_complex
|
36
|
-
shared_builder = SqlStmt
|
34
|
+
shared_builder = SqlStmt.new.insert.into('target')
|
37
35
|
shared_builder.table('shared_tbl')
|
38
|
-
shared_builder.
|
36
|
+
shared_builder.set('created_at', 'NOW()').set('duration', 5).setq('is_bad', 'b')
|
39
37
|
|
40
38
|
first_builder = shared_builder
|
41
39
|
other_builder = shared_builder.dup
|
@@ -43,13 +41,11 @@ class TestInsertSelect < DohTest::TestGroup
|
|
43
41
|
first_builder.where("status='bad'")
|
44
42
|
|
45
43
|
other_builder.table('other_tbl o')
|
46
|
-
other_builder.
|
47
|
-
other_builder.
|
44
|
+
other_builder.set('info', 'o.info')
|
45
|
+
other_builder.set('data', 'o.data')
|
48
46
|
other_builder.where('s.id=o.shared_id', "status='good'")
|
49
47
|
|
50
48
|
assert_equal("INSERT INTO target (created_at,duration,is_bad) SELECT NOW(),5,'b' FROM shared_tbl WHERE status='bad'", first_builder.to_s)
|
51
49
|
assert_equal("INSERT INTO target (created_at,duration,is_bad,info,data) SELECT NOW(),5,'b',o.info,o.data FROM shared_tbl,other_tbl o WHERE s.id=o.shared_id AND status='good'", other_builder.to_s)
|
52
50
|
end
|
53
51
|
end
|
54
|
-
|
55
|
-
end
|
data/test/select_test.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require_relative 'helper'
|
2
|
+
|
3
|
+
class TestSelect < Minitest::Test
|
4
|
+
def test_includes_table
|
5
|
+
sqlb = SqlStmt.new.select.table('target t')
|
6
|
+
assert(sqlb.includes_table?('target'))
|
7
|
+
assert(sqlb.includes_table?('t'))
|
8
|
+
assert(!sqlb.includes_table?('blah'))
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_minimum_requirements
|
12
|
+
assert_raises(SqlStmtError) { SqlStmt.new.select.table('target').to_s }
|
13
|
+
assert_raises(SqlStmtError) { SqlStmt.new.select.table('target').no_where.to_s }
|
14
|
+
assert_raises(SqlStmtError) { SqlStmt.new.select.table('target').optional_where.to_s }
|
15
|
+
assert_equal('SELECT blah FROM target', SqlStmt.new.select.table('target').optional_where.get('blah').to_sql)
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_stuff
|
19
|
+
assert_equal('SELECT blah FROM source', SqlStmt.new.select.table('source').get('blah').no_where.to_s)
|
20
|
+
assert_equal('SELECT DISTINCT blah FROM source', SqlStmt.new.select.table('source').get('blah').no_where.distinct.to_s)
|
21
|
+
assert_equal('SELECT blah FROM source WHERE source_id = 1', SqlStmt.new.select.table('source').get('blah').where('source_id = 1').to_s)
|
22
|
+
assert_equal('SELECT blah FROM source s', SqlStmt.new.select.table('source s').get('blah').no_where.to_s)
|
23
|
+
assert_equal('SELECT blah FROM source s JOIN other o ON s.blah_id = o.blah_id', SqlStmt.new.select.table('source s').join('other o', 's.blah_id = o.blah_id').get('blah').no_where.to_s)
|
24
|
+
assert_equal('SELECT blah FROM source s LEFT JOIN other o ON s.blah_id = o.blah_id', SqlStmt.new.select.table('source s').left_join('other o', 's.blah_id = o.blah_id').get('blah').no_where.to_s)
|
25
|
+
assert_equal('SELECT blah,blee FROM source', SqlStmt.new.select.table('source').get('blah','blee').no_where.to_s)
|
26
|
+
assert_equal('SELECT blah FROM source HAVING blee > 0', SqlStmt.new.select.table('source').get('blah').no_where.having('blee > 0').to_s)
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_duplicate_joins
|
30
|
+
sqlb = SqlStmt.new.select.table('source s').get('frog').no_where
|
31
|
+
4.times { sqlb.join('other o', 's.blah_id = o.blah_id') }
|
32
|
+
assert_equal('SELECT frog FROM source s JOIN other o ON s.blah_id = o.blah_id', sqlb.to_s)
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_join_with_multiple_conditions
|
36
|
+
%i(join left_join).each do |method|
|
37
|
+
sqlb = SqlStmt.new.select.table('source s').get('frog').no_where.send(method, 'other o', 'z.blee_id = o.blee_id', 'z.other_field = o.other_field')
|
38
|
+
method_sql = method.to_s.upcase.sub('_', ' ')
|
39
|
+
assert_equal("SELECT frog FROM source s #{method_sql} other o ON z.blee_id = o.blee_id AND z.other_field = o.other_field", sqlb.to_s)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -1,8 +1,6 @@
|
|
1
|
-
|
1
|
+
require_relative 'helper'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
class Test_to_sql < DohTest::TestGroup
|
3
|
+
class Test_to_sql < Minitest::Test
|
6
4
|
def test_stuff
|
7
5
|
assert_equal("'blah'", 'blah'.to_sql)
|
8
6
|
assert_equal('NULL', nil.to_sql)
|
@@ -15,6 +13,3 @@ class Test_to_sql < DohTest::TestGroup
|
|
15
13
|
assert_equal("('a','b','c')", ['a', 'b', 'c'].to_sql)
|
16
14
|
end
|
17
15
|
end
|
18
|
-
|
19
|
-
end
|
20
|
-
|
@@ -1,38 +1,36 @@
|
|
1
|
-
|
1
|
+
require_relative 'helper'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
class TestUpdate < DohTest::TestGroup
|
3
|
+
class TestUpdate < Minitest::Test
|
6
4
|
def test_minimum_requirements
|
7
|
-
assert_raises(
|
8
|
-
assert_raises(
|
5
|
+
assert_raises(SqlStmtError) { SqlStmt.new.update.table('target').to_s }
|
6
|
+
assert_raises(SqlStmtError) { SqlStmt.new.update.table('target').no_where.to_s }
|
9
7
|
end
|
10
8
|
|
11
9
|
def test_simple
|
12
|
-
assert_equal('UPDATE target SET blah = blee',
|
13
|
-
assert_equal('UPDATE target SET blah = blee LIMIT 3',
|
14
|
-
assert_equal('UPDATE target SET blah = blee WHERE target_id = 1',
|
10
|
+
assert_equal('UPDATE target SET blah = blee', SqlStmt.new.update.table('target').set('blah', 'blee').no_where.to_s)
|
11
|
+
assert_equal('UPDATE target SET blah = blee LIMIT 3', SqlStmt.new.update.table('target').set('blah', 'blee').no_where.limit(3).to_s)
|
12
|
+
assert_equal('UPDATE target SET blah = blee WHERE target_id = 1', SqlStmt.new.update.table('target').set('blah', 'blee').where('target_id = 1').to_s)
|
15
13
|
end
|
16
14
|
|
17
15
|
def test_join
|
18
|
-
builder = SqlStmt
|
19
|
-
builder.
|
16
|
+
builder = SqlStmt.new.update.table('main m').join('other o', 'm.main_id = o.main_id')
|
17
|
+
builder.set('blah', 3)
|
20
18
|
builder.no_where
|
21
19
|
assert_equal('UPDATE main m JOIN other o ON m.main_id = o.main_id SET blah = 3', builder.to_s)
|
22
20
|
end
|
23
21
|
|
24
22
|
def test_dup
|
25
|
-
shared_builder = SqlStmt
|
23
|
+
shared_builder = SqlStmt.new.update.table('target')
|
26
24
|
first_builder = shared_builder
|
27
25
|
other_builder = shared_builder.dup
|
28
26
|
|
29
27
|
first_builder.where('status="bad"')
|
30
|
-
first_builder.
|
28
|
+
first_builder.set('created_at', 'NOW()')
|
31
29
|
first_builder.table('some_tbl s')
|
32
30
|
|
33
31
|
other_builder.no_where
|
34
|
-
other_builder.
|
35
|
-
other_builder.
|
32
|
+
other_builder.set('info', 'o.info')
|
33
|
+
other_builder.set('created_at', 'then')
|
36
34
|
other_builder.table('other_tbl o')
|
37
35
|
|
38
36
|
assert_equal('UPDATE target,some_tbl s SET created_at = NOW() WHERE status="bad"', first_builder.to_s)
|
@@ -40,9 +38,9 @@ class TestUpdate < DohTest::TestGroup
|
|
40
38
|
end
|
41
39
|
|
42
40
|
def test_complex
|
43
|
-
shared_builder = SqlStmt
|
41
|
+
shared_builder = SqlStmt.new.update.table('target')
|
44
42
|
shared_builder.table('shared_tbl')
|
45
|
-
shared_builder.
|
43
|
+
shared_builder.set('created_at', 'NOW()').set('duration', 5).set('is_bad', 1)
|
46
44
|
|
47
45
|
first_builder = shared_builder
|
48
46
|
other_builder = shared_builder.dup
|
@@ -50,8 +48,8 @@ class TestUpdate < DohTest::TestGroup
|
|
50
48
|
first_builder.where('status="bad"')
|
51
49
|
|
52
50
|
other_builder.table('other_tbl o')
|
53
|
-
other_builder.
|
54
|
-
other_builder.
|
51
|
+
other_builder.set('info', 'o.info')
|
52
|
+
other_builder.set('data', 'o.data')
|
55
53
|
other_builder.where('s.id=o.shared_id')
|
56
54
|
other_builder.where('status="good"')
|
57
55
|
|
@@ -59,5 +57,3 @@ class TestUpdate < DohTest::TestGroup
|
|
59
57
|
assert_equal('UPDATE target,shared_tbl,other_tbl o SET created_at = NOW(), duration = 5, is_bad = 1, info = o.info, data = o.data WHERE s.id=o.shared_id AND status="good"', other_builder.to_s)
|
60
58
|
end
|
61
59
|
end
|
62
|
-
|
63
|
-
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sqlstmt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Makani Mason
|
@@ -9,36 +9,8 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
13
|
-
dependencies:
|
14
|
-
- !ruby/object:Gem::Dependency
|
15
|
-
name: dohutil
|
16
|
-
requirement: !ruby/object:Gem::Requirement
|
17
|
-
requirements:
|
18
|
-
- - ">="
|
19
|
-
- !ruby/object:Gem::Version
|
20
|
-
version: 0.2.21
|
21
|
-
type: :runtime
|
22
|
-
prerelease: false
|
23
|
-
version_requirements: !ruby/object:Gem::Requirement
|
24
|
-
requirements:
|
25
|
-
- - ">="
|
26
|
-
- !ruby/object:Gem::Version
|
27
|
-
version: 0.2.21
|
28
|
-
- !ruby/object:Gem::Dependency
|
29
|
-
name: dohtest
|
30
|
-
requirement: !ruby/object:Gem::Requirement
|
31
|
-
requirements:
|
32
|
-
- - ">="
|
33
|
-
- !ruby/object:Gem::Version
|
34
|
-
version: 0.1.42
|
35
|
-
type: :development
|
36
|
-
prerelease: false
|
37
|
-
version_requirements: !ruby/object:Gem::Requirement
|
38
|
-
requirements:
|
39
|
-
- - ">="
|
40
|
-
- !ruby/object:Gem::Version
|
41
|
-
version: 0.1.42
|
12
|
+
date: 2016-01-18 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
42
14
|
description: build SQL statements in a modular fashion, one piece at a time; only
|
43
15
|
used/tested with MySQL so far
|
44
16
|
email:
|
@@ -50,21 +22,15 @@ extra_rdoc_files:
|
|
50
22
|
files:
|
51
23
|
- MIT-LICENSE
|
52
24
|
- lib/sqlstmt.rb
|
53
|
-
- lib/sqlstmt/delete.rb
|
54
25
|
- lib/sqlstmt/error.rb
|
55
|
-
- lib/sqlstmt/
|
56
|
-
- lib/sqlstmt/insert_select.rb
|
57
|
-
- lib/sqlstmt/insert_values.rb
|
58
|
-
- lib/sqlstmt/query.rb
|
59
|
-
- lib/sqlstmt/select.rb
|
26
|
+
- lib/sqlstmt/sqlstmt.rb
|
60
27
|
- lib/sqlstmt/to_sql.rb
|
61
|
-
-
|
62
|
-
-
|
63
|
-
- test/
|
64
|
-
- test/
|
65
|
-
- test/
|
66
|
-
- test/
|
67
|
-
- test/update.dt.rb
|
28
|
+
- test/delete_test.rb
|
29
|
+
- test/helper.rb
|
30
|
+
- test/insert_select_test.rb
|
31
|
+
- test/select_test.rb
|
32
|
+
- test/to_sql_test.rb
|
33
|
+
- test/update_test.rb
|
68
34
|
homepage: https://github.com/atpsoft/sqlstmt
|
69
35
|
licenses:
|
70
36
|
- MIT
|
@@ -90,8 +56,9 @@ signing_key:
|
|
90
56
|
specification_version: 4
|
91
57
|
summary: build SQL statements in a modular fashion, one piece at a time
|
92
58
|
test_files:
|
93
|
-
- test/
|
94
|
-
- test/
|
95
|
-
- test/
|
96
|
-
- test/
|
97
|
-
- test/
|
59
|
+
- test/delete_test.rb
|
60
|
+
- test/helper.rb
|
61
|
+
- test/insert_select_test.rb
|
62
|
+
- test/select_test.rb
|
63
|
+
- test/to_sql_test.rb
|
64
|
+
- test/update_test.rb
|
data/lib/sqlstmt/delete.rb
DELETED
@@ -1,35 +0,0 @@
|
|
1
|
-
require 'sqlstmt/from_query'
|
2
|
-
|
3
|
-
module SqlStmt
|
4
|
-
|
5
|
-
class Delete < FromQuery
|
6
|
-
force_deep_copy :from_tables
|
7
|
-
|
8
|
-
def initialize
|
9
|
-
super
|
10
|
-
@from_tables = []
|
11
|
-
end
|
12
|
-
|
13
|
-
def from(table)
|
14
|
-
@from_tables << table
|
15
|
-
self
|
16
|
-
end
|
17
|
-
|
18
|
-
private
|
19
|
-
def verify_minimum_requirements
|
20
|
-
super
|
21
|
-
combined_table_count = @tables.size + @joins.size
|
22
|
-
raise SqlStmt::Error, "unable to build sql - must call :from when including multiple tables" if @from_tables.empty? && (combined_table_count > 1)
|
23
|
-
end
|
24
|
-
|
25
|
-
def build_stmt
|
26
|
-
if @from_tables.empty?
|
27
|
-
table_clause = ''
|
28
|
-
else
|
29
|
-
table_clause = ' ' + @from_tables.join(',')
|
30
|
-
end
|
31
|
-
"DELETE#{table_clause}#{build_from_clause}"
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
end
|
data/lib/sqlstmt/from_query.rb
DELETED
@@ -1,52 +0,0 @@
|
|
1
|
-
require 'sqlstmt/query'
|
2
|
-
|
3
|
-
module SqlStmt
|
4
|
-
|
5
|
-
class FromQuery < Query
|
6
|
-
def initialize
|
7
|
-
super
|
8
|
-
@group_by = nil
|
9
|
-
@order_by = nil
|
10
|
-
@having = []
|
11
|
-
end
|
12
|
-
|
13
|
-
def group_by(clause)
|
14
|
-
@group_by = clause
|
15
|
-
self
|
16
|
-
end
|
17
|
-
|
18
|
-
def order_by(clause)
|
19
|
-
@order_by = clause
|
20
|
-
self
|
21
|
-
end
|
22
|
-
|
23
|
-
def having(*sql)
|
24
|
-
@having.concat(sql)
|
25
|
-
self
|
26
|
-
end
|
27
|
-
|
28
|
-
private
|
29
|
-
def verify_minimum_requirements
|
30
|
-
super
|
31
|
-
raise SqlStmt::Error, "unable to build sql - must call :table or :join (or one if it's variants)" if @tables.empty? && @joins.empty?
|
32
|
-
raise SqlStmt::Error, "unable to build sql - must call :table if using :join (or one if it's variants)" if @tables.empty? && !@joins.empty?
|
33
|
-
end
|
34
|
-
|
35
|
-
def having_clause
|
36
|
-
if @having.empty?
|
37
|
-
''
|
38
|
-
else
|
39
|
-
" HAVING #{@having.join(' AND ')}"
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
def build_from_clause
|
44
|
-
join_clause = build_join_clause
|
45
|
-
group_clause = simple_clause('GROUP BY', @group_by)
|
46
|
-
order_clause = simple_clause('ORDER BY', @order_by)
|
47
|
-
limit_clause = simple_clause('LIMIT', @limit)
|
48
|
-
" FROM #{build_table_list}#{join_clause}#{build_where_clause}#{group_clause}#{having_clause}#{order_clause}#{limit_clause}"
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
end
|
@@ -1,48 +0,0 @@
|
|
1
|
-
require 'sqlstmt/from_query'
|
2
|
-
require 'sqlstmt/value_util'
|
3
|
-
|
4
|
-
module SqlStmt
|
5
|
-
|
6
|
-
class InsertSelect < FromQuery
|
7
|
-
force_deep_copy :values
|
8
|
-
include ValueUtil
|
9
|
-
|
10
|
-
def initialize
|
11
|
-
super
|
12
|
-
@values = []
|
13
|
-
@distinct = @ignore = false
|
14
|
-
@into_table = nil
|
15
|
-
end
|
16
|
-
|
17
|
-
def distinct
|
18
|
-
@distinct = true
|
19
|
-
self
|
20
|
-
end
|
21
|
-
|
22
|
-
def ignore
|
23
|
-
@ignore = true
|
24
|
-
self
|
25
|
-
end
|
26
|
-
|
27
|
-
def insert_into(table)
|
28
|
-
@into_table = table
|
29
|
-
self
|
30
|
-
end
|
31
|
-
|
32
|
-
private
|
33
|
-
def verify_minimum_requirements
|
34
|
-
super
|
35
|
-
raise SqlStmt::Error, "unable to build sql - must call :into" if @into_table.nil?
|
36
|
-
raise SqlStmt::Error, "unable to build sql - must call :field or :fieldq" if @fields.empty?
|
37
|
-
end
|
38
|
-
|
39
|
-
def build_stmt
|
40
|
-
distinct_str = if @distinct then 'DISTINCT ' else '' end
|
41
|
-
ignore_str = if @ignore then 'IGNORE ' else '' end
|
42
|
-
into_str = @fields.join(',')
|
43
|
-
select_str = @values.join(',')
|
44
|
-
"INSERT #{ignore_str}INTO #@into_table (#{into_str}) SELECT #{distinct_str}#{select_str}#{build_from_clause}"
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
end
|
@@ -1,37 +0,0 @@
|
|
1
|
-
require 'sqlstmt/from_query'
|
2
|
-
require 'sqlstmt/value_util'
|
3
|
-
|
4
|
-
module SqlStmt
|
5
|
-
|
6
|
-
class InsertValues < FromQuery
|
7
|
-
force_deep_copy :values
|
8
|
-
include ValueUtil
|
9
|
-
|
10
|
-
def initialize
|
11
|
-
super
|
12
|
-
@values = []
|
13
|
-
@into_table = nil
|
14
|
-
no_where
|
15
|
-
end
|
16
|
-
|
17
|
-
def into(table)
|
18
|
-
@into_table = table
|
19
|
-
table(table)
|
20
|
-
self
|
21
|
-
end
|
22
|
-
|
23
|
-
private
|
24
|
-
def verify_minimum_requirements
|
25
|
-
super
|
26
|
-
raise SqlStmt::Error, "unable to build sql - must call :into" if @into_table.nil?
|
27
|
-
raise SqlStmt::Error, "unable to build sql - must call :field or :fieldq" if @fields.empty?
|
28
|
-
end
|
29
|
-
|
30
|
-
def build_stmt
|
31
|
-
into_str = @fields.join(',')
|
32
|
-
values_str = @values.join(',')
|
33
|
-
"INSERT INTO #@into_table (#{into_str}) VALUES (#{values_str})"
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
end
|
data/lib/sqlstmt/query.rb
DELETED
@@ -1,110 +0,0 @@
|
|
1
|
-
require 'dohutil/core_ext/force_deep_copy'
|
2
|
-
require 'sqlstmt/error'
|
3
|
-
|
4
|
-
module SqlStmt
|
5
|
-
|
6
|
-
class Query
|
7
|
-
force_deep_copy :fields, :tables, :joins, :wheres
|
8
|
-
attr_reader :fields, :tables, :joins, :wheres
|
9
|
-
|
10
|
-
def initialize
|
11
|
-
@fields = []
|
12
|
-
@tables = []
|
13
|
-
@joins = []
|
14
|
-
@wheres = []
|
15
|
-
@where_behavior = :require
|
16
|
-
@limit = nil
|
17
|
-
end
|
18
|
-
|
19
|
-
def table(table)
|
20
|
-
@tables << table
|
21
|
-
self
|
22
|
-
end
|
23
|
-
|
24
|
-
def join(table, *exprs)
|
25
|
-
@joins << ['JOIN', table, "ON #{exprs.join(' AND ')}"]
|
26
|
-
self
|
27
|
-
end
|
28
|
-
|
29
|
-
def optional_join(table, expr)
|
30
|
-
unless includes_table?(table)
|
31
|
-
join(table, expr)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
def left_join(table, *exprs)
|
36
|
-
@joins << ['LEFT JOIN', table, "ON #{exprs.join(' AND ')}"]
|
37
|
-
self
|
38
|
-
end
|
39
|
-
|
40
|
-
def where(*sql)
|
41
|
-
@wheres.concat(sql)
|
42
|
-
self
|
43
|
-
end
|
44
|
-
|
45
|
-
def no_where
|
46
|
-
@where_behavior = :exclude
|
47
|
-
self
|
48
|
-
end
|
49
|
-
|
50
|
-
def optional_where
|
51
|
-
@where_behavior = :optional
|
52
|
-
self
|
53
|
-
end
|
54
|
-
|
55
|
-
def limit(clause)
|
56
|
-
@limit = clause
|
57
|
-
self
|
58
|
-
end
|
59
|
-
|
60
|
-
def to_s
|
61
|
-
verify_minimum_requirements
|
62
|
-
build_stmt
|
63
|
-
end
|
64
|
-
alias_method :to_sql, :to_s
|
65
|
-
|
66
|
-
def includes_table?(table_to_find)
|
67
|
-
retval = @tables.find { |table| table_names_match?(table, table_to_find) }
|
68
|
-
retval ||= @joins.find { |_, table, _| table_names_match?(table, table_to_find) }
|
69
|
-
retval
|
70
|
-
end
|
71
|
-
|
72
|
-
private
|
73
|
-
def table_names_match?(fullstr, tofind)
|
74
|
-
if tofind.index(' ') || !fullstr.index(' ')
|
75
|
-
return fullstr == tofind
|
76
|
-
end
|
77
|
-
orig_name, _, tblas = fullstr.partition(' ')
|
78
|
-
(orig_name == tofind) || (tblas == tofind)
|
79
|
-
end
|
80
|
-
|
81
|
-
def verify_minimum_requirements
|
82
|
-
if (@where_behavior == :require) && @wheres.empty?
|
83
|
-
raise SqlStmt::Error, "unable to build sql - must call :where, :no_where, or :optional_where"
|
84
|
-
elsif (@where_behavior == :exclude) && !@wheres.empty?
|
85
|
-
raise SqlStmt::Error, "unable to build sql - :where and :no_where must not both be called, consider :optional_where instead"
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
def build_table_list
|
90
|
-
@tables.join(',')
|
91
|
-
end
|
92
|
-
|
93
|
-
def simple_clause(keywords, value)
|
94
|
-
if value then " #{keywords} #{value}" else '' end
|
95
|
-
end
|
96
|
-
|
97
|
-
def build_join_clause
|
98
|
-
if @joins.empty?
|
99
|
-
''
|
100
|
-
else
|
101
|
-
' ' + @joins.collect{|ary| ary.join(' ')}.uniq.join(' ')
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
def build_where_clause
|
106
|
-
if @wheres.empty? then '' else " WHERE #{@wheres.join(' AND ')}" end
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
end
|
data/lib/sqlstmt/select.rb
DELETED
@@ -1,48 +0,0 @@
|
|
1
|
-
require 'sqlstmt/from_query'
|
2
|
-
|
3
|
-
module SqlStmt
|
4
|
-
|
5
|
-
class Select < FromQuery
|
6
|
-
def initialize
|
7
|
-
super
|
8
|
-
@distinct = false
|
9
|
-
@straight_join = false
|
10
|
-
@into = nil
|
11
|
-
end
|
12
|
-
|
13
|
-
def field(*field_exprs)
|
14
|
-
@fields.concat(field_exprs)
|
15
|
-
self
|
16
|
-
end
|
17
|
-
|
18
|
-
def distinct
|
19
|
-
@distinct = true
|
20
|
-
self
|
21
|
-
end
|
22
|
-
|
23
|
-
def straight_join
|
24
|
-
@straight_join = true
|
25
|
-
self
|
26
|
-
end
|
27
|
-
|
28
|
-
def into_outfile(str)
|
29
|
-
@into = "OUTFILE #{str}"
|
30
|
-
self
|
31
|
-
end
|
32
|
-
|
33
|
-
private
|
34
|
-
def verify_minimum_requirements
|
35
|
-
super
|
36
|
-
raise SqlStmt::Error, "unable to build sql - must call :field" if @fields.empty?
|
37
|
-
end
|
38
|
-
|
39
|
-
def build_stmt
|
40
|
-
straight_join_str = if @straight_join then 'STRAIGHT_JOIN ' else '' end
|
41
|
-
distinct_str = if @distinct then 'DISTINCT ' else '' end
|
42
|
-
into_str = if @into then " INTO #{@into}" else '' end
|
43
|
-
select_str = @fields.join(',')
|
44
|
-
"SELECT #{straight_join_str}#{distinct_str}#{select_str}#{build_from_clause}#{into_str}"
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
end
|
data/lib/sqlstmt/update.rb
DELETED
@@ -1,36 +0,0 @@
|
|
1
|
-
require 'sqlstmt/query'
|
2
|
-
require 'sqlstmt/value_util'
|
3
|
-
|
4
|
-
module SqlStmt
|
5
|
-
|
6
|
-
class Update < Query
|
7
|
-
force_deep_copy :values
|
8
|
-
include ValueUtil
|
9
|
-
|
10
|
-
def initialize
|
11
|
-
super
|
12
|
-
@values = []
|
13
|
-
end
|
14
|
-
|
15
|
-
private
|
16
|
-
def verify_minimum_requirements
|
17
|
-
super
|
18
|
-
raise SqlStmt::Error, "unable to build sql - must call :table" if @tables.empty?
|
19
|
-
raise SqlStmt::Error, "unable to build sql - must call :field or :fieldq" if @fields.empty?
|
20
|
-
end
|
21
|
-
|
22
|
-
def build_set_clause
|
23
|
-
set_exprs = []
|
24
|
-
@fields.each_with_index do |field, index|
|
25
|
-
set_exprs.push("#{field} = #{@values[index]}")
|
26
|
-
end
|
27
|
-
set_exprs.join(', ')
|
28
|
-
end
|
29
|
-
|
30
|
-
def build_stmt
|
31
|
-
limit_clause = simple_clause('LIMIT', @limit)
|
32
|
-
"UPDATE #{build_table_list}#{build_join_clause} SET #{build_set_clause}#{build_where_clause}#{limit_clause}"
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
end
|
data/lib/sqlstmt/value_util.rb
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
require 'sqlstmt/to_sql'
|
2
|
-
|
3
|
-
module ValueUtil
|
4
|
-
def field(field, value)
|
5
|
-
raise "trying to include field #{field} again" if @fields.include?(field)
|
6
|
-
@fields.push(field)
|
7
|
-
@values.push(if value.is_a?(String) then value else value.to_sql end)
|
8
|
-
self
|
9
|
-
end
|
10
|
-
|
11
|
-
def fieldq(field, value)
|
12
|
-
field(field, value.to_sql)
|
13
|
-
end
|
14
|
-
end
|
data/test/delete.dt.rb
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
require 'sqlstmt/delete'
|
2
|
-
|
3
|
-
module SqlStmt
|
4
|
-
|
5
|
-
class TestDelete < DohTest::TestGroup
|
6
|
-
def test_minimum_requirements
|
7
|
-
assert_raises(SqlStmt::Error) { Delete.new.table('target').to_s }
|
8
|
-
end
|
9
|
-
|
10
|
-
def test_simple
|
11
|
-
assert_equal('DELETE t FROM target t,other_table o', Delete.new.from('t').table('target t').table('other_table o').no_where.to_s)
|
12
|
-
assert_equal('DELETE t,o FROM t JOIN o ON t.id=o.id', Delete.new.from('t').from('o').table('t').join('o','t.id=o.id').no_where.to_s)
|
13
|
-
assert_equal('DELETE FROM target', Delete.new.table('target').no_where.to_s)
|
14
|
-
assert_equal('DELETE FROM target WHERE target_id = 1', Delete.new.table('target').where('target_id = 1').to_s)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
end
|
data/test/select.dt.rb
DELETED
@@ -1,53 +0,0 @@
|
|
1
|
-
require 'sqlstmt/select'
|
2
|
-
|
3
|
-
module SqlStmt
|
4
|
-
|
5
|
-
class TestSelect < DohTest::TestGroup
|
6
|
-
def test_includes_table
|
7
|
-
sqlb = Select.new.table('target t')
|
8
|
-
assert(sqlb.includes_table?('target'))
|
9
|
-
assert(sqlb.includes_table?('t'))
|
10
|
-
assert(!sqlb.includes_table?('blah'))
|
11
|
-
end
|
12
|
-
|
13
|
-
def test_minimum_requirements
|
14
|
-
assert_raises(SqlStmt::Error) { Select.new.table('target').to_s }
|
15
|
-
assert_raises(SqlStmt::Error) { Select.new.table('target').no_where.to_s }
|
16
|
-
assert_raises(SqlStmt::Error) { Select.new.table('target').optional_where.to_s }
|
17
|
-
assert_equal('SELECT blah FROM target', Select.new.table('target').optional_where.field('blah').to_sql)
|
18
|
-
end
|
19
|
-
|
20
|
-
def test_stuff
|
21
|
-
assert_equal('SELECT blah FROM source', Select.new.table('source').field('blah').no_where.to_s)
|
22
|
-
assert_equal('SELECT DISTINCT blah FROM source', Select.new.table('source').field('blah').no_where.distinct.to_s)
|
23
|
-
assert_equal('SELECT blah FROM source WHERE source_id = 1', Select.new.table('source').field('blah').where('source_id = 1').to_s)
|
24
|
-
assert_equal('SELECT blah FROM source s', Select.new.table('source s').field('blah').no_where.to_s)
|
25
|
-
assert_equal('SELECT blah FROM source s JOIN other o ON s.blah_id = o.blah_id', Select.new.table('source s').join('other o', 's.blah_id = o.blah_id').field('blah').no_where.to_s)
|
26
|
-
assert_equal('SELECT blah FROM source s LEFT JOIN other o ON s.blah_id = o.blah_id', Select.new.table('source s').left_join('other o', 's.blah_id = o.blah_id').field('blah').no_where.to_s)
|
27
|
-
assert_equal('SELECT blah,blee FROM source', Select.new.table('source').field('blah','blee').no_where.to_s)
|
28
|
-
assert_equal('SELECT blah FROM source HAVING blee > 0', Select.new.table('source').field('blah').no_where.having('blee > 0').to_s)
|
29
|
-
end
|
30
|
-
|
31
|
-
def test_duplicate_joins
|
32
|
-
sqlb = Select.new.table('source s').field('frog').no_where
|
33
|
-
4.times { sqlb.join('other o', 's.blah_id = o.blah_id') }
|
34
|
-
assert_equal('SELECT frog FROM source s JOIN other o ON s.blah_id = o.blah_id', sqlb.to_s)
|
35
|
-
end
|
36
|
-
|
37
|
-
def test_optional_join
|
38
|
-
sqlb = Select.new.table('source s').field('frog').no_where
|
39
|
-
sqlb.join('other o', 's.blah_id = o.blah_id')
|
40
|
-
sqlb.optional_join('other o', 'z.blee_id = o.blee_id')
|
41
|
-
assert_equal('SELECT frog FROM source s JOIN other o ON s.blah_id = o.blah_id', sqlb.to_s)
|
42
|
-
end
|
43
|
-
|
44
|
-
def test_join_with_multiple_conditions
|
45
|
-
%i(join left_join).each do |method|
|
46
|
-
sqlb = Select.new.table('source s').field('frog').no_where.send(method, 'other o', 'z.blee_id = o.blee_id', 'z.other_field = o.other_field')
|
47
|
-
method_sql = method.to_s.upcase.sub('_', ' ')
|
48
|
-
assert_equal("SELECT frog FROM source s #{method_sql} other o ON z.blee_id = o.blee_id AND z.other_field = o.other_field", sqlb.to_s)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
end
|