sequel_core 1.1 → 1.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,17 @@
1
+ === 1.2 (2008-02-15)
2
+
3
+ * Added support for :varchar[100] like type declarations in #create_table.
4
+
5
+ * Fixed #rename_column in mysql adapter to support types like varchar(255) (#159).
6
+
7
+ * Added support for order and limit in DELETE statement in MySQL adapter (#160).
8
+
9
+ * Added checks to Dataset#multi_insert to prevent work if no values are given (#162).
10
+
11
+ * Override ruby2ruby implementation of Proc#to_sexp which leaks memory (#161).
12
+
13
+ * Added log option, help for sequel script (#157).
14
+
1
15
  === 1.1 (2008-02-15)
2
16
 
3
17
  * Fixed Dataset#join_table to support joining of datasets (#156).
data/Rakefile CHANGED
@@ -9,7 +9,7 @@ include FileUtils
9
9
  # Configuration
10
10
  ##############################################################################
11
11
  NAME = "sequel_core"
12
- VERS = "1.1"
12
+ VERS = "1.2"
13
13
  CLEAN.include ["**/.*.sw?", "pkg/*", ".config", "doc/*", "coverage/*"]
14
14
  RDOC_OPTS = [
15
15
  "--quiet",
data/bin/sequel CHANGED
@@ -1,29 +1,76 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require 'rubygems'
4
+ require 'optparse'
5
+ require 'sequel' rescue nil
4
6
  require 'sequel_core'
5
7
  require 'sequel_model' rescue nil
8
+ require 'logger'
6
9
 
7
- usage = <<END
8
- Usage: sequel <connection URI>
9
- Sequel: Lightweight ORM library for Ruby
10
+ $uri = nil
11
+ $logfile = nil
12
+ $echo = nil
10
13
 
11
- Examples:
12
- sequel sqlite:///blog.db
13
- sequel postgres://localhost/my_blog
14
+ opts = OptionParser.new do |opts|
15
+ opts.banner = "Sequel: Lightweight ORM for Ruby"
16
+ opts.define_head "Usage: sequel <uri> [options]"
17
+ opts.separator ""
18
+ opts.separator "Examples:"
19
+ opts.separator " sequel sqlite:///blog.db"
20
+ opts.separator " sequel postgres://localhost/my_blog"
21
+
22
+ opts.separator ""
23
+ opts.separator "For more information see http://code.google.com/p/ruby-sequel"
24
+ opts.separator ""
25
+ opts.separator "Options:"
14
26
 
15
- For more information see http://code.google.com/p/ruby-sequel
16
- END
27
+ opts.on("-l", "--log logfile", "log SQL statements to log file") do |v|
28
+ $logfile = v
29
+ end
30
+
31
+ # opts.on("-e", "--echo", "echo SQL statements") do |v|
32
+ # $echo = v
33
+ # end
34
+
35
+ opts.on_tail("-?", "--help", "Show this message") do
36
+ puts opts
37
+ exit
38
+ end
39
+
40
+ opts.on_tail("-v", "--version", "Show version") do
41
+ class << Gem; attr_accessor :loaded_specs; end
42
+ specs = Gem.loaded_specs['sequel']
43
+ puts "sequel #{specs.version} (#{specs.date.strftime '%Y-%m-%d'})"
44
+ specs = Gem.loaded_specs['sequel_core']
45
+ puts "sequel_core #{specs.version} (#{specs.date.strftime '%Y-%m-%d'})"
46
+ begin
47
+ specs = Gem.loaded_specs['sequel_model']
48
+ puts "sequel_model #{specs.version} (#{specs.date.strftime '%Y-%m-%d'})"
49
+ rescue
50
+ end
51
+ exit
52
+ end
53
+ end
54
+ opts.parse!
17
55
 
18
56
  db = ARGV.shift
19
57
 
20
- if db.nil? || db.empty?
21
- puts usage
58
+ if db.blank?
59
+ puts opts
22
60
  exit
23
61
  end
24
62
 
63
+ db_opts = {}
64
+ if $logfile
65
+ db_opts[:logger] = Logger.new($logfile)
66
+ end
67
+ if $echo
68
+ db_opts[:echo] = true
69
+ end
70
+
25
71
  begin
26
- DB = Sequel.connect db
72
+ puts "db_opts = #{db_opts.inspect}"
73
+ DB = Sequel.connect db, db_opts
27
74
  rescue => e
28
75
  puts e.message
29
76
  exit
@@ -40,3 +87,85 @@ end
40
87
  require 'irb'
41
88
  puts "Your database is stored in DB..."
42
89
  IRB.start
90
+
91
+ __END__
92
+
93
+ #!/usr/bin/env ruby
94
+
95
+ require 'rubygems'
96
+ require 'optparse'
97
+ require 'bulkmail'
98
+
99
+ $helo = nil
100
+ $from = nil
101
+ $recipients = []
102
+ $content = nil
103
+ $delay = 60..300
104
+
105
+ opts = OptionParser.new do |opts|
106
+ opts.banner = "Usage: bulkmail <options>"
107
+ opts.define_head "Simple bulk-mailer."
108
+ opts.separator ""
109
+ opts.separator "Options:"
110
+
111
+ opts.on("-h", "--helo HOSTNAME", "HELO host name.") do |v|
112
+ $helo = v
113
+ end
114
+
115
+ opts.on("-r", "--recipients filename", "Recipients file name") do |v|
116
+ $recipients = IO.readlines(v).map {|l| l =~ /(.*)(\r\n|\n)$/ ? $1 : l}.compact
117
+ end
118
+
119
+ opts.on("-c", "--content filename", "Content file name") do |v|
120
+ $content = IO.read(v)
121
+ end
122
+
123
+ opts.on("-f", "--from from", "From address") do |v|
124
+ $from = v
125
+ end
126
+
127
+ opts.on('-n', "--nodelay", "No delay") do |v|
128
+ $delay = 0
129
+ end
130
+
131
+ # No argument, shows at tail. This will print an options summary.
132
+ # Try it and see!
133
+ opts.on_tail("-?", "--help", "Show this message") do
134
+ puts opts
135
+ exit
136
+ end
137
+
138
+ # Another typical switch to print the version.
139
+ opts.on_tail("-v", "--version", "Show version") do
140
+ class << Gem; attr_accessor :loaded_specs; end
141
+ specs = Gem.loaded_specs['bulkmail']
142
+ puts "bulkmail #{specs.version} (#{specs.date.strftime '%Y-%m-%d'})"
143
+ exit
144
+ end
145
+ end
146
+
147
+ begin
148
+ opts.parse! ARGV
149
+ rescue => e
150
+ puts e.message
151
+ puts e.backtrace.first
152
+ exit
153
+ end
154
+
155
+ unless $content
156
+ puts opts
157
+ exit
158
+ end
159
+
160
+ trap('INT') {exit}
161
+
162
+ puts "Please hold on..."
163
+
164
+ sender = BulkMail::Sender.new({
165
+ :list => $recipients,
166
+ :from => $from,
167
+ :message => $content,
168
+ :helo => $helo,
169
+ :delay => $delay
170
+ })
171
+ sender.start
@@ -141,9 +141,9 @@ module Sequel
141
141
  def alter_table_sql(table, op)
142
142
  case op[:op]
143
143
  when :rename_column
144
- "ALTER TABLE #{table} CHANGE COLUMN #{literal(op[:name])} #{literal(op[:new_name])} #{op[:type]}"
144
+ "ALTER TABLE #{table} CHANGE COLUMN #{literal(op[:name])} #{literal(op[:new_name])} #{type_literal(op[:type])}"
145
145
  when :set_column_type
146
- "ALTER TABLE #{table} CHANGE COLUMN #{literal(op[:name])} #{literal(op[:name])} #{op[:type]}"
146
+ "ALTER TABLE #{table} CHANGE COLUMN #{literal(op[:name])} #{literal(op[:name])} #{type_literal(op[:type])}"
147
147
  when :drop_index
148
148
  "DROP INDEX #{default_index_name(table, op[:columns])} ON #{table}"
149
149
  else
@@ -316,13 +316,26 @@ module Sequel
316
316
  # MySQL supports ORDER and LIMIT clauses in UPDATE statements.
317
317
  def update_sql(values, opts = nil)
318
318
  sql = super
319
-
320
319
  opts = opts ? @opts.merge(opts) : @opts
321
320
 
322
321
  if order = opts[:order]
323
322
  sql << " ORDER BY #{column_list(order)}"
324
323
  end
324
+ if limit = opts[:limit]
325
+ sql << " LIMIT #{limit}"
326
+ end
325
327
 
328
+ sql
329
+ end
330
+
331
+ # MySQL supports ORDER and LIMIT clauses in DELETE statements.
332
+ def delete_sql(opts = nil)
333
+ sql = super
334
+ opts = opts ? @opts.merge(opts) : @opts
335
+
336
+ if order = opts[:order]
337
+ sql << " ORDER BY #{column_list(order)}"
338
+ end
326
339
  if limit = opts[:limit]
327
340
  sql << " LIMIT #{limit}"
328
341
  end
@@ -242,15 +242,20 @@ module Sequel
242
242
  # # this will commit every 50 records
243
243
  # dataset.multi_insert(lots_of_records, :slice => 50)
244
244
  def multi_insert(*args)
245
- if args[0].is_a?(Array) && args[1].is_a?(Array)
245
+ if args.empty?
246
+ return
247
+ elsif args[0].is_a?(Array) && args[1].is_a?(Array)
246
248
  columns, values, opts = *args
247
249
  else
248
250
  # we assume that an array of hashes is given
249
251
  hashes, opts = *args
252
+ return if hashes.empty?
250
253
  columns = hashes.first.keys
251
254
  # convert the hashes into arrays
252
255
  values = hashes.map {|h| columns.map {|c| h[c]}}
253
256
  end
257
+ # make sure there's work to do
258
+ return if columns.empty? || values.empty?
254
259
 
255
260
  slice_size = opts && (opts[:commit_every] || opts[:slice])
256
261
 
@@ -371,12 +371,12 @@ rescue Exception
371
371
  end
372
372
 
373
373
  class Proc
374
- # replacement for Proc#to_sexp, if it's not available
375
- unless instance_methods.include?('to_sexp')
376
- def to_sexp
377
- block = self
378
- c = Class.new {define_method(:m, &block)}
379
- ParseTree.translate(c, :m)[2]
380
- end
374
+ # replacement for Proc#to_sexp as defined in ruby2ruby.
375
+ # see also: http://rubyforge.org/tracker/index.php?func=detail&aid=18095&group_id=1513&atid=5921
376
+ # The ruby2ruby implementation leaks memory, so we fix it.
377
+ def to_sexp
378
+ block = self
379
+ c = Class.new {define_method(:m, &block)}
380
+ ParseTree.translate(c, :m)[2]
381
381
  end
382
382
  end
@@ -550,7 +550,7 @@ module Sequel
550
550
  "INSERT INTO #{table} (#{columns}) VALUES (#{literal(r)})"
551
551
  end
552
552
  end
553
-
553
+
554
554
  # Formats an UPDATE statement using the given values.
555
555
  #
556
556
  # dataset.update_sql(:price => 100, :category => 'software') #=>
@@ -45,6 +45,10 @@ module Sequel
45
45
  schema_utility_dataset.literal(v)
46
46
  end
47
47
 
48
+ def type_literal(t)
49
+ t.is_a?(Symbol) ? t.to_s : literal(t)
50
+ end
51
+
48
52
  def expression_list(*args, &block)
49
53
  schema_utility_dataset.expression_list(*args, &block)
50
54
  end
@@ -53,7 +57,7 @@ module Sequel
53
57
  if column[:type] == :check
54
58
  return constraint_definition_sql(column)
55
59
  end
56
- sql = "#{literal(column[:name].to_sym)} #{TYPES[column[:type]]}"
60
+ sql = "#{literal(column[:name].to_sym)} #{type_literal(TYPES[column[:type]])}"
57
61
  column[:size] ||= 255 if column[:type] == :varchar
58
62
  elements = column[:size] || column[:elements]
59
63
  sql << "(#{literal(elements)})" if elements
@@ -319,6 +319,17 @@ context "A MySQL database" do
319
319
  @db[:test2].first[:zyx].should == 'qqqq'
320
320
  end
321
321
 
322
+ specify "should support rename_column operations with types like varchar(255)" do
323
+ @db[:test2].delete
324
+ @db.add_column :test2, :tre, :text
325
+ @db[:test2] << {:name => 'mmm', :value => 111, :tre => 'qqqq'}
326
+
327
+ @db[:test2].columns.should == [:name, :value, :zyx, :tre]
328
+ @db.rename_column :test2, :tre, :ert, :type => :varchar[255]
329
+ @db[:test2].columns.should == [:name, :value, :zyx, :ert]
330
+ @db[:test2].first[:ert].should == 'qqqq'
331
+ end
332
+
322
333
  specify "should support set_column_type operations" do
323
334
  @db.add_column :test2, :xyz, :float
324
335
  @db[:test2].delete
data/spec/dataset_spec.rb CHANGED
@@ -1050,7 +1050,7 @@ end
1050
1050
  context "Dataset#empty?" do
1051
1051
  specify "should return true if records exist in the dataset" do
1052
1052
  @db = Sequel::Database.new
1053
- @db.meta_def(:execute) {|sql| puts "blah";@sqls ||=[]; @sqls << sql}
1053
+ @db.meta_def(:execute) {|sql| @sqls ||=[]; @sqls << sql}
1054
1054
  @db.meta_def(:sqls) {@sqls ||= []}
1055
1055
 
1056
1056
  $cccc = Class.new(Sequel::Dataset) do
@@ -2171,6 +2171,35 @@ context "Dataset#multi_insert" do
2171
2171
  'COMMIT'
2172
2172
  ]
2173
2173
  end
2174
+
2175
+ specify "should not do anything if no columns or values are given" do
2176
+ @ds.multi_insert
2177
+ @db.sqls.should be_nil
2178
+
2179
+ @ds.multi_insert([])
2180
+ @db.sqls.should be_nil
2181
+
2182
+ @ds.multi_insert([], [])
2183
+ @db.sqls.should be_nil
2184
+
2185
+ @ds.multi_insert([{}, {}])
2186
+ @db.sqls.should be_nil
2187
+
2188
+ @ds.multi_insert([:a, :b], [])
2189
+ @db.sqls.should be_nil
2190
+
2191
+ @ds.multi_insert([:x, :y], [[1, 2], [3, 4], [5, 6]], :slice => 2)
2192
+ @db.sqls.should == [
2193
+ 'BEGIN',
2194
+ "INSERT INTO items (x, y) VALUES (1, 2)",
2195
+ "INSERT INTO items (x, y) VALUES (3, 4)",
2196
+ 'COMMIT',
2197
+ 'BEGIN',
2198
+ "INSERT INTO items (x, y) VALUES (5, 6)",
2199
+ 'COMMIT'
2200
+ ]
2201
+ end
2202
+
2174
2203
  end
2175
2204
 
2176
2205
  context "Dataset#query" do
data/spec/schema_spec.rb CHANGED
@@ -94,6 +94,13 @@ context "DB#create_table" do
94
94
  end
95
95
  @db.sqls.should == ["CREATE TABLE cats (name varchar(51))"]
96
96
  end
97
+
98
+ specify "should accept varchar size as sql function" do
99
+ @db.create_table(:cats) do
100
+ column :name, :varchar[102]
101
+ end
102
+ @db.sqls.should == ["CREATE TABLE cats (name varchar(102))"]
103
+ end
97
104
 
98
105
  specify "should accept foreign keys" do
99
106
  @db.create_table(:cats) do
@@ -59,46 +59,6 @@ context "Sequelizer without Ruby2Ruby" do
59
59
  end
60
60
  end
61
61
 
62
- context "Proc without #to_sexp method (Ruby2Ruby missing)" do
63
- setup do
64
- class Proc
65
- alias_method :orig_to_sexp, :to_sexp
66
- remove_method :to_sexp
67
- end
68
-
69
- module Kernel
70
- alias_method :orig_sq_require, :require
71
- def require(name); raise LoadError if name == 'ruby2ruby'; end
72
- end
73
- old_verbose = $VERBOSE
74
- $VERBOSE = nil
75
- load(File.join(File.dirname(__FILE__), '../lib/sequel_core/dataset/sequelizer.rb'))
76
- $VERBOSE = old_verbose
77
- @db = Sequel::Database.new
78
- @ds = @db[:items]
79
- end
80
-
81
- teardown do
82
- module Kernel
83
- alias_method :require, :orig_sq_require
84
- end
85
- old_verbose = $VERBOSE
86
- $VERBOSE = nil
87
- load(File.join(File.dirname(__FILE__), '../lib/sequel_core/dataset/sequelizer.rb'))
88
- $VERBOSE = old_verbose
89
-
90
- class Proc
91
- alias_method :to_sexp, :orig_to_sexp
92
- end
93
- end
94
-
95
- specify "should define a replacement Proc#to_sexp implementation" do
96
- pr = proc {1 + 1}
97
- proc {pr.to_sexp}.should_not raise_error
98
- pr.to_sexp.should == [:bmethod, nil, [:call, [:lit, 1], :+, [:array, [:lit, 1]]]]
99
- end
100
- end
101
-
102
62
  context "Proc#to_sql" do
103
63
  DB = Sequel::Database.new
104
64
  DS = DB[:items]
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sequel_core
3
3
  version: !ruby/object:Gem::Version
4
- version: "1.1"
4
+ version: "1.2"
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: 2008-02-15 00:00:00 +02:00
12
+ date: 2008-02-16 00:00:00 +02:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency