sequel_core 1.1 → 1.2

Sign up to get free protection for your applications and to get access to all the features.
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