sequel 0.4.3 → 0.4.4
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 +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
|