sequel 2.11.0 → 2.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (162) hide show
  1. data/CHANGELOG +168 -0
  2. data/README.rdoc +77 -95
  3. data/Rakefile +100 -80
  4. data/bin/sequel +2 -1
  5. data/doc/advanced_associations.rdoc +23 -32
  6. data/doc/cheat_sheet.rdoc +23 -40
  7. data/doc/dataset_filtering.rdoc +6 -6
  8. data/doc/prepared_statements.rdoc +22 -22
  9. data/doc/release_notes/2.12.0.txt +534 -0
  10. data/doc/schema.rdoc +3 -1
  11. data/doc/sharding.rdoc +8 -8
  12. data/doc/virtual_rows.rdoc +65 -0
  13. data/lib/sequel.rb +1 -1
  14. data/lib/{sequel_core → sequel}/adapters/ado.rb +3 -3
  15. data/lib/{sequel_core → sequel}/adapters/db2.rb +0 -0
  16. data/lib/{sequel_core → sequel}/adapters/dbi.rb +1 -1
  17. data/lib/{sequel_core → sequel}/adapters/do.rb +9 -5
  18. data/lib/{sequel_core → sequel}/adapters/do/mysql.rb +1 -1
  19. data/lib/{sequel_core → sequel}/adapters/do/postgres.rb +1 -1
  20. data/lib/{sequel_core → sequel}/adapters/do/sqlite.rb +1 -1
  21. data/lib/{sequel_core → sequel}/adapters/firebird.rb +84 -80
  22. data/lib/{sequel_core → sequel}/adapters/informix.rb +1 -1
  23. data/lib/{sequel_core → sequel}/adapters/jdbc.rb +21 -14
  24. data/lib/{sequel_core → sequel}/adapters/jdbc/h2.rb +14 -13
  25. data/lib/{sequel_core → sequel}/adapters/jdbc/mysql.rb +1 -1
  26. data/lib/{sequel_core → sequel}/adapters/jdbc/oracle.rb +1 -1
  27. data/lib/{sequel_core → sequel}/adapters/jdbc/postgresql.rb +1 -1
  28. data/lib/{sequel_core → sequel}/adapters/jdbc/sqlite.rb +1 -1
  29. data/lib/{sequel_core → sequel}/adapters/mysql.rb +60 -39
  30. data/lib/{sequel_core → sequel}/adapters/odbc.rb +8 -4
  31. data/lib/{sequel_core → sequel}/adapters/openbase.rb +0 -0
  32. data/lib/{sequel_core → sequel}/adapters/oracle.rb +38 -7
  33. data/lib/{sequel_core → sequel}/adapters/postgres.rb +24 -24
  34. data/lib/{sequel_core → sequel}/adapters/shared/mssql.rb +5 -5
  35. data/lib/{sequel_core → sequel}/adapters/shared/mysql.rb +126 -71
  36. data/lib/{sequel_core → sequel}/adapters/shared/oracle.rb +7 -10
  37. data/lib/{sequel_core → sequel}/adapters/shared/postgres.rb +159 -125
  38. data/lib/{sequel_core → sequel}/adapters/shared/progress.rb +1 -2
  39. data/lib/{sequel_core → sequel}/adapters/shared/sqlite.rb +72 -67
  40. data/lib/{sequel_core → sequel}/adapters/sqlite.rb +11 -7
  41. data/lib/{sequel_core → sequel}/adapters/utils/date_format.rb +0 -0
  42. data/lib/{sequel_core → sequel}/adapters/utils/stored_procedures.rb +0 -0
  43. data/lib/{sequel_core → sequel}/adapters/utils/unsupported.rb +19 -0
  44. data/lib/{sequel_core → sequel}/connection_pool.rb +7 -5
  45. data/lib/sequel/core.rb +221 -0
  46. data/lib/{sequel_core → sequel}/core_sql.rb +91 -49
  47. data/lib/{sequel_core → sequel}/database.rb +264 -149
  48. data/lib/{sequel_core/schema/generator.rb → sequel/database/schema_generator.rb} +6 -2
  49. data/lib/{sequel_core/database/schema.rb → sequel/database/schema_methods.rb} +12 -12
  50. data/lib/sequel/database/schema_sql.rb +224 -0
  51. data/lib/{sequel_core → sequel}/dataset.rb +78 -236
  52. data/lib/{sequel_core → sequel}/dataset/convenience.rb +99 -61
  53. data/lib/{sequel_core/object_graph.rb → sequel/dataset/graph.rb} +16 -14
  54. data/lib/{sequel_core → sequel}/dataset/prepared_statements.rb +1 -1
  55. data/lib/{sequel_core → sequel}/dataset/sql.rb +150 -99
  56. data/lib/sequel/deprecated.rb +593 -0
  57. data/lib/sequel/deprecated_migration.rb +91 -0
  58. data/lib/sequel/exceptions.rb +48 -0
  59. data/lib/sequel/extensions/blank.rb +42 -0
  60. data/lib/{sequel_model → sequel/extensions}/inflector.rb +8 -1
  61. data/lib/{sequel_core → sequel/extensions}/migration.rb +1 -1
  62. data/lib/{sequel_core/dataset → sequel/extensions}/pagination.rb +0 -0
  63. data/lib/{sequel_core → sequel/extensions}/pretty_table.rb +7 -0
  64. data/lib/{sequel_core/dataset → sequel/extensions}/query.rb +7 -0
  65. data/lib/sequel/extensions/string_date_time.rb +47 -0
  66. data/lib/sequel/metaprogramming.rb +43 -0
  67. data/lib/sequel/model.rb +110 -0
  68. data/lib/sequel/model/associations.rb +1300 -0
  69. data/lib/sequel/model/base.rb +937 -0
  70. data/lib/sequel/model/deprecated.rb +204 -0
  71. data/lib/sequel/model/deprecated_hooks.rb +103 -0
  72. data/lib/sequel/model/deprecated_inflector.rb +335 -0
  73. data/lib/sequel/model/deprecated_validations.rb +388 -0
  74. data/lib/sequel/model/errors.rb +39 -0
  75. data/lib/{sequel_model → sequel/model}/exceptions.rb +4 -4
  76. data/lib/sequel/model/inflections.rb +208 -0
  77. data/lib/sequel/model/plugins.rb +76 -0
  78. data/lib/sequel/plugins/caching.rb +122 -0
  79. data/lib/sequel/plugins/hook_class_methods.rb +122 -0
  80. data/lib/sequel/plugins/schema.rb +53 -0
  81. data/lib/sequel/plugins/serialization.rb +117 -0
  82. data/lib/sequel/plugins/single_table_inheritance.rb +63 -0
  83. data/lib/sequel/plugins/validation_class_methods.rb +384 -0
  84. data/lib/sequel/plugins/validation_helpers.rb +150 -0
  85. data/lib/{sequel_core → sequel}/sql.rb +125 -190
  86. data/lib/{sequel_core → sequel}/version.rb +2 -1
  87. data/lib/sequel_core.rb +1 -172
  88. data/lib/sequel_model.rb +1 -91
  89. data/spec/adapters/firebird_spec.rb +5 -5
  90. data/spec/adapters/informix_spec.rb +1 -1
  91. data/spec/adapters/mysql_spec.rb +128 -42
  92. data/spec/adapters/oracle_spec.rb +47 -19
  93. data/spec/adapters/postgres_spec.rb +64 -52
  94. data/spec/adapters/spec_helper.rb +1 -1
  95. data/spec/adapters/sqlite_spec.rb +12 -17
  96. data/spec/{sequel_core → core}/connection_pool_spec.rb +10 -10
  97. data/spec/{sequel_core → core}/core_ext_spec.rb +19 -19
  98. data/spec/{sequel_core → core}/core_sql_spec.rb +68 -71
  99. data/spec/{sequel_core → core}/database_spec.rb +135 -99
  100. data/spec/{sequel_core → core}/dataset_spec.rb +398 -242
  101. data/spec/{sequel_core → core}/expression_filters_spec.rb +13 -13
  102. data/spec/core/migration_spec.rb +263 -0
  103. data/spec/{sequel_core → core}/object_graph_spec.rb +10 -10
  104. data/spec/{sequel_core → core}/pretty_table_spec.rb +2 -2
  105. data/spec/{sequel_core → core}/schema_generator_spec.rb +0 -0
  106. data/spec/{sequel_core → core}/schema_spec.rb +8 -10
  107. data/spec/{sequel_core → core}/spec_helper.rb +29 -2
  108. data/spec/{sequel_core → core}/version_spec.rb +0 -0
  109. data/spec/extensions/blank_spec.rb +67 -0
  110. data/spec/extensions/caching_spec.rb +201 -0
  111. data/spec/{sequel_model/hooks_spec.rb → extensions/hook_class_methods_spec.rb} +8 -23
  112. data/spec/{sequel_model → extensions}/inflector_spec.rb +3 -0
  113. data/spec/{sequel_core → extensions}/migration_spec.rb +4 -4
  114. data/spec/extensions/pagination_spec.rb +99 -0
  115. data/spec/extensions/pretty_table_spec.rb +91 -0
  116. data/spec/extensions/query_spec.rb +85 -0
  117. data/spec/{sequel_model → extensions}/schema_spec.rb +22 -1
  118. data/spec/extensions/serialization_spec.rb +109 -0
  119. data/spec/extensions/single_table_inheritance_spec.rb +53 -0
  120. data/spec/{sequel_model → extensions}/spec_helper.rb +13 -4
  121. data/spec/extensions/string_date_time_spec.rb +93 -0
  122. data/spec/{sequel_model/validations_spec.rb → extensions/validation_class_methods_spec.rb} +15 -103
  123. data/spec/extensions/validation_helpers_spec.rb +291 -0
  124. data/spec/integration/dataset_test.rb +31 -0
  125. data/spec/integration/eager_loader_test.rb +17 -30
  126. data/spec/integration/schema_test.rb +8 -5
  127. data/spec/integration/spec_helper.rb +17 -0
  128. data/spec/integration/transaction_test.rb +68 -0
  129. data/spec/{sequel_model → model}/association_reflection_spec.rb +0 -0
  130. data/spec/{sequel_model → model}/associations_spec.rb +23 -10
  131. data/spec/{sequel_model → model}/base_spec.rb +29 -20
  132. data/spec/{sequel_model → model}/caching_spec.rb +16 -14
  133. data/spec/{sequel_model → model}/dataset_methods_spec.rb +0 -0
  134. data/spec/{sequel_model → model}/eager_loading_spec.rb +8 -8
  135. data/spec/model/hooks_spec.rb +472 -0
  136. data/spec/model/inflector_spec.rb +126 -0
  137. data/spec/{sequel_model → model}/model_spec.rb +25 -20
  138. data/spec/model/plugins_spec.rb +142 -0
  139. data/spec/{sequel_model → model}/record_spec.rb +121 -62
  140. data/spec/model/schema_spec.rb +92 -0
  141. data/spec/model/spec_helper.rb +124 -0
  142. data/spec/model/validations_spec.rb +1080 -0
  143. metadata +136 -107
  144. data/lib/sequel_core/core_ext.rb +0 -217
  145. data/lib/sequel_core/dataset/callback.rb +0 -13
  146. data/lib/sequel_core/dataset/schema.rb +0 -15
  147. data/lib/sequel_core/deprecated.rb +0 -26
  148. data/lib/sequel_core/exceptions.rb +0 -44
  149. data/lib/sequel_core/schema.rb +0 -2
  150. data/lib/sequel_core/schema/sql.rb +0 -325
  151. data/lib/sequel_model/association_reflection.rb +0 -267
  152. data/lib/sequel_model/associations.rb +0 -499
  153. data/lib/sequel_model/base.rb +0 -539
  154. data/lib/sequel_model/caching.rb +0 -82
  155. data/lib/sequel_model/dataset_methods.rb +0 -26
  156. data/lib/sequel_model/eager_loading.rb +0 -370
  157. data/lib/sequel_model/hooks.rb +0 -101
  158. data/lib/sequel_model/plugins.rb +0 -62
  159. data/lib/sequel_model/record.rb +0 -568
  160. data/lib/sequel_model/schema.rb +0 -49
  161. data/lib/sequel_model/validations.rb +0 -429
  162. data/spec/sequel_model/plugins_spec.rb +0 -80
@@ -1,10 +1,11 @@
1
1
  module Sequel
2
2
  MAJOR = 2
3
- MINOR = 11
3
+ MINOR = 12
4
4
  TINY = 0
5
5
 
6
6
  VERSION = [MAJOR, MINOR, TINY].join('.')
7
7
 
8
+ # The version of Sequel you are using, as a string (e.g. "2.11.0")
8
9
  def self.version
9
10
  VERSION
10
11
  end
data/lib/sequel_core.rb CHANGED
@@ -1,172 +1 @@
1
- %w'bigdecimal bigdecimal/util date enumerator thread time uri yaml'.each do |f|
2
- require f
3
- end
4
- %w"core_ext sql core_sql connection_pool exceptions pretty_table
5
- dataset migration schema database object_graph version".each do |f|
6
- require "sequel_core/#{f}"
7
- end
8
-
9
- # Top level module for Sequel
10
- #
11
- # There are some class methods that are added via metaprogramming, one for
12
- # each supported adapter. For example:
13
- #
14
- # DB = Sequel.sqlite # Memory database
15
- # DB = Sequel.sqlite('blog.db')
16
- # DB = Sequel.postgres('database_name', :user=>'user',
17
- # :password=>'password', :host=>'host', :port=>5432,
18
- # :max_connections=>10)
19
- #
20
- # If a block is given to these methods, it is passed the opened Database
21
- # object, which is closed (disconnected) when the block exits. For example:
22
- #
23
- # Sequel.sqlite('blog.db'){|db| puts db.users.count}
24
- #
25
- # Sequel converts the column type tinyint to a boolean by default,
26
- # you can override the conversion to use tinyint as an integer:
27
- #
28
- # Sequel.convert_tinyint_to_bool = false
29
- #
30
- # Sequel converts two digit years in Dates and DateTimes by default,
31
- # so 01/02/03 is interpreted at January 2nd, 2003, and 12/13/99 is interpreted
32
- # as December 13, 1999.. You can override this # to treat those dates as
33
- # January 2nd, 0003 and December 13, 0099, respectively, by setting:
34
- #
35
- # Sequel.convert_two_digit_years = false
36
- #
37
- # Sequel can use either Time or DateTime for times returned from the
38
- # database. It defaults to Time. To change it to DateTime, use:
39
- #
40
- # Sequel.datetime_class = DateTime
41
- module Sequel
42
- @convert_tinyint_to_bool = true
43
- @convert_two_digit_years = true
44
- @datetime_class = Time
45
-
46
- metaattr_accessor :convert_tinyint_to_bool
47
- metaattr_accessor :convert_two_digit_years
48
- metaattr_accessor :datetime_class
49
-
50
- # Creates a new database object based on the supplied connection string
51
- # and optional arguments. The specified scheme determines the database
52
- # class used, and the rest of the string specifies the connection options.
53
- # For example:
54
- #
55
- # DB = Sequel.connect('sqlite:/') # Memory database
56
- # DB = Sequel.connect('sqlite://blog.db') # ./blog.db
57
- # DB = Sequel.connect('sqlite:///blog.db') # /blog.db
58
- # DB = Sequel.connect('postgres://user:password@host:port/database_name')
59
- # DB = Sequel.connect('sqlite:///blog.db', :max_connections=>10)
60
- #
61
- # If a block is given, it is passed the opened Database object, which is
62
- # closed when the block exits. For example:
63
- #
64
- # Sequel.connect('sqlite://blog.db'){|db| puts db.users.count}
65
- #
66
- # This is also aliased as Sequel.open.
67
- def self.connect(*args, &block)
68
- Database.connect(*args, &block)
69
- end
70
- metaalias :open, :connect
71
-
72
- # Set the method to call on identifiers going into the database. This affects
73
- # the literalization of identifiers by calling this method on them before they are input.
74
- # Sequel upcases identifiers in all SQL strings for most databases, so to turn that off:
75
- #
76
- # Sequel.identifier_input_method = nil
77
- #
78
- # to downcase instead:
79
- #
80
- # Sequel.identifier_input_method = :downcase
81
- #
82
- # Other string methods work as well.
83
- def self.identifier_input_method=(value)
84
- Database.identifier_input_method = value
85
- end
86
-
87
- # Set the method to call on identifiers coming out of the database. This affects
88
- # the literalization of identifiers by calling this method on them when they are
89
- # retrieved from the database. Sequel downcases identifiers retrieved for most
90
- # databases, so to turn that off:
91
- #
92
- # Sequel.identifier_output_method = nil
93
- #
94
- # to upcase instead:
95
- #
96
- # Sequel.identifier_output_method = :upcase
97
- #
98
- # Other string methods work as well.
99
- def self.identifier_output_method=(value)
100
- Database.identifier_output_method = value
101
- end
102
-
103
- # Set whether to quote identifiers for all databases by default. By default,
104
- # Sequel quotes identifiers in all SQL strings, so to turn that off:
105
- #
106
- # Sequel.quote_identifiers = false
107
- def self.quote_identifiers=(value)
108
- Database.quote_identifiers = value
109
- end
110
-
111
- # Set whether to set the single threaded mode for all databases by default. By default,
112
- # Sequel uses a threadsafe connection pool, which isn't as fast as the
113
- # single threaded connection pool. If your program will only have one thread,
114
- # and speed is a priority, you may want to set this to true:
115
- #
116
- # Sequel.single_threaded = true
117
- def self.single_threaded=(value)
118
- Database.single_threaded = value
119
- end
120
-
121
- # Set whether to upcase identifiers for all databases by default. By default,
122
- # Sequel upcases identifiers unless the database folds unquoted identifiers to
123
- # lower case (MySQL, PostgreSQL, and SQLite).
124
- #
125
- # Sequel.upcase_identifiers = false
126
- #
127
- # This will set the indentifier_input_method to :upcase if value is true
128
- # or nil if value is false.
129
- def self.upcase_identifiers=(value)
130
- Database.upcase_identifiers = value
131
- end
132
-
133
- # Always returns false, since ParseTree support has been removed.
134
- def self.use_parse_tree
135
- false
136
- end
137
-
138
- # Raises an error if attempting to turn ParseTree support on (since it no longer exists).
139
- # Otherwise, is a no-op.
140
- def self.use_parse_tree=(val)
141
- raise(Error, 'ParseTree support has been removed from Sequel') if val
142
- end
143
-
144
- ### Private Class Methods ###
145
-
146
- # Helper method that the database adapter class methods that are added to Sequel via
147
- # metaprogramming use to parse arguments.
148
- def self.adapter_method(adapter, *args, &block) # :nodoc:
149
- raise(::Sequel::Error, "Wrong number of arguments, 0-2 arguments valid") if args.length > 2
150
- opts = {:adapter=>adapter.to_sym}
151
- opts[:database] = args.shift if args.length >= 1 && !(args[0].is_a?(Hash))
152
- if Hash === (arg = args[0])
153
- opts.merge!(arg)
154
- elsif !arg.nil?
155
- raise ::Sequel::Error, "Wrong format of arguments, either use (), (String), (Hash), or (String, Hash)"
156
- end
157
- connect(opts, &block)
158
- end
159
-
160
- # Method that adds a database adapter class method to Sequel that calls
161
- # Sequel.adapter_method.
162
- def self.def_adapter_method(*adapters) # :nodoc:
163
- adapters.each do |adapter|
164
- instance_eval("def #{adapter}(*args, &block); adapter_method('#{adapter}', *args, &block) end")
165
- end
166
- end
167
-
168
- private_class_method :adapter_method, :def_adapter_method
169
-
170
- # Add the database adapter class methods to Sequel via metaprogramming
171
- def_adapter_method(*Database::ADAPTERS)
172
- end
1
+ require 'sequel/core'
data/lib/sequel_model.rb CHANGED
@@ -1,91 +1 @@
1
- require 'sequel_core'
2
- %w"inflector base hooks record schema association_reflection dataset_methods
3
- associations caching plugins validations eager_loading exceptions".each do |f|
4
- require "sequel_model/#{f}"
5
- end
6
-
7
- module Sequel
8
- # Holds the nameless subclasses that are created with
9
- # Sequel::Model(), necessary for reopening subclasses with the
10
- # Sequel::Model() superclass specified.
11
- @models = {}
12
-
13
- # Lets you create a Model subclass with its dataset already set.
14
- # source can be an existing dataset or a symbol (in which case
15
- # it will create a dataset using the default database with
16
- # source as the table name).
17
- #
18
- # Example:
19
- # class Comment < Sequel::Model(:something)
20
- # table_name # => :something
21
- # end
22
- def self.Model(source)
23
- @models[source] ||= Class.new(Model).set_dataset(source)
24
- end
25
-
26
- # Model has some methods that are added via metaprogramming:
27
- #
28
- # * All of the methods in DATASET_METHODS have class methods created that call
29
- # the Model's dataset with the method of the same name with the given
30
- # arguments.
31
- # * All of the methods in HOOKS have class methods created that accept
32
- # either a method name symbol or an optional tag and a block. These
33
- # methods run the code as a callback at the specified time. For example:
34
- #
35
- # Model.before_save :do_something
36
- # Model.before_save(:do_something_else){ self.something_else = 42}
37
- # object = Model.new
38
- # object.save
39
- #
40
- # Would run the object's :do_something method following by the code
41
- # block related to :do_something_else. Note that if you specify a
42
- # block, a tag is optional. If the tag is not nil, it will overwrite
43
- # a previous block with the same tag. This allows hooks to work with
44
- # systems that reload code.
45
- # * All of the methods in HOOKS also create instance methods, but you
46
- # should not override these instance methods.
47
- # * The following instance_methods all call the class method of the same
48
- # name: columns, dataset, db, primary_key, str_columns.
49
- # * The following class level attr_readers are created: allowed_columns,
50
- # cache_store, cache_ttl, dataset_methods, primary_key, restricted_columns,
51
- # sti_dataset, and sti_key. You should not usually need to
52
- # access these directly.
53
- # * All validation methods also accept the options specified in #validates_each,
54
- # in addition to the options specified in the RDoc for that method.
55
- # * The following class level attr_accessors are created: raise_on_typecast_failure,
56
- # raise_on_save_failure, strict_param_setting, typecast_empty_string_to_nil,
57
- # and typecast_on_assignment:
58
- #
59
- # # Don't raise an error if a validation attempt fails in
60
- # # save/create/save_changes/etc.
61
- # Model.raise_on_save_failure = false
62
- # Model.before_save{false}
63
- # Model.new.save # => nil
64
- # # Don't raise errors in new/set/update/etc. if an attempt to
65
- # # access a missing/restricted method occurs (just silently
66
- # # skip it)
67
- # Model.strict_param_setting = false
68
- # Model.new(:id=>1) # No Error
69
- # # Don't typecast attribute values on assignment
70
- # Model.typecast_on_assignment = false
71
- # m = Model.new
72
- # m.number = '10'
73
- # m.number # => '10' instead of 10
74
- # # Don't typecast empty string to nil for non-string, non-blob columns.
75
- # Model.typecast_empty_string_to_nil = false
76
- # m.number = ''
77
- # m.number # => '' instead of nil
78
- # # Don't raise if unable to typecast data for a column
79
- # Model.typecast_empty_string_to_nil = true
80
- # Model.raise_on_typecast_failure = false
81
- # m.not_null_column = '' # => nil
82
- # m.number = 'A' # => 'A'
83
- #
84
- # * The following class level method aliases are defined:
85
- # * Model.dataset= => set_dataset
86
- # * Model.is_a => is
87
- class Model
88
- extend Enumerable
89
- extend Associations
90
- end
91
- end
1
+ require 'sequel/model'
@@ -26,7 +26,7 @@ FIREBIRD_DB.create_table! :test5 do
26
26
  end
27
27
 
28
28
  context "A Firebird database" do
29
- setup do
29
+ before do
30
30
  @db = FIREBIRD_DB
31
31
  end
32
32
 
@@ -43,7 +43,7 @@ context "A Firebird database" do
43
43
  end
44
44
 
45
45
  context "A Firebird dataset" do
46
- setup do
46
+ before do
47
47
  @d = FIREBIRD_DB[:test]
48
48
  @d.delete # remove all records
49
49
  end
@@ -212,7 +212,7 @@ context "A Firebird dataset" do
212
212
  end
213
213
 
214
214
  context "A Firebird dataset with a timestamp field" do
215
- setup do
215
+ before do
216
216
  @d = FIREBIRD_DB[:test3]
217
217
  @d.delete
218
218
  end
@@ -226,7 +226,7 @@ context "A Firebird dataset with a timestamp field" do
226
226
  end
227
227
 
228
228
  context "A Firebird database" do
229
- setup do
229
+ before do
230
230
  @db = FIREBIRD_DB
231
231
  end
232
232
 
@@ -342,7 +342,7 @@ context "A Firebird database" do
342
342
  end
343
343
 
344
344
  context "Postgres::Dataset#insert" do
345
- setup do
345
+ before do
346
346
  @ds = FIREBIRD_DB[:test5]
347
347
  @ds.delete
348
348
  end
@@ -24,7 +24,7 @@ context "A Informix database" do
24
24
  end
25
25
 
26
26
  context "A Informix dataset" do
27
- setup do
27
+ before do
28
28
  @d = INFORMIX_DB[:test]
29
29
  @d.delete # remove all records
30
30
  end
@@ -44,7 +44,7 @@ else
44
44
  end
45
45
 
46
46
  context "MySQL", '#create_table' do
47
- setup do
47
+ before do
48
48
  @db = MYSQL_DB
49
49
  end
50
50
  after(:each) do
@@ -57,10 +57,10 @@ context "MySQL", '#create_table' do
57
57
  end
58
58
 
59
59
  context "A MySQL database" do
60
- setup do
60
+ before do
61
61
  @db = MYSQL_DB
62
62
  end
63
- teardown do
63
+ after do
64
64
  Sequel.convert_tinyint_to_bool = true
65
65
  end
66
66
 
@@ -96,14 +96,10 @@ context "A MySQL database" do
96
96
  Sequel.convert_tinyint_to_bool = false
97
97
  @db.schema(:booltest, :reload=>true).should == [[:value, {:type=>:integer, :allow_null=>true, :primary_key=>false, :default=>nil, :db_type=>"tinyint(4)"}]]
98
98
  end
99
-
100
- specify "should get the schema all database tables if no table name is used" do
101
- @db.schema(:booltest, :reload=>true).should == @db.schema(nil, :reload=>true)[:booltest]
102
- end
103
99
  end
104
100
 
105
101
  context "A MySQL dataset" do
106
- setup do
102
+ before do
107
103
  @d = MYSQL_DB[:items]
108
104
  @d.delete # remove all records
109
105
  MYSQL_DB.sqls.clear
@@ -274,10 +270,10 @@ context "A MySQL dataset" do
274
270
  end
275
271
 
276
272
  context "MySQL datasets" do
277
- setup do
273
+ before do
278
274
  @d = MYSQL_DB[:orders]
279
275
  end
280
- teardown do
276
+ after do
281
277
  Sequel.convert_tinyint_to_bool = true
282
278
  end
283
279
 
@@ -285,11 +281,9 @@ context "MySQL datasets" do
285
281
  @d.quote_identifiers = true
286
282
  market = 'ICE'
287
283
  ack_stamp = Time.now - 15 * 60 # 15 minutes ago
288
- @d.query do
289
- select :market, :minute.sql_function(:from_unixtime.sql_function(:ack)).as(:minute)
290
- where {(:ack.sql_number > ack_stamp) & {:market => market}}
291
- group_by :minute.sql_function(:from_unixtime.sql_function(:ack))
292
- end.sql.should == \
284
+ @d.select(:market, :minute.sql_function(:from_unixtime.sql_function(:ack)).as(:minute)).
285
+ where{|o|(:ack.sql_number > ack_stamp) & {:market => market}}.
286
+ group_by(:minute.sql_function(:from_unixtime.sql_function(:ack))).sql.should == \
293
287
  "SELECT `market`, minute(from_unixtime(`ack`)) AS `minute` FROM `orders` WHERE ((`ack` > #{@d.literal(ack_stamp)}) AND (`market` = 'ICE')) GROUP BY minute(from_unixtime(`ack`))"
294
288
  end
295
289
 
@@ -319,7 +313,7 @@ context "MySQL datasets" do
319
313
  end
320
314
 
321
315
  context "MySQL join expressions" do
322
- setup do
316
+ before do
323
317
  @ds = MYSQL_DB[:nodes]
324
318
  @ds.db.meta_def(:server_version) {50014}
325
319
  end
@@ -370,7 +364,7 @@ context "MySQL join expressions" do
370
364
  end
371
365
 
372
366
  context "Joined MySQL dataset" do
373
- setup do
367
+ before do
374
368
  @ds = MYSQL_DB[:nodes]
375
369
  end
376
370
 
@@ -394,7 +388,7 @@ context "Joined MySQL dataset" do
394
388
  end
395
389
 
396
390
  context "A MySQL database" do
397
- setup do
391
+ before do
398
392
  @db = MYSQL_DB
399
393
  end
400
394
 
@@ -485,21 +479,21 @@ context "A MySQL database", "with table options" do
485
479
  end
486
480
 
487
481
  specify "should allow to pass custom options (engine, charset, collate) for table creation" do
488
- statements = @db.create_table_sql_list(:items, *(@g.create_info << @options))
482
+ statements = @db.send(:create_table_sql_list, :items, *(@g.create_info << @options))
489
483
  statements.should == [
490
484
  "CREATE TABLE items (size integer, name text) ENGINE=MyISAM DEFAULT CHARSET=latin2 DEFAULT COLLATE=swedish"
491
485
  ]
492
486
  end
493
487
 
494
488
  specify "should use default options if specified (engine, charset, collate) for table creation" do
495
- statements = @db.create_table_sql_list(:items, *(@g.create_info))
489
+ statements = @db.send(:create_table_sql_list, :items, *(@g.create_info))
496
490
  statements.should == [
497
491
  "CREATE TABLE items (size integer, name text) ENGINE=InnoDB DEFAULT CHARSET=utf8 DEFAULT COLLATE=utf8"
498
492
  ]
499
493
  end
500
494
 
501
495
  specify "should not use default if option has a nil value" do
502
- statements = @db.create_table_sql_list(:items, *(@g.create_info << {:engine=>nil, :charset=>nil, :collate=>nil}))
496
+ statements = @db.send(:create_table_sql_list, :items, *(@g.create_info << {:engine=>nil, :charset=>nil, :collate=>nil}))
503
497
  statements.should == [
504
498
  "CREATE TABLE items (size integer, name text)"
505
499
  ]
@@ -507,7 +501,7 @@ context "A MySQL database", "with table options" do
507
501
  end
508
502
 
509
503
  context "A MySQL database" do
510
- setup do
504
+ before do
511
505
  @db = MYSQL_DB
512
506
  end
513
507
 
@@ -516,7 +510,7 @@ context "A MySQL database" do
516
510
  boolean :active1, :default => true
517
511
  boolean :active2, :default => false
518
512
  end
519
- statements = @db.create_table_sql_list(:items, *g.create_info)
513
+ statements = @db.send(:create_table_sql_list, :items, *g.create_info)
520
514
  statements.should == [
521
515
  "CREATE TABLE items (active1 boolean DEFAULT 1, active2 boolean DEFAULT 0)"
522
516
  ]
@@ -527,7 +521,7 @@ context "A MySQL database" do
527
521
  foreign_key :p_id, :table => :users, :key => :id,
528
522
  :null => false, :on_delete => :cascade
529
523
  end
530
- @db.create_table_sql_list(:items, *g.create_info).should == [
524
+ @db.send(:create_table_sql_list, :items, *g.create_info).should == [
531
525
  "CREATE TABLE items (p_id integer NOT NULL, FOREIGN KEY (p_id) REFERENCES users(id) ON DELETE CASCADE)"
532
526
  ]
533
527
  end
@@ -536,7 +530,7 @@ specify "should correctly format ALTER TABLE statements with foreign keys" do
536
530
  g = Sequel::Schema::AlterTableGenerator.new(@db) do
537
531
  add_foreign_key :p_id, :users, :key => :id, :null => false, :on_delete => :cascade
538
532
  end
539
- @db.alter_table_sql_list(:items, g.operations).should == [[
533
+ @db.send(:alter_table_sql_list, :items, g.operations).should == [[
540
534
  "ALTER TABLE items ADD COLUMN p_id integer NOT NULL",
541
535
  "ALTER TABLE items ADD FOREIGN KEY (p_id) REFERENCES users(id) ON DELETE CASCADE"
542
536
  ]]
@@ -584,7 +578,7 @@ if %w'localhost 127.0.0.1 ::1'.include?(MYSQL_URI.host) and MYSQL_DB.class.adapt
584
578
  end
585
579
 
586
580
  context "A grouped MySQL dataset" do
587
- setup do
581
+ before do
588
582
  MYSQL_DB[:test2].delete
589
583
  MYSQL_DB[:test2] << {:name => '11', :value => 10}
590
584
  MYSQL_DB[:test2] << {:name => '11', :value => 20}
@@ -606,16 +600,13 @@ context "A grouped MySQL dataset" do
606
600
  end
607
601
 
608
602
  context "A MySQL database" do
609
- setup do
610
- end
611
-
612
603
  specify "should support fulltext indexes" do
613
604
  g = Sequel::Schema::Generator.new(MYSQL_DB) do
614
605
  text :title
615
606
  text :body
616
607
  full_text_index [:title, :body]
617
608
  end
618
- MYSQL_DB.create_table_sql_list(:posts, *g.create_info).should == [
609
+ MYSQL_DB.send(:create_table_sql_list, :posts, *g.create_info).should == [
619
610
  "CREATE TABLE posts (title text, body text)",
620
611
  "CREATE FULLTEXT INDEX posts_title_body_index ON posts (title, body)"
621
612
  ]
@@ -637,7 +628,7 @@ context "A MySQL database" do
637
628
  point :geom
638
629
  spatial_index [:geom]
639
630
  end
640
- MYSQL_DB.create_table_sql_list(:posts, *g.create_info).should == [
631
+ MYSQL_DB.send(:create_table_sql_list, :posts, *g.create_info).should == [
641
632
  "CREATE TABLE posts (geom point)",
642
633
  "CREATE SPATIAL INDEX posts_geom_index ON posts (geom)"
643
634
  ]
@@ -648,7 +639,7 @@ context "A MySQL database" do
648
639
  text :title
649
640
  index :title, :type => :hash
650
641
  end
651
- MYSQL_DB.create_table_sql_list(:posts, *g.create_info).should == [
642
+ MYSQL_DB.send(:create_table_sql_list, :posts, *g.create_info).should == [
652
643
  "CREATE TABLE posts (title text)",
653
644
  "CREATE INDEX posts_title_index ON posts (title) USING hash"
654
645
  ]
@@ -659,7 +650,7 @@ context "A MySQL database" do
659
650
  text :title
660
651
  index :title, :type => :hash, :unique => true
661
652
  end
662
- MYSQL_DB.create_table_sql_list(:posts, *g.create_info).should == [
653
+ MYSQL_DB.send(:create_table_sql_list, :posts, *g.create_info).should == [
663
654
  "CREATE TABLE posts (title text)",
664
655
  "CREATE UNIQUE INDEX posts_title_index ON posts (title) USING hash"
665
656
  ]
@@ -667,9 +658,9 @@ context "A MySQL database" do
667
658
  end
668
659
 
669
660
  context "MySQL::Dataset#insert" do
670
- setup do
661
+ before do
671
662
  @d = MYSQL_DB[:items]
672
- @d.delete # remove all records
663
+ @d.delete
673
664
  MYSQL_DB.sqls.clear
674
665
  end
675
666
 
@@ -711,9 +702,9 @@ context "MySQL::Dataset#insert" do
711
702
  end
712
703
 
713
704
  context "MySQL::Dataset#multi_insert" do
714
- setup do
705
+ before do
715
706
  @d = MYSQL_DB[:items]
716
- @d.delete # remove all records
707
+ @d.delete
717
708
  MYSQL_DB.sqls.clear
718
709
  end
719
710
 
@@ -774,7 +765,7 @@ context "MySQL::Dataset#multi_insert" do
774
765
  end
775
766
 
776
767
  specify "should support inserting using columns and values arrays" do
777
- @d.multi_insert([:name, :value], [['abc', 1], ['def', 2]])
768
+ @d.import([:name, :value], [['abc', 1], ['def', 2]])
778
769
 
779
770
  MYSQL_DB.sqls.should == [
780
771
  SQL_BEGIN,
@@ -789,8 +780,70 @@ context "MySQL::Dataset#multi_insert" do
789
780
  end
790
781
  end
791
782
 
783
+ context "MySQL::Dataset#insert_ignore" do
784
+ before do
785
+ @d = MYSQL_DB[:items]
786
+ @d.delete
787
+ MYSQL_DB.sqls.clear
788
+ end
789
+
790
+ specify "should add the IGNORE keyword when inserting" do
791
+ @d.insert_ignore.multi_insert([{:name => 'abc'}, {:name => 'def'}])
792
+
793
+ MYSQL_DB.sqls.should == [
794
+ SQL_BEGIN,
795
+ "INSERT IGNORE INTO items (name) VALUES ('abc'), ('def')",
796
+ SQL_COMMIT
797
+ ]
798
+
799
+ @d.all.should == [
800
+ {:name => 'abc', :value => nil}, {:name => 'def', :value => nil}
801
+ ]
802
+ end
803
+ end
804
+
805
+ context "MySQL::Dataset#on_duplicate_key_update" do
806
+ before do
807
+ @d = MYSQL_DB[:items]
808
+ @d.delete
809
+ MYSQL_DB.sqls.clear
810
+ end
811
+
812
+ specify "should add the ON DUPLICATE KEY UPDATE and ALL columns when no args given" do
813
+ @d.on_duplicate_key_update.import([:name,:value],
814
+ [['abc', 1], ['def',2]]
815
+ )
816
+
817
+ MYSQL_DB.sqls.should == [
818
+ SQL_BEGIN,
819
+ "INSERT INTO items (name, value) VALUES ('abc', 1), ('def', 2) ON DUPLICATE KEY UPDATE name=VALUES(name), value=VALUES(value)",
820
+ SQL_COMMIT
821
+ ]
822
+
823
+ @d.all.should == [
824
+ {:name => 'abc', :value => 1}, {:name => 'def', :value => 2}
825
+ ]
826
+ end
827
+ specify "should add the ON DUPLICATE KEY UPDATE and columns specified when args are given" do
828
+ @d.on_duplicate_key_update(:value).import([:name,:value],
829
+ [['abc', 1], ['def',2]]
830
+ )
831
+
832
+ MYSQL_DB.sqls.should == [
833
+ SQL_BEGIN,
834
+ "INSERT INTO items (name, value) VALUES ('abc', 1), ('def', 2) ON DUPLICATE KEY UPDATE value=VALUES(value)",
835
+ SQL_COMMIT
836
+ ]
837
+
838
+ @d.all.should == [
839
+ {:name => 'abc', :value => 1}, {:name => 'def', :value => 2}
840
+ ]
841
+ end
842
+
843
+ end
844
+
792
845
  context "MySQL::Dataset#replace" do
793
- setup do
846
+ before do
794
847
  MYSQL_DB.drop_table(:items) if MYSQL_DB.table_exists?(:items)
795
848
  MYSQL_DB.create_table :items do
796
849
  integer :id, :unique => true
@@ -814,7 +867,7 @@ context "MySQL::Dataset#replace" do
814
867
  end
815
868
 
816
869
  context "MySQL::Dataset#complex_expression_sql" do
817
- setup do
870
+ before do
818
871
  @d = MYSQL_DB.dataset
819
872
  end
820
873
 
@@ -832,7 +885,7 @@ context "MySQL::Dataset#complex_expression_sql" do
832
885
  specify "should handle string concatenation with CONCAT if more than one record" do
833
886
  @d.literal([:x, :y].sql_string_join).should == "CONCAT(x, y)"
834
887
  @d.literal([:x, :y].sql_string_join(' ')).should == "CONCAT(x, ' ', y)"
835
- @d.literal([:x.sql_function(:y), 1, 'z'.lit].sql_string_join(:y|1)).should == "CONCAT(x(y), y[1], '1', y[1], z)"
888
+ @d.literal([:x.sql_function(:y), 1, 'z'.lit].sql_string_join(:y.sql_subscript(1))).should == "CONCAT(x(y), y[1], '1', y[1], z)"
836
889
  end
837
890
 
838
891
  specify "should handle string concatenation as simple string if just one record" do
@@ -843,7 +896,7 @@ end
843
896
 
844
897
  unless MYSQL_DB.class.adapter_scheme == :do
845
898
  context "MySQL Stored Procedures" do
846
- teardown do
899
+ after do
847
900
  MYSQL_DB.execute('DROP PROCEDURE test_sproc')
848
901
  end
849
902
 
@@ -879,3 +932,36 @@ unless MYSQL_DB.class.adapter_scheme == :do
879
932
  end
880
933
  end
881
934
  end
935
+
936
+ if MYSQL_DB.class.adapter_scheme == :mysql
937
+ context "MySQL bad date/time conversions" do
938
+ after do
939
+ Sequel::MySQL.convert_invalid_date_time = false
940
+ end
941
+
942
+ specify "should raise an exception when a bad date/time is used and convert_invalid_date_time is false" do
943
+ Sequel::MySQL.convert_invalid_date_time = false
944
+ proc{MYSQL_DB["SELECT CAST('0000-00-00' AS date)"].single_value}.should raise_error(Sequel::InvalidValue)
945
+ proc{MYSQL_DB["SELECT CAST('0000-00-00 00:00:00' AS datetime)"].single_value}.should raise_error(Sequel::InvalidValue)
946
+ proc{MYSQL_DB["SELECT CAST('25:00:00' AS time)"].single_value}.should raise_error(Sequel::InvalidValue)
947
+ end
948
+
949
+ specify "should not use a nil value bad date/time is used and convert_invalid_date_time is nil or :nil" do
950
+ Sequel::MySQL.convert_invalid_date_time = nil
951
+ MYSQL_DB["SELECT CAST('0000-00-00' AS date)"].single_value.should == nil
952
+ MYSQL_DB["SELECT CAST('0000-00-00 00:00:00' AS datetime)"].single_value.should == nil
953
+ MYSQL_DB["SELECT CAST('25:00:00' AS time)"].single_value.should == nil
954
+ Sequel::MySQL.convert_invalid_date_time = :nil
955
+ MYSQL_DB["SELECT CAST('0000-00-00' AS date)"].single_value.should == nil
956
+ MYSQL_DB["SELECT CAST('0000-00-00 00:00:00' AS datetime)"].single_value.should == nil
957
+ MYSQL_DB["SELECT CAST('25:00:00' AS time)"].single_value.should == nil
958
+ end
959
+
960
+ specify "should not use a nil value bad date/time is used and convert_invalid_date_time is :string" do
961
+ Sequel::MySQL.convert_invalid_date_time = :string
962
+ MYSQL_DB["SELECT CAST('0000-00-00' AS date)"].single_value.should == '0000-00-00'
963
+ MYSQL_DB["SELECT CAST('0000-00-00 00:00:00' AS datetime)"].single_value.should == '0000-00-00 00:00:00'
964
+ MYSQL_DB["SELECT CAST('25:00:00' AS time)"].single_value.should == '25:00:00'
965
+ end
966
+ end
967
+ end