sequel 2.10.0 → 2.11.0

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.
Files changed (78) hide show
  1. data/CHANGELOG +51 -1
  2. data/README.rdoc +2 -2
  3. data/Rakefile +2 -2
  4. data/doc/advanced_associations.rdoc +6 -18
  5. data/doc/release_notes/1.0.txt +38 -0
  6. data/doc/release_notes/1.1.txt +143 -0
  7. data/doc/release_notes/1.3.txt +101 -0
  8. data/doc/release_notes/1.4.0.txt +53 -0
  9. data/doc/release_notes/1.5.0.txt +155 -0
  10. data/doc/release_notes/2.0.0.txt +298 -0
  11. data/doc/release_notes/2.1.0.txt +271 -0
  12. data/doc/release_notes/2.10.0.txt +328 -0
  13. data/doc/release_notes/2.11.0.txt +215 -0
  14. data/doc/release_notes/2.2.0.txt +253 -0
  15. data/doc/release_notes/2.3.0.txt +88 -0
  16. data/doc/release_notes/2.4.0.txt +106 -0
  17. data/doc/release_notes/2.5.0.txt +137 -0
  18. data/doc/release_notes/2.6.0.txt +157 -0
  19. data/doc/release_notes/2.7.0.txt +166 -0
  20. data/doc/release_notes/2.8.0.txt +171 -0
  21. data/doc/release_notes/2.9.0.txt +97 -0
  22. data/lib/sequel_core/adapters/ado.rb +3 -0
  23. data/lib/sequel_core/adapters/db2.rb +0 -11
  24. data/lib/sequel_core/adapters/dbi.rb +0 -11
  25. data/lib/sequel_core/adapters/do.rb +0 -12
  26. data/lib/sequel_core/adapters/firebird.rb +21 -16
  27. data/lib/sequel_core/adapters/informix.rb +1 -11
  28. data/lib/sequel_core/adapters/jdbc.rb +1 -13
  29. data/lib/sequel_core/adapters/jdbc/h2.rb +3 -11
  30. data/lib/sequel_core/adapters/jdbc/mysql.rb +0 -17
  31. data/lib/sequel_core/adapters/jdbc/postgresql.rb +3 -15
  32. data/lib/sequel_core/adapters/mysql.rb +31 -27
  33. data/lib/sequel_core/adapters/odbc.rb +34 -28
  34. data/lib/sequel_core/adapters/openbase.rb +0 -11
  35. data/lib/sequel_core/adapters/oracle.rb +11 -9
  36. data/lib/sequel_core/adapters/postgres.rb +14 -17
  37. data/lib/sequel_core/adapters/shared/mssql.rb +6 -15
  38. data/lib/sequel_core/adapters/shared/mysql.rb +29 -14
  39. data/lib/sequel_core/adapters/shared/oracle.rb +4 -0
  40. data/lib/sequel_core/adapters/shared/postgres.rb +30 -35
  41. data/lib/sequel_core/adapters/shared/progress.rb +4 -0
  42. data/lib/sequel_core/adapters/shared/sqlite.rb +73 -13
  43. data/lib/sequel_core/adapters/sqlite.rb +8 -18
  44. data/lib/sequel_core/adapters/utils/date_format.rb +21 -0
  45. data/lib/sequel_core/{dataset → adapters/utils}/stored_procedures.rb +0 -0
  46. data/lib/sequel_core/{dataset → adapters/utils}/unsupported.rb +0 -0
  47. data/lib/sequel_core/core_ext.rb +1 -1
  48. data/lib/sequel_core/core_sql.rb +9 -4
  49. data/lib/sequel_core/database.rb +63 -62
  50. data/lib/sequel_core/dataset.rb +9 -4
  51. data/lib/sequel_core/dataset/convenience.rb +10 -9
  52. data/lib/sequel_core/dataset/prepared_statements.rb +1 -1
  53. data/lib/sequel_core/dataset/sql.rb +130 -36
  54. data/lib/sequel_core/schema/sql.rb +2 -2
  55. data/lib/sequel_core/sql.rb +44 -51
  56. data/lib/sequel_core/version.rb +1 -1
  57. data/lib/sequel_model/associations.rb +25 -17
  58. data/lib/sequel_model/base.rb +35 -7
  59. data/lib/sequel_model/caching.rb +1 -6
  60. data/lib/sequel_model/record.rb +23 -5
  61. data/lib/sequel_model/validations.rb +20 -5
  62. data/spec/adapters/firebird_spec.rb +6 -1
  63. data/spec/adapters/mysql_spec.rb +12 -0
  64. data/spec/adapters/postgres_spec.rb +2 -2
  65. data/spec/adapters/sqlite_spec.rb +81 -2
  66. data/spec/integration/dataset_test.rb +2 -2
  67. data/spec/integration/type_test.rb +12 -2
  68. data/spec/sequel_core/core_sql_spec.rb +46 -12
  69. data/spec/sequel_core/database_spec.rb +24 -12
  70. data/spec/sequel_core/dataset_spec.rb +82 -32
  71. data/spec/sequel_core/schema_spec.rb +16 -0
  72. data/spec/sequel_model/associations_spec.rb +89 -0
  73. data/spec/sequel_model/base_spec.rb +66 -0
  74. data/spec/sequel_model/eager_loading_spec.rb +32 -0
  75. data/spec/sequel_model/record_spec.rb +9 -9
  76. data/spec/sequel_model/spec_helper.rb +3 -0
  77. data/spec/sequel_model/validations_spec.rb +63 -3
  78. metadata +41 -4
@@ -75,17 +75,6 @@ module Sequel
75
75
  class Dataset < Sequel::Dataset
76
76
  MAX_COL_SIZE = 256
77
77
 
78
- def literal(v)
79
- case v
80
- when Time
81
- literal(v.iso8601)
82
- when Date, DateTime
83
- literal(v.to_s)
84
- else
85
- super
86
- end
87
- end
88
-
89
78
  def fetch_rows(sql)
90
79
  execute(sql) do |sth|
91
80
  @column_info = get_column_info(sth)
@@ -76,17 +76,6 @@ module Sequel
76
76
  end
77
77
 
78
78
  class Dataset < Sequel::Dataset
79
- def literal(v)
80
- case v
81
- when Time
82
- literal(v.iso8601)
83
- when Date, DateTime
84
- literal(v.to_s)
85
- else
86
- super
87
- end
88
- end
89
-
90
79
  def fetch_rows(sql, &block)
91
80
  execute(sql) do |s|
92
81
  begin
@@ -175,18 +175,6 @@ module Sequel
175
175
 
176
176
  # Dataset class for Sequel::DataObjects::Database objects.
177
177
  class Dataset < Sequel::Dataset
178
- # Handle the usual time class overrides.
179
- def literal(v)
180
- case v
181
- when Time
182
- literal(v.iso8601)
183
- when Date, DateTime
184
- literal(v.to_s)
185
- else
186
- super
187
- end
188
- end
189
-
190
178
  # Execute the SQL on the database and yield the rows as hashes
191
179
  # with symbol keys.
192
180
  def fetch_rows(sql)
@@ -1,4 +1,5 @@
1
1
  require 'fb'
2
+ require 'sequel_core/adapters/utils/unsupported'
2
3
 
3
4
  module Sequel
4
5
  # The Sequel Firebird adapter requires the ruby fb driver located at
@@ -214,6 +215,7 @@ module Sequel
214
215
 
215
216
  BOOL_TRUE = '1'.freeze
216
217
  BOOL_FALSE = '0'.freeze
218
+ NULL = LiteralString.new('NULL').freeze
217
219
  COMMA_SEPARATOR = ', '.freeze
218
220
  FIREBIRD_TIMESTAMP_FORMAT = "TIMESTAMP '%Y-%m-%d %H:%M:%S".freeze
219
221
  SELECT_CLAUSE_ORDER = %w'distinct limit columns from join where group having compounds order'.freeze
@@ -239,7 +241,7 @@ module Sequel
239
241
  # Insert given values into the database.
240
242
  def insert(*values)
241
243
  if !@opts[:sql]
242
- single_value(:sql=>insert_returning_pk_sql(*values))
244
+ single_value(default_server_opts(:sql=>insert_returning_pk_sql(*values)))
243
245
  else
244
246
  execute_insert(insert_sql(*values), :table=>opts[:from].first,
245
247
  :values=>values.size == 1 ? values.first : values)
@@ -249,7 +251,7 @@ module Sequel
249
251
  # Use the RETURNING clause to return the primary key of the inserted record, if it exists
250
252
  def insert_returning_pk_sql(*values)
251
253
  pk = db.primary_key(opts[:from].first)
252
- insert_returning_sql(pk ? Sequel::SQL::Identifier.new(pk) : 'NULL'.lit, *values)
254
+ insert_returning_sql(pk ? Sequel::SQL::Identifier.new(pk) : NULL, *values)
253
255
  end
254
256
 
255
257
  # Use the RETURNING clause to return the columns listed in returning.
@@ -259,20 +261,7 @@ module Sequel
259
261
 
260
262
  # Insert a record returning the record inserted
261
263
  def insert_select(*values)
262
- single_record(:naked=>true, :sql=>insert_returning_sql(nil, *values))
263
- end
264
-
265
- def literal(v)
266
- case v
267
- when Time, DateTime
268
- "#{v.strftime(FIREBIRD_TIMESTAMP_FORMAT)}.#{sprintf("%04d",v.usec / 100)}'"
269
- when TrueClass
270
- BOOL_TRUE
271
- when FalseClass
272
- BOOL_FALSE
273
- else
274
- super
275
- end
264
+ single_record(default_server_opts(:naked=>true, :sql=>insert_returning_sql(nil, *values)))
276
265
  end
277
266
 
278
267
  # The order of clauses in the SELECT SQL statement
@@ -293,6 +282,22 @@ module Sequel
293
282
  m
294
283
  end
295
284
  end
285
+
286
+ def literal_datetime(v)
287
+ "#{v.strftime(FIREBIRD_TIMESTAMP_FORMAT)}.#{sprintf("%04d",(v.sec_fraction * 864000000))}'"
288
+ end
289
+
290
+ def literal_false
291
+ BOOL_FALSE
292
+ end
293
+
294
+ def literal_time(v)
295
+ "#{v.strftime(FIREBIRD_TIMESTAMP_FORMAT)}.#{sprintf("%04d",v.usec / 100)}'"
296
+ end
297
+
298
+ def literal_true
299
+ BOOL_TRUE
300
+ end
296
301
  end
297
302
  end
298
303
  end
@@ -1,3 +1,4 @@
1
+ require 'sequel_core/adapters/utils/unsupported'
1
2
  require 'informix'
2
3
 
3
4
  module Sequel
@@ -39,17 +40,6 @@ module Sequel
39
40
 
40
41
  SELECT_CLAUSE_ORDER = %w'limit distinct columns from join where having group compounds order'.freeze
41
42
 
42
- def literal(v)
43
- case v
44
- when Time
45
- literal(v.iso8601)
46
- when Date, DateTime
47
- literal(v.to_s)
48
- else
49
- super
50
- end
51
- end
52
-
53
43
  def fetch_rows(sql, &block)
54
44
  execute(sql) do |cursor|
55
45
  begin
@@ -1,5 +1,5 @@
1
1
  require 'java'
2
- require 'sequel_core/dataset/stored_procedures'
2
+ require 'sequel_core/adapters/utils/stored_procedures'
3
3
 
4
4
  module Sequel
5
5
  # Houses Sequel's JDBC support when running on JRuby.
@@ -414,18 +414,6 @@ module Sequel
414
414
  self
415
415
  end
416
416
 
417
- # Use the ISO values for dates and times.
418
- def literal(v)
419
- case v
420
- when Time
421
- literal(v.iso8601)
422
- when Date, DateTime, Java::JavaSql::Timestamp, Java::JavaSql::Date
423
- literal(v.to_s)
424
- else
425
- super
426
- end
427
- end
428
-
429
417
  # Create a named prepared statement that is stored in the
430
418
  # database (and connection) for reuse.
431
419
  def prepare(type, name=nil, values=nil)
@@ -1,3 +1,5 @@
1
+ require 'sequel_core/adapters/utils/date_format'
2
+
1
3
  module Sequel
2
4
  module JDBC
3
5
  # Database and Dataset support for H2 databases accessed via JDBC.
@@ -52,17 +54,7 @@ module Sequel
52
54
 
53
55
  # Dataset class for H2 datasets accessed via JDBC.
54
56
  class Dataset < JDBC::Dataset
55
- # Use H2 syntax for Date, DateTime, and Time types.
56
- def literal(v)
57
- case v
58
- when Date
59
- v.strftime("DATE '%Y-%m-%d'")
60
- when DateTime, Time
61
- v.strftime("TIMESTAMP '%Y-%m-%d %H:%M:%S'")
62
- else
63
- super
64
- end
65
- end
57
+ include Dataset::SQLStandardDateFormat
66
58
  end
67
59
  end
68
60
  end
@@ -46,27 +46,10 @@ module Sequel
46
46
  execute_insert(insert_sql(*values))
47
47
  end
48
48
 
49
- # Handle time types correctly
50
- def literal(v)
51
- case v
52
- when Time, DateTime
53
- v.strftime("'%Y-%m-%d %H:%M:%S'")
54
- else
55
- super
56
- end
57
- end
58
-
59
49
  # Use execute_insert to execute the replace_sql.
60
50
  def replace(*args)
61
51
  execute_insert(replace_sql(*args))
62
52
  end
63
-
64
- private
65
-
66
- # Call execute_insert on the database.
67
- def execute_insert(sql, opts={})
68
- @db.execute_insert(sql, {:server=>@opts[:server] || :default}.merge(opts))
69
- end
70
53
  end
71
54
  end
72
55
  end
@@ -91,21 +91,9 @@ module Sequel
91
91
  ps
92
92
  end
93
93
 
94
- # Convert Java::JavaSql::Timestamps correctly, and handle Strings
95
- # similar to the native postgres adapter.
96
- def literal(v)
97
- case v
98
- when LiteralString
99
- v
100
- when SQL::Blob
101
- super
102
- when String
103
- db.synchronize{|c| "'#{c.escape_string(v)}'"}
104
- when Java::JavaSql::Timestamp
105
- "TIMESTAMP #{literal(v.to_s)}"
106
- else
107
- super
108
- end
94
+ # Literalize strings similar to the native postgres adapter
95
+ def literal_string(v)
96
+ db.synchronize{|c| "'#{c.escape_string(v)}'"}
109
97
  end
110
98
  end
111
99
  end
@@ -1,6 +1,6 @@
1
1
  require 'mysql'
2
2
  require 'sequel_core/adapters/shared/mysql'
3
- require 'sequel_core/dataset/stored_procedures'
3
+ require 'sequel_core/adapters/utils/stored_procedures'
4
4
 
5
5
  module Sequel
6
6
  # Module for holding all MySQL-related classes and modules for Sequel.
@@ -27,10 +27,10 @@ module Sequel
27
27
  246 => :to_d, # MYSQL_TYPE_NEWDECIMAL
28
28
  247 => :to_i, # MYSQL_TYPE_ENUM
29
29
  248 => :to_i, # MYSQL_TYPE_SET
30
- 249 => :to_blob, # MYSQL_TYPE_TINY_BLOB
31
- 250 => :to_blob, # MYSQL_TYPE_MEDIUM_BLOB
32
- 251 => :to_blob, # MYSQL_TYPE_LONG_BLOB
33
- 252 => :to_blob, # MYSQL_TYPE_BLOB
30
+ 249 => :to_sequel_blob, # MYSQL_TYPE_TINY_BLOB
31
+ 250 => :to_sequel_blob, # MYSQL_TYPE_MEDIUM_BLOB
32
+ 251 => :to_sequel_blob, # MYSQL_TYPE_LONG_BLOB
33
+ 252 => :to_sequel_blob, # MYSQL_TYPE_BLOB
34
34
  # 253 => :to_s, # MYSQL_TYPE_VAR_STRING
35
35
  # 254 => :to_s, # MYSQL_TYPE_STRING
36
36
  # 255 => :to_s # MYSQL_TYPE_GEOMETRY
@@ -45,19 +45,30 @@ module Sequel
45
45
  # Support stored procedures on MySQL
46
46
  def call_sproc(name, opts={}, &block)
47
47
  args = opts[:args] || []
48
- execute("CALL #{name}(#{literal(args) unless args.empty?})", opts.merge(:sproc=>false), &block)
48
+ execute("CALL #{name}#{args.empty? ? '()' : literal(args)}", opts.merge(:sproc=>false), &block)
49
49
  end
50
50
 
51
51
  # Connect to the database. In addition to the usual database options,
52
52
  # the following options have effect:
53
53
  #
54
- # * :encoding, :charset - Set all the related character sets for this
54
+ # * :auto_is_null - Set to true to use MySQL default behavior of having
55
+ # a filter for an autoincrement column equals NULL to return the last
56
+ # inserted row.
57
+ # * :charset - Same as :encoding (:encoding takes precendence)
58
+ # * :compress - Set to false to not compress results from the server
59
+ # * :encoding - Set all the related character sets for this
55
60
  # connection (connection, client, database, server, and results).
56
61
  # * :socket - Use a unix socket file instead of connecting via TCP/IP.
62
+ # * :timeout - Set the timeout in seconds before the server will
63
+ # disconnect this connection.
57
64
  def connect(server)
58
65
  opts = server_opts(server)
59
66
  conn = Mysql.init
60
67
  conn.options(Mysql::OPT_LOCAL_INFILE, "client")
68
+ if encoding = opts[:encoding] || opts[:charset]
69
+ # set charset _before_ the connect. using an option instead of "SET (NAMES|CHARACTER_SET_*)" works across reconnects
70
+ conn.options(Mysql::SET_CHARSET_NAME, encoding)
71
+ end
61
72
  conn.real_connect(
62
73
  opts[:host] || 'localhost',
63
74
  opts[:user],
@@ -67,16 +78,16 @@ module Sequel
67
78
  opts[:socket],
68
79
  Mysql::CLIENT_MULTI_RESULTS +
69
80
  Mysql::CLIENT_MULTI_STATEMENTS +
70
- Mysql::CLIENT_COMPRESS
81
+ (opts[:compress] == false ? 0 : Mysql::CLIENT_COMPRESS)
71
82
  )
83
+
84
+ # increase timeout so mysql server doesn't disconnect us
85
+ conn.query("set @@wait_timeout = #{opts[:timeout] || 2592000}")
86
+
87
+ # By default, MySQL 'where id is null' selects the last inserted id
88
+ conn.query("set SQL_AUTO_IS_NULL=0") unless opts[:auto_is_null]
89
+
72
90
  conn.query_with_result = false
73
- if encoding = opts[:encoding] || opts[:charset]
74
- conn.query("set character_set_connection = '#{encoding}'")
75
- conn.query("set character_set_client = '#{encoding}'")
76
- conn.query("set character_set_database = '#{encoding}'")
77
- conn.query("set character_set_server = '#{encoding}'")
78
- conn.query("set character_set_results = '#{encoding}'")
79
- end
80
91
  conn.meta_eval{attr_accessor :prepared_statements}
81
92
  conn.prepared_statements = {}
82
93
  conn.reconnect = true
@@ -288,18 +299,6 @@ module Sequel
288
299
  execute_dui(insert_sql(*values)){|c| c.insert_id}
289
300
  end
290
301
 
291
- # Handle correct quoting of strings using ::MySQL.quote.
292
- def literal(v)
293
- case v
294
- when LiteralString
295
- v
296
- when String
297
- "'#{::Mysql.quote(v)}'"
298
- else
299
- super
300
- end
301
- end
302
-
303
302
  # Store the given type of prepared statement in the associated database
304
303
  # with the given name.
305
304
  def prepare(type, name=nil, values=nil)
@@ -349,6 +348,11 @@ module Sequel
349
348
  super(sql, {:type=>:dui}.merge(opts), &block)
350
349
  end
351
350
 
351
+ # Handle correct quoting of strings using ::MySQL.quote.
352
+ def literal_string(v)
353
+ "'#{::Mysql.quote(v)}'"
354
+ end
355
+
352
356
  # Extend the dataset with the MySQL stored procedure methods.
353
357
  def prepare_extend_sproc(ds)
354
358
  ds.extend(StoredProcedureMethods)
@@ -100,25 +100,6 @@ module Sequel
100
100
  ODBC_TIMESTAMP_AFTER_SECONDS =
101
101
  ODBC_TIMESTAMP_FORMAT.index( '%S' ).succ - ODBC_TIMESTAMP_FORMAT.length
102
102
  ODBC_DATE_FORMAT = "{d '%Y-%m-%d'}".freeze
103
-
104
- def literal(v)
105
- case v
106
- when true
107
- BOOL_TRUE
108
- when false
109
- BOOL_FALSE
110
- when Time, DateTime
111
- formatted = v.strftime(ODBC_TIMESTAMP_FORMAT)
112
- usec = (Time === v ? v.usec : (v.sec_fraction * 86400000000))
113
- formatted.insert(ODBC_TIMESTAMP_AFTER_SECONDS, ".#{(usec.to_f/1000).round}") if usec >= 1000
114
- formatted
115
- when Date
116
- v.strftime(ODBC_DATE_FORMAT)
117
- else
118
- super
119
- end
120
- end
121
-
122
103
  UNTITLED_COLUMN = 'untitled_%d'.freeze
123
104
 
124
105
  def fetch_rows(sql, &block)
@@ -141,15 +122,7 @@ module Sequel
141
122
  end
142
123
 
143
124
  private
144
-
145
- def hash_row(row)
146
- hash = {}
147
- row.each_with_index do |v, idx|
148
- hash[@columns[idx]] = convert_odbc_value(v)
149
- end
150
- hash
151
- end
152
-
125
+
153
126
  def convert_odbc_value(v)
154
127
  # When fetching a result set, the Ruby ODBC driver converts all ODBC
155
128
  # SQL types to an equivalent Ruby type; with the exception of
@@ -169,6 +142,39 @@ module Sequel
169
142
  v
170
143
  end
171
144
  end
145
+
146
+ def hash_row(row)
147
+ hash = {}
148
+ row.each_with_index do |v, idx|
149
+ hash[@columns[idx]] = convert_odbc_value(v)
150
+ end
151
+ hash
152
+ end
153
+
154
+ def literal_date(v)
155
+ v.strftime(ODBC_DATE_FORMAT)
156
+ end
157
+
158
+ def literal_datetime(v)
159
+ formatted = v.strftime(ODBC_TIMESTAMP_FORMAT)
160
+ usec = v.sec_fraction * 86400000000
161
+ formatted.insert(ODBC_TIMESTAMP_AFTER_SECONDS, ".#{(usec.to_f/1000).round}") if usec >= 1000
162
+ formatted
163
+ end
164
+
165
+ def literal_false
166
+ BOOL_FALSE
167
+ end
168
+
169
+ def literal_true
170
+ BOOL_TRUE
171
+ end
172
+
173
+ def literal_time(v)
174
+ formatted = v.strftime(ODBC_TIMESTAMP_FORMAT)
175
+ formatted.insert(ODBC_TIMESTAMP_AFTER_SECONDS, ".#{(v.usec.to_f/1000).round}") if usec >= 1000
176
+ formatted
177
+ end
172
178
  end
173
179
  end
174
180
  end