sequel 0.2.0.1 → 0.2.0.2

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 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