sequel 0.4.3 → 0.4.4
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +16 -0
- data/Rakefile +1 -1
- data/lib/sequel/adapters/mysql.rb +13 -0
- data/lib/sequel/adapters/sqlite.rb +9 -0
- data/lib/sequel/database.rb +32 -3
- data/lib/sequel/dataset/sequelizer.rb +104 -56
- data/lib/sequel/dataset/sql.rb +1 -1
- data/lib/sequel/schema/schema_generator.rb +63 -1
- data/lib/sequel/schema/schema_sql.rb +27 -0
- data/spec/adapters/mysql_spec.rb +71 -19
- data/spec/adapters/postgres_spec.rb +48 -5
- data/spec/adapters/sqlite_spec.rb +37 -0
- data/spec/database_spec.rb +105 -0
- data/spec/schema_spec.rb +10 -1
- data/spec/sequelizer_spec.rb +26 -1
- metadata +2 -2
data/CHANGELOG
CHANGED
@@ -1,3 +1,19 @@
|
|
1
|
+
=== 0.4.4 (2007-12-17)
|
2
|
+
|
3
|
+
* Implemented Database#rename_table (#104).
|
4
|
+
|
5
|
+
* Fixed drop_index in mysql adapter (#103).
|
6
|
+
|
7
|
+
* Added ALTER TABLE specs for postgres, sqlite and mysql adapters. Added custom alter_table behavior for sqlite and mysql adapters (#101, #102).
|
8
|
+
|
9
|
+
* Added direct Database API for altering tables.
|
10
|
+
|
11
|
+
* Added Database#alter_table method with support for adding, dropping, renaming, modifying columns and adding and droppping indexes.
|
12
|
+
|
13
|
+
* Added #unique schema method for defining unique indexes (thanks Dado).
|
14
|
+
|
15
|
+
* Implemented unfolding of #each calls inside sequelizer blocks (thanks Jim Morris).
|
16
|
+
|
1
17
|
=== 0.4.3 (2007-12-15)
|
2
18
|
|
3
19
|
* Fixed Dataset#update to accept strings (#98).
|
data/Rakefile
CHANGED
@@ -6,7 +6,7 @@ require 'fileutils'
|
|
6
6
|
include FileUtils
|
7
7
|
|
8
8
|
NAME = "sequel"
|
9
|
-
VERS = "0.4.
|
9
|
+
VERS = "0.4.4"
|
10
10
|
CLEAN.include ['**/.*.sw?', 'pkg/*', '.config', 'doc/*', 'coverage/*']
|
11
11
|
RDOC_OPTS = ['--quiet', '--title', "Sequel: Concise ORM for Ruby",
|
12
12
|
"--opname", "index.html",
|
@@ -143,6 +143,19 @@ module Sequel
|
|
143
143
|
end
|
144
144
|
end
|
145
145
|
|
146
|
+
def alter_table_sql(table, op)
|
147
|
+
case op[:op]
|
148
|
+
when :rename_column
|
149
|
+
"ALTER TABLE #{table} CHANGE COLUMN #{op[:name]} #{op[:new_name]} #{op[:type]}"
|
150
|
+
when :set_column_type
|
151
|
+
"ALTER TABLE #{table} CHANGE COLUMN #{op[:name]} #{op[:name]} #{op[:type]}"
|
152
|
+
when :drop_index
|
153
|
+
"DROP INDEX #{default_index_name(table, op[:columns])} ON #{table}"
|
154
|
+
else
|
155
|
+
super(table, op)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
146
159
|
def transaction
|
147
160
|
@pool.hold do |conn|
|
148
161
|
@transactions ||= []
|
@@ -97,6 +97,15 @@ module Sequel
|
|
97
97
|
pragma_set(:temp_store, value)
|
98
98
|
end
|
99
99
|
|
100
|
+
def alter_table_sql(table, op)
|
101
|
+
case op[:op]
|
102
|
+
when :add_column
|
103
|
+
"ALTER TABLE #{table} ADD #{column_definition_sql(op)}"
|
104
|
+
else
|
105
|
+
raise SequelError, "Unsupported ALTER TABLE operation"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
100
109
|
def transaction(&block)
|
101
110
|
@pool.hold do |conn|
|
102
111
|
if conn.transaction_active?
|
data/lib/sequel/database.rb
CHANGED
@@ -174,7 +174,7 @@ module Sequel
|
|
174
174
|
# end
|
175
175
|
def create_table(name, &block)
|
176
176
|
g = Schema::Generator.new(self, name, &block)
|
177
|
-
create_table_sql_list(*g.create_info).each {|
|
177
|
+
create_table_sql_list(*g.create_info).each {|sql| execute(sql)}
|
178
178
|
end
|
179
179
|
|
180
180
|
# Forcibly creates a table. If the table already exists it is dropped.
|
@@ -188,12 +188,41 @@ module Sequel
|
|
188
188
|
names.each {|n| execute(drop_table_sql(n))}
|
189
189
|
end
|
190
190
|
|
191
|
+
def rename_table(*args)
|
192
|
+
execute(rename_table_sql(*args))
|
193
|
+
end
|
194
|
+
|
195
|
+
def alter_table(name, &block)
|
196
|
+
g = Schema::AlterTableGenerator.new(self, name, &block)
|
197
|
+
alter_table_sql_list(name, g.operations).each {|sql| execute(sql)}
|
198
|
+
end
|
199
|
+
|
200
|
+
def add_column(table, *args)
|
201
|
+
alter_table(table) {add_column(*args)}
|
202
|
+
end
|
203
|
+
|
204
|
+
def drop_column(table, *args)
|
205
|
+
alter_table(table) {drop_column(*args)}
|
206
|
+
end
|
207
|
+
|
208
|
+
def rename_column(table, *args)
|
209
|
+
alter_table(table) {rename_column(*args)}
|
210
|
+
end
|
211
|
+
|
212
|
+
def set_column_type(table, *args)
|
213
|
+
alter_table(table) {set_column_type(*args)}
|
214
|
+
end
|
215
|
+
|
191
216
|
# Adds an index to a table for the given columns:
|
192
217
|
#
|
193
218
|
# DB.add_index(:posts, :title)
|
194
219
|
# DB.add_index(:posts, [:author, :title], :unique => true)
|
195
|
-
def add_index(table,
|
196
|
-
|
220
|
+
def add_index(table, *args)
|
221
|
+
alter_table(table) {add_index(*args)}
|
222
|
+
end
|
223
|
+
|
224
|
+
def drop_index(table, *args)
|
225
|
+
alter_table(table) {drop_index(*args)}
|
197
226
|
end
|
198
227
|
|
199
228
|
# Returns true if the given table exists.
|
@@ -75,7 +75,7 @@ class Sequel::Dataset
|
|
75
75
|
#
|
76
76
|
# This method depends on the Ruby2Ruby gem. If you do not have Ruby2Ruby
|
77
77
|
# installed, this method will raise an error.
|
78
|
-
def ext_expr(e, b)
|
78
|
+
def ext_expr(e, b, opts)
|
79
79
|
eval(RubyToRuby.new.process(e), b)
|
80
80
|
end
|
81
81
|
|
@@ -103,103 +103,151 @@ class Sequel::Dataset
|
|
103
103
|
# :substring[:x, 5] #=> "substring(x, 5)"
|
104
104
|
#
|
105
105
|
# All other method calls are evaulated as normal Ruby code.
|
106
|
-
def call_expr(e, b)
|
106
|
+
def call_expr(e, b, opts)
|
107
107
|
case op = e[2]
|
108
108
|
when :>, :<, :>=, :<=
|
109
|
-
l = eval_expr(e[1], b)
|
110
|
-
r = eval_expr(e[3][1], b)
|
109
|
+
l = eval_expr(e[1], b, opts)
|
110
|
+
r = eval_expr(e[3][1], b, opts)
|
111
111
|
if l.is_one_of?(Symbol, Sequel::LiteralString, Sequel::SQL::Expression) || \
|
112
112
|
r.is_one_of?(Symbol, Sequel::LiteralString, Sequel::SQL::Expression)
|
113
113
|
"(#{literal(l)} #{op} #{literal(r)})"
|
114
114
|
else
|
115
|
-
ext_expr(e, b)
|
115
|
+
ext_expr(e, b, opts)
|
116
116
|
end
|
117
117
|
when :==
|
118
|
-
l = eval_expr(e[1], b)
|
119
|
-
r = eval_expr(e[3][1], b)
|
118
|
+
l = eval_expr(e[1], b, opts)
|
119
|
+
r = eval_expr(e[3][1], b, opts)
|
120
120
|
compare_expr(l, r)
|
121
121
|
when :=~
|
122
|
-
l = eval_expr(e[1], b)
|
123
|
-
r = eval_expr(e[3][1], b)
|
122
|
+
l = eval_expr(e[1], b, opts)
|
123
|
+
r = eval_expr(e[3][1], b, opts)
|
124
124
|
match_expr(l, r)
|
125
125
|
when :+, :-, :*, :%, :/
|
126
|
-
l = eval_expr(e[1], b)
|
127
|
-
r = eval_expr(e[3][1], b)
|
126
|
+
l = eval_expr(e[1], b, opts)
|
127
|
+
r = eval_expr(e[3][1], b, opts)
|
128
128
|
if l.is_one_of?(Symbol, Sequel::LiteralString, Sequel::SQL::Expression) || \
|
129
129
|
r.is_one_of?(Symbol, Sequel::LiteralString, Sequel::SQL::Expression)
|
130
130
|
"(#{literal(l)} #{op} #{literal(r)})".lit
|
131
131
|
else
|
132
|
-
ext_expr(e, b)
|
132
|
+
ext_expr(e, b, opts)
|
133
133
|
end
|
134
134
|
when :<<
|
135
|
-
l = eval_expr(e[1], b)
|
136
|
-
r = eval_expr(e[3][1], b)
|
135
|
+
l = eval_expr(e[1], b, opts)
|
136
|
+
r = eval_expr(e[3][1], b, opts)
|
137
137
|
"#{literal(l)} = #{literal(r)}".lit
|
138
138
|
when :|
|
139
|
-
l = eval_expr(e[1], b)
|
140
|
-
r = eval_expr(e[3][1], b)
|
139
|
+
l = eval_expr(e[1], b, opts)
|
140
|
+
r = eval_expr(e[3][1], b, opts)
|
141
141
|
if l.is_one_of?(Symbol, Sequel::SQL::Subscript)
|
142
142
|
l|r
|
143
143
|
elsif l.is_one_of?(Symbol, Sequel::LiteralString, Sequel::SQL::Expression) || \
|
144
144
|
r.is_one_of?(Symbol, Sequel::LiteralString, Sequel::SQL::Expression)
|
145
145
|
"(#{literal(l)} #{op} #{literal(r)})".lit
|
146
146
|
else
|
147
|
-
ext_expr(e, b)
|
147
|
+
ext_expr(e, b, opts)
|
148
148
|
end
|
149
149
|
when :in, :in?
|
150
150
|
# in/in? operators are supported using two forms:
|
151
151
|
# :x.in([1, 2, 3])
|
152
152
|
# :x.in(1, 2, 3) # variable arity
|
153
|
-
l = eval_expr(e[1], b)
|
154
|
-
r = eval_expr((e[3].size == 2) ? e[3][1] : e[3], b)
|
153
|
+
l = eval_expr(e[1], b, opts)
|
154
|
+
r = eval_expr((e[3].size == 2) ? e[3][1] : e[3], b, opts)
|
155
155
|
compare_expr(l, r)
|
156
156
|
when :nil, :nil?
|
157
|
-
l = eval_expr(e[1], b)
|
157
|
+
l = eval_expr(e[1], b, opts)
|
158
158
|
compare_expr(l, nil)
|
159
159
|
when :like, :like?
|
160
|
-
l = eval_expr(e[1], b)
|
161
|
-
r = eval_expr(e[3][1], b)
|
160
|
+
l = eval_expr(e[1], b, opts)
|
161
|
+
r = eval_expr(e[3][1], b, opts)
|
162
162
|
match_expr(l, r)
|
163
163
|
else
|
164
164
|
if (op == :[]) && (e[1][0] == :lit) && (Symbol === e[1][1])
|
165
165
|
# SQL Functions, e.g.: :sum[:x]
|
166
166
|
if e[3]
|
167
|
-
e[1][1][*eval_expr(e[3], b)]
|
167
|
+
e[1][1][*eval_expr(e[3], b, opts)]
|
168
168
|
else
|
169
169
|
e[1][1][]
|
170
170
|
end
|
171
171
|
else
|
172
172
|
# external code
|
173
|
-
ext_expr(e, b)
|
173
|
+
ext_expr(e, b, opts)
|
174
174
|
end
|
175
175
|
end
|
176
176
|
end
|
177
177
|
|
178
|
-
def fcall_expr(e, b) #:nodoc:
|
179
|
-
ext_expr(e, b)
|
178
|
+
def fcall_expr(e, b, opts) #:nodoc:
|
179
|
+
ext_expr(e, b, opts)
|
180
180
|
end
|
181
181
|
|
182
|
-
def vcall_expr(e, b) #:nodoc:
|
182
|
+
def vcall_expr(e, b, opts) #:nodoc:
|
183
183
|
eval(e[1].to_s, b)
|
184
184
|
end
|
185
185
|
|
186
|
-
def iter_expr(e, b) #:nodoc:
|
187
|
-
if e[1] ==
|
188
|
-
|
186
|
+
def iter_expr(e, b, opts) #:nodoc:
|
187
|
+
if e[1][0] == :call && e[1][2] == :each
|
188
|
+
unfold_each_expr(e, b, opts)
|
189
|
+
elsif e[1] == [:fcall, :proc]
|
190
|
+
eval_expr(e[3], b, opts) # inline proc
|
189
191
|
else
|
190
|
-
ext_expr(e, b) # method call with inline proc
|
192
|
+
ext_expr(e, b, opts) # method call with inline proc
|
191
193
|
end
|
192
194
|
end
|
193
195
|
|
196
|
+
def replace_dvars(a, values)
|
197
|
+
a.map do |i|
|
198
|
+
if i.is_a?(Array) && (i[0] == :dvar)
|
199
|
+
if v = values[i[1]]
|
200
|
+
value_to_parse_tree(v)
|
201
|
+
else
|
202
|
+
i
|
203
|
+
end
|
204
|
+
elsif Array === i
|
205
|
+
replace_dvars(i, values)
|
206
|
+
else
|
207
|
+
i
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
def value_to_parse_tree(value)
|
213
|
+
c = Class.new
|
214
|
+
c.class_eval("def m; #{value.inspect}; end")
|
215
|
+
ParseTree.translate(c, :m)[2][1][2]
|
216
|
+
end
|
217
|
+
|
218
|
+
def unfold_each_expr(e, b, opts) #:nodoc:
|
219
|
+
source = eval_expr(e[1][1], b, opts)
|
220
|
+
block_dvars = []
|
221
|
+
if e[2][0] == :dasgn_curr
|
222
|
+
block_dvars << e[2][1]
|
223
|
+
elsif e[2][0] == :masgn
|
224
|
+
e[2][1].each do |i|
|
225
|
+
if i.is_a?(Array) && i[0] == :dasgn_curr
|
226
|
+
block_dvars << i[1]
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
new_block = [:block]
|
231
|
+
|
232
|
+
source.each do |*dvars|
|
233
|
+
iter_values = (Array === dvars[0]) ? dvars[0] : dvars
|
234
|
+
values = block_dvars.inject({}) {|m, i| m[i] = iter_values.shift; m}
|
235
|
+
iter = replace_dvars(e[3], values)
|
236
|
+
new_block << iter
|
237
|
+
end
|
238
|
+
|
239
|
+
pt_expr(new_block, b, opts)
|
240
|
+
end
|
241
|
+
|
194
242
|
# Evaluates a parse-tree into an SQL expression.
|
195
|
-
def eval_expr(e, b)
|
243
|
+
def eval_expr(e, b, opts)
|
196
244
|
case e[0]
|
197
245
|
when :call # method call
|
198
|
-
call_expr(e, b)
|
246
|
+
call_expr(e, b, opts)
|
199
247
|
when :fcall
|
200
|
-
fcall_expr(e, b)
|
248
|
+
fcall_expr(e, b, opts)
|
201
249
|
when :vcall
|
202
|
-
vcall_expr(e, b)
|
250
|
+
vcall_expr(e, b, opts)
|
203
251
|
when :ivar, :cvar, :dvar, :const, :gvar # local ref
|
204
252
|
eval(e[1].to_s, b)
|
205
253
|
when :nth_ref:
|
@@ -214,31 +262,31 @@ class Sequel::Dataset
|
|
214
262
|
when :lit, :str # literal
|
215
263
|
e[1]
|
216
264
|
when :dot2 # inclusive range
|
217
|
-
eval_expr(e[1], b)..eval_expr(e[2], b)
|
265
|
+
eval_expr(e[1], b, opts)..eval_expr(e[2], b, opts)
|
218
266
|
when :dot3 # exclusive range
|
219
|
-
eval_expr(e[1], b)...eval_expr(e[2], b)
|
267
|
+
eval_expr(e[1], b, opts)...eval_expr(e[2], b, opts)
|
220
268
|
when :colon2 # qualified constant ref
|
221
|
-
eval_expr(e[1], b).const_get(e[2])
|
269
|
+
eval_expr(e[1], b, opts).const_get(e[2])
|
222
270
|
when :false: false
|
223
271
|
when :true: true
|
224
272
|
when :nil: nil
|
225
273
|
when :array
|
226
274
|
# array
|
227
|
-
e[1..-1].map {|i| eval_expr(i, b)}
|
275
|
+
e[1..-1].map {|i| eval_expr(i, b, opts)}
|
228
276
|
when :match3
|
229
277
|
# =~/!~ operator
|
230
|
-
l = eval_expr(e[2], b)
|
231
|
-
r = eval_expr(e[1], b)
|
278
|
+
l = eval_expr(e[2], b, opts)
|
279
|
+
r = eval_expr(e[1], b, opts)
|
232
280
|
compare_expr(l, r)
|
233
281
|
when :iter
|
234
|
-
iter_expr(e, b)
|
282
|
+
iter_expr(e, b, opts)
|
235
283
|
when :dasgn, :dasgn_curr
|
236
284
|
# assignment
|
237
285
|
l = e[1]
|
238
|
-
r = eval_expr(e[2], b)
|
286
|
+
r = eval_expr(e[2], b, opts)
|
239
287
|
raise SequelError, "Invalid expression #{l} = #{r}. Did you mean :#{l} == #{r}?"
|
240
288
|
when :if, :dstr
|
241
|
-
ext_expr(e, b)
|
289
|
+
ext_expr(e, b, opts)
|
242
290
|
else
|
243
291
|
raise SequelError, "Invalid expression tree: #{e.inspect}"
|
244
292
|
end
|
@@ -247,40 +295,40 @@ class Sequel::Dataset
|
|
247
295
|
JOIN_AND = " AND ".freeze
|
248
296
|
JOIN_COMMA = ", ".freeze
|
249
297
|
|
250
|
-
def pt_expr(e, b,
|
298
|
+
def pt_expr(e, b, opts = {}) #:nodoc:
|
251
299
|
case e[0]
|
252
300
|
when :not # negation: !x, (x != y), (x !~ y)
|
253
301
|
if (e[1][0] == :lit) && (Symbol === e[1][1])
|
254
302
|
# translate (!:x) into (x = 'f')
|
255
303
|
compare_expr(e[1][1], false)
|
256
304
|
else
|
257
|
-
"(NOT #{pt_expr(e[1], b,
|
305
|
+
"(NOT #{pt_expr(e[1], b, opts)})"
|
258
306
|
end
|
259
307
|
when :and # x && y
|
260
|
-
"(#{e[1..-1].map {|i| pt_expr(i, b,
|
308
|
+
"(#{e[1..-1].map {|i| pt_expr(i, b, opts)}.join(JOIN_AND)})"
|
261
309
|
when :or # x || y
|
262
|
-
"(#{pt_expr(e[1], b,
|
310
|
+
"(#{pt_expr(e[1], b, opts)} OR #{pt_expr(e[2], b, opts)})"
|
263
311
|
when :call, :vcall, :iter, :match3 # method calls, blocks
|
264
|
-
eval_expr(e, b)
|
312
|
+
eval_expr(e, b, opts)
|
265
313
|
when :block # block of statements
|
266
|
-
if comma_separated
|
267
|
-
"#{e[1..-1].map {|i| pt_expr(i, b,
|
314
|
+
if opts[:comma_separated]
|
315
|
+
"#{e[1..-1].map {|i| pt_expr(i, b, opts)}.join(JOIN_COMMA)}"
|
268
316
|
else
|
269
|
-
"(#{e[1..-1].map {|i| pt_expr(i, b,
|
317
|
+
"(#{e[1..-1].map {|i| pt_expr(i, b, opts)}.join(JOIN_AND)})"
|
270
318
|
end
|
271
319
|
else # literals
|
272
320
|
if e == [:lvar, :block]
|
273
|
-
eval_expr(e, b)
|
321
|
+
eval_expr(e, b, opts)
|
274
322
|
else
|
275
|
-
literal(eval_expr(e, b))
|
323
|
+
literal(eval_expr(e, b, opts))
|
276
324
|
end
|
277
325
|
end
|
278
326
|
end
|
279
327
|
|
280
328
|
# Translates a Ruby block into an SQL expression.
|
281
|
-
def proc_to_sql(proc,
|
329
|
+
def proc_to_sql(proc, opts = {})
|
282
330
|
c = Class.new {define_method(:m, &proc)}
|
283
|
-
pt_expr(ParseTree.translate(c, :m)[2][2], proc.binding,
|
331
|
+
pt_expr(ParseTree.translate(c, :m)[2][2], proc.binding, opts)
|
284
332
|
end
|
285
333
|
end
|
286
334
|
end
|
data/lib/sequel/dataset/sql.rb
CHANGED
@@ -478,7 +478,7 @@ module Sequel
|
|
478
478
|
|
479
479
|
sql = "UPDATE #{@opts[:from]} SET "
|
480
480
|
if block
|
481
|
-
sql << proc_to_sql(block, true)
|
481
|
+
sql << proc_to_sql(block, :comma_separated => true)
|
482
482
|
else
|
483
483
|
# check if array with keys
|
484
484
|
values = values.to_hash if values.is_a?(Array) && values.keys
|
@@ -7,7 +7,7 @@ module Sequel
|
|
7
7
|
@columns = []
|
8
8
|
@indexes = []
|
9
9
|
@primary_key = nil
|
10
|
-
instance_eval(&block)
|
10
|
+
instance_eval(&block) if block
|
11
11
|
end
|
12
12
|
|
13
13
|
def method_missing(type, name = nil, opts = {})
|
@@ -51,6 +51,10 @@ module Sequel
|
|
51
51
|
@indexes << {:columns => columns}.merge(opts)
|
52
52
|
end
|
53
53
|
|
54
|
+
def unique(columns, opts = {})
|
55
|
+
index(columns, {:unique => true}.merge(opts))
|
56
|
+
end
|
57
|
+
|
54
58
|
def create_info
|
55
59
|
if @primary_key && !has_column?(@primary_key[:name])
|
56
60
|
@columns.unshift(@primary_key)
|
@@ -58,6 +62,64 @@ module Sequel
|
|
58
62
|
[@table_name, @columns, @indexes]
|
59
63
|
end
|
60
64
|
end
|
65
|
+
|
66
|
+
class AlterTableGenerator
|
67
|
+
attr_reader :operations
|
68
|
+
|
69
|
+
def initialize(db, table_name, &block)
|
70
|
+
@db = db
|
71
|
+
@table_name = table_name
|
72
|
+
@operations = []
|
73
|
+
instance_eval(&block) if block
|
74
|
+
end
|
75
|
+
|
76
|
+
def add_column(name, type, opts = {})
|
77
|
+
@operations << {
|
78
|
+
:op => :add_column,
|
79
|
+
:name => name,
|
80
|
+
:type => type
|
81
|
+
}.merge(opts)
|
82
|
+
end
|
83
|
+
|
84
|
+
def drop_column(name)
|
85
|
+
@operations << {
|
86
|
+
:op => :drop_column,
|
87
|
+
:name => name
|
88
|
+
}
|
89
|
+
end
|
90
|
+
|
91
|
+
def rename_column(name, new_name, opts = {})
|
92
|
+
@operations << {
|
93
|
+
:op => :rename_column,
|
94
|
+
:name => name,
|
95
|
+
:new_name => new_name
|
96
|
+
}.merge(opts)
|
97
|
+
end
|
98
|
+
|
99
|
+
def set_column_type(name, type)
|
100
|
+
@operations << {
|
101
|
+
:op => :set_column_type,
|
102
|
+
:name => name,
|
103
|
+
:type => type
|
104
|
+
}
|
105
|
+
end
|
106
|
+
|
107
|
+
def add_index(columns, opts = {})
|
108
|
+
columns = [columns] unless columns.is_a?(Array)
|
109
|
+
@operations << {
|
110
|
+
:op => :add_index,
|
111
|
+
:columns => columns
|
112
|
+
}.merge(opts)
|
113
|
+
end
|
114
|
+
|
115
|
+
def drop_index(columns)
|
116
|
+
columns = [columns] unless columns.is_a?(Array)
|
117
|
+
@operations << {
|
118
|
+
:op => :drop_index,
|
119
|
+
:columns => columns
|
120
|
+
}
|
121
|
+
end
|
122
|
+
end
|
61
123
|
end
|
62
124
|
end
|
63
125
|
|
@@ -84,6 +84,33 @@ module Sequel
|
|
84
84
|
def drop_table_sql(name)
|
85
85
|
"DROP TABLE #{name}"
|
86
86
|
end
|
87
|
+
|
88
|
+
def rename_table_sql(name, new_name)
|
89
|
+
"ALTER TABLE #{name} RENAME TO #{new_name}"
|
90
|
+
end
|
91
|
+
|
92
|
+
def alter_table_sql_list(table, operations)
|
93
|
+
operations.map {|op| alter_table_sql(table, op)}
|
94
|
+
end
|
95
|
+
|
96
|
+
def alter_table_sql(table, op)
|
97
|
+
case op[:op]
|
98
|
+
when :add_column
|
99
|
+
"ALTER TABLE #{table} ADD COLUMN #{column_definition_sql(op)}"
|
100
|
+
when :drop_column
|
101
|
+
"ALTER TABLE #{table} DROP COLUMN #{op[:name]}"
|
102
|
+
when :rename_column
|
103
|
+
"ALTER TABLE #{table} RENAME COLUMN #{op[:name]} TO #{op[:new_name]}"
|
104
|
+
when :set_column_type
|
105
|
+
"ALTER TABLE #{table} ALTER COLUMN #{op[:name]} TYPE #{op[:type]}"
|
106
|
+
when :add_index
|
107
|
+
index_definition_sql(table, op)
|
108
|
+
when :drop_index
|
109
|
+
"DROP INDEX #{default_index_name(table, op[:columns])}"
|
110
|
+
else
|
111
|
+
raise SequelError, "Unsupported ALTER TABLE operation"
|
112
|
+
end
|
113
|
+
end
|
87
114
|
end
|
88
115
|
end
|
89
116
|
end
|
data/spec/adapters/mysql_spec.rb
CHANGED
@@ -1,14 +1,16 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), '../../lib/sequel')
|
2
|
+
require 'logger'
|
2
3
|
|
3
4
|
MYSQL_DB = Sequel('mysql://root@localhost/sandbox')
|
4
|
-
if MYSQL_DB.table_exists?(:items)
|
5
|
-
|
6
|
-
end
|
5
|
+
MYSQL_DB.drop_table(:items) if MYSQL_DB.table_exists?(:items)
|
6
|
+
MYSQL_DB.drop_table(:test2) if MYSQL_DB.table_exists?(:test2)
|
7
7
|
MYSQL_DB.create_table :items do
|
8
|
+
text :name
|
9
|
+
integer :value, :index => true
|
10
|
+
end
|
11
|
+
MYSQL_DB.create_table :test2 do
|
8
12
|
text :name
|
9
13
|
integer :value
|
10
|
-
|
11
|
-
index :value
|
12
14
|
end
|
13
15
|
|
14
16
|
context "A MySQL database" do
|
@@ -235,20 +237,21 @@ context "MySQL datasets" do
|
|
235
237
|
end
|
236
238
|
end
|
237
239
|
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
end
|
251
|
-
|
240
|
+
# # Commented out because it was causing subsequent examples to fail for some reason
|
241
|
+
# context "Simple stored procedure test" do
|
242
|
+
# setup do
|
243
|
+
# # Create a simple stored procedure but drop it first if there
|
244
|
+
# MYSQL_DB.execute("DROP PROCEDURE IF EXISTS sp_get_server_id;")
|
245
|
+
# MYSQL_DB.execute("CREATE PROCEDURE sp_get_server_id() SQL SECURITY DEFINER SELECT @@SERVER_ID as server_id;")
|
246
|
+
# end
|
247
|
+
#
|
248
|
+
# specify "should return the server-id via a stored procedure call" do
|
249
|
+
# @server_id = MYSQL_DB["SELECT @@SERVER_ID as server_id;"].first[:server_id] # grab the server_id via a simple query
|
250
|
+
# @server_id_by_sp = MYSQL_DB["CALL sp_get_server_id();"].first[:server_id]
|
251
|
+
# @server_id_by_sp.should == @server_id # compare it to output from stored procedure
|
252
|
+
# end
|
253
|
+
# end
|
254
|
+
#
|
252
255
|
context "Joiמed MySQL dataset" do
|
253
256
|
setup do
|
254
257
|
@ds = MYSQL_DB[:nodes].join(:attributes, :node_id => :id)
|
@@ -259,3 +262,52 @@ context "Joiמed MySQL dataset" do
|
|
259
262
|
"SELECT * FROM nodes INNER JOIN attributes ON (attributes.`node_id` = nodes.`id`)"
|
260
263
|
end
|
261
264
|
end
|
265
|
+
|
266
|
+
context "A MySQL database" do
|
267
|
+
setup do
|
268
|
+
@db = MYSQL_DB
|
269
|
+
end
|
270
|
+
|
271
|
+
specify "should support add_column operations" do
|
272
|
+
@db.add_column :test2, :xyz, :text
|
273
|
+
|
274
|
+
@db[:test2].columns.should == [:name, :value, :xyz]
|
275
|
+
@db[:test2] << {:name => 'mmm', :value => 111, :xyz => '000'}
|
276
|
+
@db[:test2].first[:xyz].should == '000'
|
277
|
+
end
|
278
|
+
|
279
|
+
specify "should support drop_column operations" do
|
280
|
+
@db[:test2].columns.should == [:name, :value, :xyz]
|
281
|
+
@db.drop_column :test2, :xyz
|
282
|
+
|
283
|
+
@db[:test2].columns.should == [:name, :value]
|
284
|
+
end
|
285
|
+
|
286
|
+
specify "should support rename_column operations" do
|
287
|
+
@db[:test2].delete
|
288
|
+
@db.add_column :test2, :xyz, :text
|
289
|
+
@db[:test2] << {:name => 'mmm', :value => 111, :xyz => 'qqqq'}
|
290
|
+
|
291
|
+
@db[:test2].columns.should == [:name, :value, :xyz]
|
292
|
+
@db.rename_column :test2, :xyz, :zyx, :type => :text
|
293
|
+
@db[:test2].columns.should == [:name, :value, :zyx]
|
294
|
+
@db[:test2].first[:zyx].should == 'qqqq'
|
295
|
+
end
|
296
|
+
|
297
|
+
specify "should support set_column_type operations" do
|
298
|
+
@db.add_column :test2, :xyz, :float
|
299
|
+
@db[:test2].delete
|
300
|
+
@db[:test2] << {:name => 'mmm', :value => 111, :xyz => 56.78}
|
301
|
+
@db.set_column_type :test2, :xyz, :integer
|
302
|
+
|
303
|
+
@db[:test2].first[:xyz].should == 57
|
304
|
+
end
|
305
|
+
|
306
|
+
specify "should support add_index" do
|
307
|
+
@db.add_index :test2, :value
|
308
|
+
end
|
309
|
+
|
310
|
+
specify "should support drop_index" do
|
311
|
+
@db.drop_index :test2, :value
|
312
|
+
end
|
313
|
+
end
|
@@ -1,14 +1,16 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), '../../lib/sequel')
|
2
2
|
|
3
3
|
PGSQL_DB = Sequel('postgres://postgres:postgres@localhost:5432/reality_spec')
|
4
|
-
if PGSQL_DB.table_exists?(:test)
|
5
|
-
|
6
|
-
|
4
|
+
PGSQL_DB.drop_table(:test) if PGSQL_DB.table_exists?(:test)
|
5
|
+
PGSQL_DB.drop_table(:test2) if PGSQL_DB.table_exists?(:test2)
|
6
|
+
|
7
7
|
PGSQL_DB.create_table :test do
|
8
|
+
text :name
|
9
|
+
integer :value, :index => true
|
10
|
+
end
|
11
|
+
PGSQL_DB.create_table :test2 do
|
8
12
|
text :name
|
9
13
|
integer :value
|
10
|
-
|
11
|
-
index :value
|
12
14
|
end
|
13
15
|
|
14
16
|
context "A PostgreSQL database" do
|
@@ -144,3 +146,44 @@ context "A PostgreSQL dataset in array tuples mode" do
|
|
144
146
|
a[:value].should == '123'
|
145
147
|
end
|
146
148
|
end
|
149
|
+
|
150
|
+
context "A PostgreSQL database" do
|
151
|
+
setup do
|
152
|
+
@db = PGSQL_DB
|
153
|
+
end
|
154
|
+
|
155
|
+
specify "should support add_column operations" do
|
156
|
+
@db.add_column :test2, :xyz, :text, :default => '000'
|
157
|
+
|
158
|
+
@db[:test2].columns.should == [:name, :value, :xyz]
|
159
|
+
@db[:test2] << {:name => 'mmm', :value => 111}
|
160
|
+
@db[:test2].first[:xyz].should == '000'
|
161
|
+
end
|
162
|
+
|
163
|
+
specify "should support drop_column operations" do
|
164
|
+
@db[:test2].columns.should == [:name, :value, :xyz]
|
165
|
+
@db.drop_column :test2, :xyz
|
166
|
+
|
167
|
+
@db[:test2].columns.should == [:name, :value]
|
168
|
+
end
|
169
|
+
|
170
|
+
specify "should support rename_column operations" do
|
171
|
+
@db[:test2].delete
|
172
|
+
@db.add_column :test2, :xyz, :text, :default => '000'
|
173
|
+
@db[:test2] << {:name => 'mmm', :value => 111, :xyz => 'qqqq'}
|
174
|
+
|
175
|
+
@db[:test2].columns.should == [:name, :value, :xyz]
|
176
|
+
@db.rename_column :test2, :xyz, :zyx
|
177
|
+
@db[:test2].columns.should == [:name, :value, :zyx]
|
178
|
+
@db[:test2].first[:zyx].should == 'qqqq'
|
179
|
+
end
|
180
|
+
|
181
|
+
specify "should support set_column_type operations" do
|
182
|
+
@db.add_column :test2, :xyz, :float
|
183
|
+
@db[:test2].delete
|
184
|
+
@db[:test2] << {:name => 'mmm', :value => 111, :xyz => 56.78}
|
185
|
+
@db.set_column_type :test2, :xyz, :integer
|
186
|
+
|
187
|
+
@db[:test2].first[:xyz].should == 57
|
188
|
+
end
|
189
|
+
end
|
@@ -6,6 +6,10 @@ SQLITE_DB.create_table :items do
|
|
6
6
|
text :name
|
7
7
|
float :value
|
8
8
|
end
|
9
|
+
SQLITE_DB.create_table :test2 do
|
10
|
+
text :name
|
11
|
+
integer :value
|
12
|
+
end
|
9
13
|
SQLITE_DB.create_table(:time) {timestamp :t}
|
10
14
|
|
11
15
|
context "An SQLite database" do
|
@@ -306,3 +310,36 @@ context "SQLite dataset" do
|
|
306
310
|
end
|
307
311
|
end
|
308
312
|
|
313
|
+
context "A SQLite database" do
|
314
|
+
setup do
|
315
|
+
@db = SQLITE_DB
|
316
|
+
end
|
317
|
+
|
318
|
+
specify "should support add_column operations" do
|
319
|
+
@db.add_column :test2, :xyz, :text
|
320
|
+
|
321
|
+
@db[:test2].columns.should == [:name, :value, :xyz]
|
322
|
+
@db[:test2] << {:name => 'mmm', :value => 111}
|
323
|
+
@db[:test2].first[:xyz].should == '000'
|
324
|
+
end
|
325
|
+
|
326
|
+
specify "should not support drop_column operations" do
|
327
|
+
proc {@db.drop_column :test2, :xyz}.should raise_error(SequelError)
|
328
|
+
end
|
329
|
+
|
330
|
+
specify "should not support rename_column operations" do
|
331
|
+
@db[:test2].delete
|
332
|
+
@db.add_column :test2, :xyz, :text, :default => '000'
|
333
|
+
@db[:test2] << {:name => 'mmm', :value => 111, :xyz => 'qqqq'}
|
334
|
+
|
335
|
+
@db[:test2].columns.should == [:name, :value, :xyz]
|
336
|
+
proc {@db.rename_column :test2, :xyz, :zyx}.should raise_error(SequelError)
|
337
|
+
end
|
338
|
+
|
339
|
+
specify "should not support set_column_type operations" do
|
340
|
+
@db.add_column :test2, :xyz, :float
|
341
|
+
@db[:test2].delete
|
342
|
+
@db[:test2] << {:name => 'mmm', :value => 111, :xyz => 56.78}
|
343
|
+
proc {@db.set_column_type :test2, :xyz, :integer}.should raise_error(SequelError)
|
344
|
+
end
|
345
|
+
end
|
data/spec/database_spec.rb
CHANGED
@@ -229,6 +229,86 @@ context "Database#create_table" do
|
|
229
229
|
end
|
230
230
|
end
|
231
231
|
|
232
|
+
context "Database#alter_table" do
|
233
|
+
setup do
|
234
|
+
@db = DummyDatabase.new
|
235
|
+
end
|
236
|
+
|
237
|
+
specify "should construct proper SQL" do
|
238
|
+
@db.alter_table :xyz do
|
239
|
+
add_column :aaa, :text, :null => false, :unique => true
|
240
|
+
drop_column :bbb
|
241
|
+
rename_column :ccc, :ddd
|
242
|
+
set_column_type :eee, :integer
|
243
|
+
|
244
|
+
add_index :fff, :unique => true
|
245
|
+
drop_index :ggg
|
246
|
+
end
|
247
|
+
|
248
|
+
@db.sqls.should == [
|
249
|
+
'ALTER TABLE xyz ADD COLUMN aaa text UNIQUE NOT NULL',
|
250
|
+
'ALTER TABLE xyz DROP COLUMN bbb',
|
251
|
+
'ALTER TABLE xyz RENAME COLUMN ccc TO ddd',
|
252
|
+
'ALTER TABLE xyz ALTER COLUMN eee TYPE integer',
|
253
|
+
|
254
|
+
'CREATE UNIQUE INDEX xyz_fff_index ON xyz (fff)',
|
255
|
+
'DROP INDEX xyz_ggg_index'
|
256
|
+
]
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
context "Database#add_column" do
|
261
|
+
setup do
|
262
|
+
@db = DummyDatabase.new
|
263
|
+
end
|
264
|
+
|
265
|
+
specify "should construct proper SQL" do
|
266
|
+
@db.add_column :test, :name, :text, :unique => true
|
267
|
+
@db.sqls.should == [
|
268
|
+
'ALTER TABLE test ADD COLUMN name text UNIQUE'
|
269
|
+
]
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
context "Database#drop_column" do
|
274
|
+
setup do
|
275
|
+
@db = DummyDatabase.new
|
276
|
+
end
|
277
|
+
|
278
|
+
specify "should construct proper SQL" do
|
279
|
+
@db.drop_column :test, :name
|
280
|
+
@db.sqls.should == [
|
281
|
+
'ALTER TABLE test DROP COLUMN name'
|
282
|
+
]
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
context "Database#rename_column" do
|
287
|
+
setup do
|
288
|
+
@db = DummyDatabase.new
|
289
|
+
end
|
290
|
+
|
291
|
+
specify "should construct proper SQL" do
|
292
|
+
@db.rename_column :test, :abc, :def
|
293
|
+
@db.sqls.should == [
|
294
|
+
'ALTER TABLE test RENAME COLUMN abc TO def'
|
295
|
+
]
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
context "Database#set_column_type" do
|
300
|
+
setup do
|
301
|
+
@db = DummyDatabase.new
|
302
|
+
end
|
303
|
+
|
304
|
+
specify "should construct proper SQL" do
|
305
|
+
@db.set_column_type :test, :name, :integer
|
306
|
+
@db.sqls.should == [
|
307
|
+
'ALTER TABLE test ALTER COLUMN name TYPE integer'
|
308
|
+
]
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
232
312
|
context "Database#add_index" do
|
233
313
|
setup do
|
234
314
|
@db = DummyDatabase.new
|
@@ -249,6 +329,20 @@ context "Database#add_index" do
|
|
249
329
|
end
|
250
330
|
end
|
251
331
|
|
332
|
+
context "Database#drop_index" do
|
333
|
+
setup do
|
334
|
+
@db = DummyDatabase.new
|
335
|
+
end
|
336
|
+
|
337
|
+
specify "should construct proper SQL" do
|
338
|
+
@db.drop_index :test, :name
|
339
|
+
@db.sqls.should == [
|
340
|
+
'DROP INDEX test_name_index'
|
341
|
+
]
|
342
|
+
end
|
343
|
+
|
344
|
+
end
|
345
|
+
|
252
346
|
class Dummy2Database < Sequel::Database
|
253
347
|
attr_reader :sql
|
254
348
|
def execute(sql); @sql = sql; end
|
@@ -275,6 +369,17 @@ context "Database#drop_table" do
|
|
275
369
|
end
|
276
370
|
end
|
277
371
|
|
372
|
+
context "Database#rename_table" do
|
373
|
+
setup do
|
374
|
+
@db = DummyDatabase.new
|
375
|
+
end
|
376
|
+
|
377
|
+
specify "should construct proper SQL" do
|
378
|
+
@db.rename_table :abc, :xyz
|
379
|
+
@db.sqls.should == ['ALTER TABLE abc RENAME TO xyz']
|
380
|
+
end
|
381
|
+
end
|
382
|
+
|
278
383
|
context "Database#table_exists?" do
|
279
384
|
setup do
|
280
385
|
@db = DummyDatabase.new
|
data/spec/schema_spec.rb
CHANGED
@@ -174,6 +174,14 @@ context "DB#create_table" do
|
|
174
174
|
@db.sqls.should == ["CREATE TABLE cats (id integer)", "CREATE INDEX cats_id_index ON cats (id)"]
|
175
175
|
end
|
176
176
|
|
177
|
+
specify "should accept unique index definitions" do
|
178
|
+
@db.create_table(:cats) do
|
179
|
+
text :name
|
180
|
+
unique :name
|
181
|
+
end
|
182
|
+
@db.sqls.should == ["CREATE TABLE cats (name text)", "CREATE UNIQUE INDEX cats_name_index ON cats (name)"]
|
183
|
+
end
|
184
|
+
|
177
185
|
specify "should accept multiple index definitions" do
|
178
186
|
@db.create_table(:cats) do
|
179
187
|
integer :id
|
@@ -228,4 +236,5 @@ context "DB#drop_table" do
|
|
228
236
|
@db.drop_table :cats
|
229
237
|
@db.sqls.should == ['DROP TABLE cats']
|
230
238
|
end
|
231
|
-
end
|
239
|
+
end
|
240
|
+
|
data/spec/sequelizer_spec.rb
CHANGED
@@ -10,7 +10,7 @@ context "Proc#to_sql" do
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def to_sql_comma_separated
|
13
|
-
DS.proc_to_sql(self, true)
|
13
|
+
DS.proc_to_sql(self, :comma_separated => true)
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
@@ -276,6 +276,31 @@ context "Proc#to_sql" do
|
|
276
276
|
"((x > 10) OR (y > 20))"
|
277
277
|
end
|
278
278
|
|
279
|
+
specify "should support unfolding of calls to #each" do
|
280
|
+
# from http://groups.google.com/group/sequel-talk/browse_thread/thread/54a660568515fbb7
|
281
|
+
periods = [:day, :week, :month, :year, :alltime]
|
282
|
+
idx = 1
|
283
|
+
v = 2
|
284
|
+
pr = proc do
|
285
|
+
periods.each do |p|
|
286
|
+
(p|idx) << (p|idx) + v
|
287
|
+
end
|
288
|
+
end
|
289
|
+
pr.to_sql_comma_separated.should == \
|
290
|
+
"day[1] = (day[1] + 2), week[1] = (week[1] + 2), month[1] = (month[1] + 2), year[1] = (year[1] + 2), alltime[1] = (alltime[1] + 2)"
|
291
|
+
end
|
292
|
+
|
293
|
+
specify "should support unfolding of calls to Hash#each" do
|
294
|
+
periods = {:month => 3}
|
295
|
+
idx = 1
|
296
|
+
pr = proc do
|
297
|
+
periods.each do |k, v|
|
298
|
+
k << k + v
|
299
|
+
end
|
300
|
+
end
|
301
|
+
pr.to_sql_comma_separated.should == "month = (month + 3)"
|
302
|
+
end
|
303
|
+
|
279
304
|
specify "should support local arguments" do
|
280
305
|
def t(x)
|
281
306
|
proc {x > 10}.to_sql
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sequel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sharon Rosner
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2007-12-
|
12
|
+
date: 2007-12-17 00:00:00 +02:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|