sequel 0.2.0.1 → 0.2.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,3 +1,25 @@
1
+ === 0.2.0.2 (2007-09-07)
2
+
3
+ * Dataset#insert can now accept subqueries.
4
+
5
+ * Changed Migrator.apply to return the version.
6
+
7
+ * Changed Sequel::Model() to cache intermediate classes so descendant classes can be reopened (#39).
8
+
9
+ * Added :charset option to MySQL adapter (#40).
10
+
11
+ * Fixed Dataset#exclude to add parens around NOT expression (#38).
12
+
13
+ * Fixed use of sub-queries with all comparison operators in block filters (#38).
14
+
15
+ * Fixed arithmetic expressions in block filters to not be literalized.
16
+
17
+ * Changed Symbol#method_missing to return LiteralString.
18
+
19
+ * Changed PrettyTable to right-align numbers.
20
+
21
+ * Fixed Model.create_table (thanks Duane Johnson.)
22
+
1
23
  === 0.2.0.1 (2007-09-04)
2
24
 
3
25
  * Improved support for invoking methods with inline procs inside block filters.
data/Rakefile CHANGED
@@ -6,7 +6,7 @@ require 'fileutils'
6
6
  include FileUtils
7
7
 
8
8
  NAME = "sequel"
9
- VERS = "0.2.0.1"
9
+ VERS = "0.2.0.2"
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",
@@ -134,7 +134,7 @@ class Symbol
134
134
  # method name is made of all upper case letters.
135
135
  def method_missing(sym)
136
136
  ((s = sym.to_s) =~ /^([A-Z]+)$/) ? \
137
- "#{s.downcase}(#{to_field_name})" : super
137
+ "#{s.downcase}(#{to_field_name})".lit : super
138
138
  end
139
139
 
140
140
  # Formats an SQL function with optional parameters
@@ -106,9 +106,9 @@ class Sequel::Dataset
106
106
  def call_expr(e, b)
107
107
  case op = e[2]
108
108
  when :>, :<, :>=, :<=
109
- l = pt_expr(e[1], b)
110
- r = pt_expr(e[3][1], b)
111
- "(#{l} #{op} #{r})"
109
+ l = eval_expr(e[1], b)
110
+ r = eval_expr(e[3][1], b)
111
+ "(#{literal(l)} #{op} #{literal(r)})"
112
112
  when :==
113
113
  l = eval_expr(e[1], b)
114
114
  r = eval_expr(e[3][1], b)
@@ -118,9 +118,9 @@ class Sequel::Dataset
118
118
  r = eval_expr(e[3][1], b)
119
119
  match_expr(l, r)
120
120
  when :+, :-, :*, :/, :%
121
- l = pt_expr(e[1], b)
122
- r = pt_expr(e[3][1], b)
123
- "(#{l} #{op} #{r})"
121
+ l = eval_expr(e[1], b)
122
+ r = eval_expr(e[3][1], b)
123
+ "(#{literal(l)} #{op} #{literal(r)})".lit
124
124
  when :in, :in?
125
125
  # in/in? operators are supported using two forms:
126
126
  # :x.in([1, 2, 3])
@@ -249,9 +249,9 @@ module Sequel
249
249
  if @opts[clause]
250
250
  l = expression_list(@opts[clause])
251
251
  r = expression_list(block || cond, parenthesize)
252
- cond = "#{l} AND NOT #{r}"
252
+ cond = "#{l} AND (NOT #{r})"
253
253
  else
254
- cond = "NOT #{expression_list(block || cond, true)}"
254
+ cond = "(NOT #{expression_list(block || cond, true)})"
255
255
  end
256
256
  clone_merge(clause => cond)
257
257
  end
@@ -420,18 +420,24 @@ module Sequel
420
420
  def insert_sql(*values)
421
421
  if values.empty?
422
422
  "INSERT INTO #{@opts[:from]} DEFAULT VALUES;"
423
- elsif (values.size == 1) && values[0].is_a?(Hash)
424
- field_list = []
425
- value_list = []
426
- values[0].each do |k, v|
427
- field_list << field_name(k)
428
- value_list << literal(v)
429
- end
430
- fl = field_list.join(COMMA_SEPARATOR)
431
- vl = value_list.join(COMMA_SEPARATOR)
432
- "INSERT INTO #{@opts[:from]} (#{fl}) VALUES (#{vl});"
433
423
  else
434
- "INSERT INTO #{@opts[:from]} VALUES (#{literal(values)});"
424
+ values = values[0] if values.size == 1
425
+ case values
426
+ when Hash
427
+ field_list = []
428
+ value_list = []
429
+ values.each do |k, v|
430
+ field_list << field_name(k)
431
+ value_list << literal(v)
432
+ end
433
+ fl = field_list.join(COMMA_SEPARATOR)
434
+ vl = value_list.join(COMMA_SEPARATOR)
435
+ "INSERT INTO #{@opts[:from]} (#{fl}) VALUES (#{vl});"
436
+ when Dataset
437
+ "INSERT INTO #{@opts[:from]} #{literal(values)}"
438
+ else
439
+ "INSERT INTO #{@opts[:from]} VALUES (#{literal(values)});"
440
+ end
435
441
  end
436
442
  end
437
443
 
@@ -115,6 +115,8 @@ module Sequel
115
115
  classes.each {|c| c.apply(db, direction)}
116
116
  set_current_migration_version(db, target)
117
117
  end
118
+
119
+ target
118
120
  end
119
121
 
120
122
  # Returns a list of migration classes filtered for the migration range and
data/lib/sequel/model.rb CHANGED
@@ -78,7 +78,7 @@ module Sequel
78
78
  end
79
79
 
80
80
  def self.create_table
81
- db.execute schema.create_sql
81
+ db.create_table_sql_list(*schema.create_info).each {|s| db << s}
82
82
  end
83
83
 
84
84
  def self.drop_table
@@ -292,7 +292,8 @@ module Sequel
292
292
  end
293
293
 
294
294
  def self.Model(table)
295
- Class.new(Sequel::Model) do
295
+ @models ||= {}
296
+ @models[table] ||= Class.new(Sequel::Model) do
296
297
  meta_def(:inherited) do |c|
297
298
  if table.is_a?(Dataset)
298
299
  c.set_dataset(table)
data/lib/sequel/mysql.rb CHANGED
@@ -69,6 +69,11 @@ module Sequel
69
69
  conn = Mysql.real_connect(@opts[:host], @opts[:user], @opts[:password],
70
70
  @opts[:database], @opts[:port])
71
71
  conn.query_with_result = false
72
+ if @opts[:charset]
73
+ conn.query("set character_set_connection = '#{@opts[:charset]}';")
74
+ conn.query("set character_set_client = '#{@opts[:charset]}';")
75
+ conn.query("set character_set_results = '#{@opts[:charset]}';")
76
+ end
72
77
  conn.reconnect = true
73
78
  conn
74
79
  end
@@ -36,8 +36,16 @@ module Sequel
36
36
  '+' + columns.map {|c| '-' * sizes[c]}.join('+') + '+'
37
37
  end
38
38
 
39
+ def self.format_cell(size, v)
40
+ case v
41
+ when Bignum, Fixnum: "%#{size}d" % v
42
+ when Float: "%#{size}g" % v
43
+ else "%-#{size}s" % v.to_s
44
+ end
45
+ end
46
+
39
47
  def self.data_line(columns, sizes, record)
40
- '|' + columns.map {|c| "%-#{sizes[c]}s" % record[c].to_s}.join('|') + '|'
48
+ '|' + columns.map {|c| format_cell(sizes[c], record[c])}.join('|') + '|'
41
49
  end
42
50
 
43
51
  def self.header_line(columns, sizes)
data/spec/dataset_spec.rb CHANGED
@@ -98,10 +98,22 @@ context "A simple dataset" do
98
98
  @dataset.delete_sql.should == 'DELETE FROM test'
99
99
  end
100
100
 
101
- specify "should format an insert statement" do
101
+ specify "should format an insert statement with default values" do
102
102
  @dataset.insert_sql.should == 'INSERT INTO test DEFAULT VALUES;'
103
+ end
104
+
105
+ specify "should format an insert statement with hash" do
103
106
  @dataset.insert_sql(:name => 'wxyz', :price => 342).
104
107
  should match(/INSERT INTO test \(name, price\) VALUES \('wxyz', 342\)|INSERT INTO test \(price, name\) VALUES \(342, 'wxyz'\)/)
108
+ end
109
+
110
+ specify "should format an insert statement with sub-query" do
111
+ @sub = Sequel::Dataset.new(nil).from(:something).filter(:x => 2)
112
+ @dataset.insert_sql(@sub).should == \
113
+ "INSERT INTO test (SELECT * FROM something WHERE (x = 2))"
114
+ end
115
+
116
+ specify "should format an insert statement with array" do
105
117
  @dataset.insert_sql('a', 2, 6.5).should ==
106
118
  "INSERT INTO test VALUES ('a', 2, 6.5);"
107
119
  end
@@ -361,33 +373,33 @@ context "Dataset#exclude" do
361
373
 
362
374
  specify "should correctly include the NOT operator when one condition is given" do
363
375
  @dataset.exclude(:region=>'Asia').select_sql.should ==
364
- "SELECT * FROM test WHERE NOT (region = 'Asia')"
376
+ "SELECT * FROM test WHERE (NOT (region = 'Asia'))"
365
377
  end
366
378
 
367
379
  specify "should take multiple conditions as a hash and express the logic correctly in SQL" do
368
380
  @dataset.exclude(:region => 'Asia', :name => 'Japan').select_sql.
369
- should match(Regexp.union(/WHERE NOT \(\(region = 'Asia'\) AND \(name = 'Japan'\)\)/,
370
- /WHERE NOT \(\(name = 'Japan'\) AND \(region = 'Asia'\)\)/))
381
+ should match(Regexp.union(/WHERE \(NOT \(\(region = 'Asia'\) AND \(name = 'Japan'\)\)\)/,
382
+ /WHERE \(NOT \(\(name = 'Japan'\) AND \(region = 'Asia'\)\)\)/))
371
383
  end
372
384
 
373
385
  specify "should parenthesize a single string condition correctly" do
374
386
  @dataset.exclude("region = 'Asia' AND name = 'Japan'").select_sql.should ==
375
- "SELECT * FROM test WHERE NOT (region = 'Asia' AND name = 'Japan')"
387
+ "SELECT * FROM test WHERE (NOT (region = 'Asia' AND name = 'Japan'))"
376
388
  end
377
389
 
378
390
  specify "should parenthesize an array condition correctly" do
379
391
  @dataset.exclude('region = ? AND name = ?', 'Asia', 'Japan').select_sql.should ==
380
- "SELECT * FROM test WHERE NOT (region = 'Asia' AND name = 'Japan')"
392
+ "SELECT * FROM test WHERE (NOT (region = 'Asia' AND name = 'Japan'))"
381
393
  end
382
394
 
383
395
  specify "should corrently parenthesize when it is used twice" do
384
396
  @dataset.exclude(:region => 'Asia').exclude(:name => 'Japan').select_sql.should ==
385
- "SELECT * FROM test WHERE NOT (region = 'Asia') AND NOT (name = 'Japan')"
397
+ "SELECT * FROM test WHERE (NOT (region = 'Asia')) AND (NOT (name = 'Japan'))"
386
398
  end
387
399
 
388
400
  specify "should support proc expressions" do
389
401
  @dataset.exclude {:id == (6...12)}.sql.should ==
390
- 'SELECT * FROM test WHERE NOT ((id >= 6 AND id < 12))'
402
+ 'SELECT * FROM test WHERE (NOT ((id >= 6 AND id < 12)))'
391
403
  end
392
404
  end
393
405
 
@@ -229,7 +229,7 @@ context "Sequel::Migrator" do
229
229
 
230
230
  Sequel::Migrator.get_current_migration_version(@db).should == 5
231
231
  end
232
-
232
+
233
233
  specify "should apply migrations correctly in the down direction" do
234
234
  Sequel::Migrator.apply(@db, '.', 1, 5)
235
235
  @db.drops.should == [5555, 3333, 2222]
@@ -250,4 +250,12 @@ context "Sequel::Migrator" do
250
250
 
251
251
  Sequel::Migrator.get_current_migration_version(@db).should == 0
252
252
  end
253
+
254
+ specify "should return the target version" do
255
+ Sequel::Migrator.apply(@db, '.', 3, 2).should == 3
256
+
257
+ Sequel::Migrator.apply(@db, '.', 0).should == 0
258
+
259
+ Sequel::Migrator.apply(@db, '.').should == 5
260
+ end
253
261
  end
data/spec/model_spec.rb CHANGED
@@ -44,4 +44,15 @@ describe Sequel::Model do
44
44
  it "puts the lotion in the basket or it gets the hose again" do
45
45
  # just kidding!
46
46
  end
47
+ end
48
+
49
+ class DummyModelBased < Sequel::Model(:blog)
50
+ end
51
+
52
+ context "Sequel::Model()" do
53
+ specify "should allow reopening of descendant classes" do
54
+ proc do
55
+ eval "class DummyModelBased < Sequel::Model(:blog); end"
56
+ end.should_not raise_error
57
+ end
47
58
  end
@@ -39,14 +39,14 @@ context "PrettyTable" do
39
39
  Sequel::PrettyTable.print(@data2, [:a, :b])
40
40
  @output.rewind
41
41
  @output.read.should == \
42
- "+--+----+\n|a |b |\n+--+----+\n|23|45 |\n|45|2377|\n+--+----+\n"
42
+ "+--+----+\n|a |b |\n+--+----+\n|23| 45|\n|45|2377|\n+--+----+\n"
43
43
  end
44
44
 
45
45
  specify "should also take header width into account" do
46
46
  Sequel::PrettyTable.print(@data3, [:aaa, :bb, :c])
47
47
  @output.rewind
48
48
  @output.read.should == \
49
- "+---+--+-+\n|aaa|bb|c|\n+---+--+-+\n|1 | | |\n| |2 | |\n| | |3|\n+---+--+-+\n"
49
+ "+---+--+-+\n|aaa|bb|c|\n+---+--+-+\n| 1| | |\n| | 2| |\n| | |3|\n+---+--+-+\n"
50
50
  end
51
51
 
52
52
  specify "should print only the specified columns" do
@@ -175,6 +175,12 @@ context "Proc#to_sql" do
175
175
 
176
176
  proc {:x == (a...b)}.to_sql.should == \
177
177
  "(x >= 3 AND x < 5)"
178
+
179
+ t1 = Time.now - 4000
180
+ t2 = Time.now - 2000
181
+
182
+ proc {:stamp == (t1..t2)}.to_sql.should == \
183
+ "(stamp >= #{DS.literal(t1)} AND stamp <= #{DS.literal(t2)})"
178
184
  end
179
185
 
180
186
  specify "should support comparison to sub-queries" do
@@ -186,8 +192,11 @@ context "Proc#to_sql" do
186
192
  # proc {:id == DB[:test].select(:node_id)}.to_sql.should == \
187
193
  # "(id IN (SELECT node_id FROM test))"
188
194
 
189
- proc {:id == DB[:test].select(:node_id).filter {:active == true}}.to_sql.should == \
190
- "(id IN (SELECT node_id FROM test WHERE (active = 't')))"
195
+ # proc {:id == DB[:test].select(:node_id).filter {:active == true}}.to_sql.should == \
196
+ # "(id IN (SELECT node_id FROM test WHERE (active = 't')))"
197
+
198
+ proc {:price >= DB[:items].select(:price)}.to_sql.should == \
199
+ "(price >= (SELECT price FROM items))"
191
200
  end
192
201
 
193
202
  specify "should support comparison to arrays" do
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.4
3
3
  specification_version: 1
4
4
  name: sequel
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.2.0.1
7
- date: 2007-09-04 00:00:00 +03:00
6
+ version: 0.2.0.2
7
+ date: 2007-09-07 00:00:00 +03:00
8
8
  summary: Lightweight ORM library for Ruby
9
9
  require_paths:
10
10
  - lib