sequel 3.38.0 → 3.39.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +62 -0
- data/README.rdoc +2 -2
- data/bin/sequel +12 -2
- data/doc/advanced_associations.rdoc +1 -1
- data/doc/association_basics.rdoc +13 -0
- data/doc/release_notes/3.39.0.txt +237 -0
- data/doc/schema_modification.rdoc +4 -4
- data/lib/sequel/adapters/jdbc/derby.rb +1 -0
- data/lib/sequel/adapters/mock.rb +5 -0
- data/lib/sequel/adapters/mysql.rb +8 -1
- data/lib/sequel/adapters/mysql2.rb +10 -3
- data/lib/sequel/adapters/postgres.rb +72 -8
- data/lib/sequel/adapters/shared/db2.rb +1 -0
- data/lib/sequel/adapters/shared/mssql.rb +57 -0
- data/lib/sequel/adapters/shared/mysql.rb +95 -19
- data/lib/sequel/adapters/shared/oracle.rb +14 -0
- data/lib/sequel/adapters/shared/postgres.rb +63 -24
- data/lib/sequel/adapters/shared/sqlite.rb +6 -9
- data/lib/sequel/connection_pool/sharded_threaded.rb +8 -3
- data/lib/sequel/connection_pool/threaded.rb +9 -4
- data/lib/sequel/database/query.rb +60 -48
- data/lib/sequel/database/schema_generator.rb +13 -6
- data/lib/sequel/database/schema_methods.rb +65 -12
- data/lib/sequel/dataset/actions.rb +22 -4
- data/lib/sequel/dataset/features.rb +5 -0
- data/lib/sequel/dataset/graph.rb +2 -3
- data/lib/sequel/dataset/misc.rb +2 -2
- data/lib/sequel/dataset/query.rb +0 -2
- data/lib/sequel/dataset/sql.rb +33 -12
- data/lib/sequel/extensions/constraint_validations.rb +451 -0
- data/lib/sequel/extensions/eval_inspect.rb +17 -2
- data/lib/sequel/extensions/pg_array_ops.rb +15 -5
- data/lib/sequel/extensions/pg_interval.rb +2 -2
- data/lib/sequel/extensions/pg_row_ops.rb +18 -0
- data/lib/sequel/extensions/schema_dumper.rb +3 -11
- data/lib/sequel/model/associations.rb +3 -2
- data/lib/sequel/model/base.rb +57 -13
- data/lib/sequel/model/exceptions.rb +20 -2
- data/lib/sequel/plugins/constraint_validations.rb +198 -0
- data/lib/sequel/plugins/defaults_setter.rb +15 -1
- data/lib/sequel/plugins/dirty.rb +2 -2
- data/lib/sequel/plugins/identity_map.rb +12 -8
- data/lib/sequel/plugins/subclasses.rb +19 -1
- data/lib/sequel/plugins/tree.rb +3 -3
- data/lib/sequel/plugins/validation_helpers.rb +24 -4
- data/lib/sequel/sql.rb +64 -24
- data/lib/sequel/timezones.rb +10 -2
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/mssql_spec.rb +26 -25
- data/spec/adapters/mysql_spec.rb +57 -23
- data/spec/adapters/oracle_spec.rb +34 -49
- data/spec/adapters/postgres_spec.rb +226 -128
- data/spec/adapters/sqlite_spec.rb +50 -49
- data/spec/core/connection_pool_spec.rb +22 -0
- data/spec/core/database_spec.rb +53 -47
- data/spec/core/dataset_spec.rb +36 -32
- data/spec/core/expression_filters_spec.rb +14 -2
- data/spec/core/mock_adapter_spec.rb +4 -0
- data/spec/core/object_graph_spec.rb +0 -13
- data/spec/core/schema_spec.rb +64 -5
- data/spec/core_extensions_spec.rb +1 -0
- data/spec/extensions/constraint_validations_plugin_spec.rb +196 -0
- data/spec/extensions/constraint_validations_spec.rb +316 -0
- data/spec/extensions/defaults_setter_spec.rb +24 -0
- data/spec/extensions/eval_inspect_spec.rb +9 -0
- data/spec/extensions/identity_map_spec.rb +11 -2
- data/spec/extensions/pg_array_ops_spec.rb +9 -0
- data/spec/extensions/pg_row_ops_spec.rb +11 -1
- data/spec/extensions/pg_row_plugin_spec.rb +4 -0
- data/spec/extensions/schema_dumper_spec.rb +8 -5
- data/spec/extensions/subclasses_spec.rb +14 -0
- data/spec/extensions/validation_helpers_spec.rb +15 -2
- data/spec/integration/dataset_test.rb +75 -1
- data/spec/integration/plugin_test.rb +146 -0
- data/spec/integration/schema_test.rb +34 -0
- data/spec/model/dataset_methods_spec.rb +38 -0
- data/spec/model/hooks_spec.rb +6 -0
- data/spec/model/validations_spec.rb +27 -2
- metadata +8 -2
@@ -37,11 +37,25 @@ module Sequel
|
|
37
37
|
|
38
38
|
private
|
39
39
|
|
40
|
+
# Parse the cached database schema for this model and set the default values appropriately.
|
40
41
|
def set_default_values
|
41
42
|
h = {}
|
42
|
-
@db_schema.each{|k, v| h[k] = v[:ruby_default]
|
43
|
+
@db_schema.each{|k, v| h[k] = convert_default_value(v[:ruby_default]) unless v[:ruby_default].nil?} if @db_schema
|
43
44
|
@default_values = h
|
44
45
|
end
|
46
|
+
|
47
|
+
# Handle the CURRENT_DATE and CURRENT_TIMESTAMP values specially by returning an appropriate Date or
|
48
|
+
# Time/DateTime value.
|
49
|
+
def convert_default_value(v)
|
50
|
+
case v
|
51
|
+
when Sequel::CURRENT_DATE
|
52
|
+
lambda{Date.today}
|
53
|
+
when Sequel::CURRENT_TIMESTAMP
|
54
|
+
lambda{Sequel.datetime_class.now}
|
55
|
+
else
|
56
|
+
v
|
57
|
+
end
|
58
|
+
end
|
45
59
|
end
|
46
60
|
|
47
61
|
module InstanceMethods
|
data/lib/sequel/plugins/dirty.rb
CHANGED
@@ -14,7 +14,7 @@ module Sequel
|
|
14
14
|
# artist.name # => 'Foo'
|
15
15
|
# artist.column_changed?(:name) # false
|
16
16
|
#
|
17
|
-
# It
|
17
|
+
# It also makes changed_columns more accurate in that it
|
18
18
|
# can detect when a the column value is changed and then
|
19
19
|
# changed back:
|
20
20
|
#
|
@@ -183,7 +183,7 @@ module Sequel
|
|
183
183
|
|
184
184
|
# If the values hash does not contain the column, make sure missing_initial_values
|
185
185
|
# does so that it doesn't get deleted from changed_columns if changed back,
|
186
|
-
# and so that
|
186
|
+
# and so that resetting the column value can be handled correctly.
|
187
187
|
def check_missing_initial_value(column)
|
188
188
|
unless values.has_key?(column) || (miv = missing_initial_values).include?(column)
|
189
189
|
miv << column
|
@@ -153,7 +153,8 @@ module Sequel
|
|
153
153
|
# The identity map key for an object of the current class with the given pk.
|
154
154
|
# May not always be correct for a class which uses STI.
|
155
155
|
def identity_map_key(pk)
|
156
|
-
|
156
|
+
pk = Array(pk)
|
157
|
+
"#{self}:#{pk.join(',')}" unless pk.compact.empty?
|
157
158
|
end
|
158
159
|
|
159
160
|
# If the identity map is in use, check it for a current copy of the object.
|
@@ -164,12 +165,14 @@ module Sequel
|
|
164
165
|
# fields and request other, potentially overlapping fields in a new query,
|
165
166
|
# and not have the second query override fields you modified.
|
166
167
|
def call(row)
|
167
|
-
return super unless idm = identity_map
|
168
|
-
if
|
168
|
+
return super unless (idm = identity_map) && (pk = primary_key)
|
169
|
+
if (k = identity_map_key(Array(pk).map{|x| row[x]})) && (o = idm[k])
|
169
170
|
o.merge_db_update(row)
|
170
171
|
else
|
171
172
|
o = super
|
172
|
-
|
173
|
+
if (k = identity_map_key(o.pk))
|
174
|
+
idm[k] = o
|
175
|
+
end
|
173
176
|
end
|
174
177
|
o
|
175
178
|
end
|
@@ -196,7 +199,7 @@ module Sequel
|
|
196
199
|
# Check the current identity map if it exists for the object with
|
197
200
|
# the matching pk. If one is found, return it, otherwise call super.
|
198
201
|
def primary_key_lookup(pk)
|
199
|
-
(idm = identity_map
|
202
|
+
((idm = identity_map) && (k = identity_map_key(pk)) && (o = idm[k])) ? o : super
|
200
203
|
end
|
201
204
|
end
|
202
205
|
|
@@ -204,8 +207,8 @@ module Sequel
|
|
204
207
|
# Remove instances from the identity map cache if they are deleted.
|
205
208
|
def delete
|
206
209
|
super
|
207
|
-
if idm = model.identity_map
|
208
|
-
idm.delete(
|
210
|
+
if (idm = model.identity_map) && (k = model.identity_map_key(pk))
|
211
|
+
idm.delete(k)
|
209
212
|
end
|
210
213
|
self
|
211
214
|
end
|
@@ -239,7 +242,8 @@ module Sequel
|
|
239
242
|
if cache_lookup &&
|
240
243
|
!dynamic_opts[:callback] &&
|
241
244
|
(idm = klass.identity_map) &&
|
242
|
-
(
|
245
|
+
(k = klass.identity_map_key(_associated_object_pk(opts[:key]))) &&
|
246
|
+
(o = idm[k])
|
243
247
|
o
|
244
248
|
else
|
245
249
|
super
|
@@ -15,13 +15,27 @@ module Sequel
|
|
15
15
|
# sc2.subclasses # []
|
16
16
|
# ssc1.subclasses # []
|
17
17
|
# c.descendents # [sc1, ssc1, sc2]
|
18
|
+
#
|
19
|
+
# You can provide a block when loading the plugin, and it will be called
|
20
|
+
# with each subclass created:
|
21
|
+
#
|
22
|
+
# a = []
|
23
|
+
# Sequel::Model.plugin(:subclasses){|sc| a << sc}
|
24
|
+
# class A < Sequel::Model; end
|
25
|
+
# class B < Sequel::Model; end
|
26
|
+
# a # => [A, B]
|
18
27
|
module Subclasses
|
19
28
|
# Initialize the subclasses instance variable for the model.
|
20
|
-
def self.apply(model)
|
29
|
+
def self.apply(model, &block)
|
21
30
|
model.instance_variable_set(:@subclasses, [])
|
31
|
+
model.instance_variable_set(:@on_subclass, block)
|
22
32
|
end
|
23
33
|
|
24
34
|
module ClassMethods
|
35
|
+
# Callable object that should be called with every descendent
|
36
|
+
# class created.
|
37
|
+
attr_reader :on_subclass
|
38
|
+
|
25
39
|
# All subclasses for the current model. Does not
|
26
40
|
# include the model itself.
|
27
41
|
attr_reader :subclasses
|
@@ -38,6 +52,10 @@ module Sequel
|
|
38
52
|
super
|
39
53
|
Sequel.synchronize{subclasses << subclass}
|
40
54
|
subclass.instance_variable_set(:@subclasses, [])
|
55
|
+
if on_subclass
|
56
|
+
subclass.instance_variable_set(:@on_subclass, on_subclass)
|
57
|
+
on_subclass.call(subclass)
|
58
|
+
end
|
41
59
|
end
|
42
60
|
|
43
61
|
private
|
data/lib/sequel/plugins/tree.rb
CHANGED
@@ -4,7 +4,7 @@ module Sequel
|
|
4
4
|
# treat a Model as a tree.
|
5
5
|
#
|
6
6
|
# A column for holding the parent key is required and is :parent_id by default.
|
7
|
-
# This may be overridden by passing column name via :key
|
7
|
+
# This may be overridden by passing column name via :key.
|
8
8
|
#
|
9
9
|
# Optionally, a column to control order of nodes returned can be specified
|
10
10
|
# by passing column name via :order.
|
@@ -98,7 +98,7 @@ module Sequel
|
|
98
98
|
nodes
|
99
99
|
end
|
100
100
|
|
101
|
-
# Returns the root node of the tree that this node descends from
|
101
|
+
# Returns the root node of the tree that this node descends from.
|
102
102
|
# This node is returned if it is a root node itself.
|
103
103
|
def root
|
104
104
|
ancestors.last || self
|
@@ -124,7 +124,7 @@ module Sequel
|
|
124
124
|
end
|
125
125
|
end
|
126
126
|
|
127
|
-
# Plugin included when :single_root option is passed
|
127
|
+
# Plugin included when :single_root option is passed.
|
128
128
|
module SingleRoot
|
129
129
|
module ClassMethods
|
130
130
|
# Returns the single root node.
|
@@ -193,19 +193,39 @@ module Sequel
|
|
193
193
|
# since it can deal with a grouping of multiple attributes.
|
194
194
|
#
|
195
195
|
# Possible Options:
|
196
|
-
#
|
197
|
-
#
|
198
|
-
#
|
196
|
+
# :message :: The message to use (default: 'is already taken')
|
197
|
+
# :only_if_modified :: Only check the uniqueness if the object is new or
|
198
|
+
# one of the columns has been modified.
|
199
|
+
# :where :: A callable object where call takes three arguments, a dataset,
|
200
|
+
# the current object, and an array of columns, and should return
|
201
|
+
# a modified dataset that is filtered to include only rows with
|
202
|
+
# the same values as the current object for each column in the array.
|
203
|
+
#
|
204
|
+
# If you want to to a case insensitive uniqueness validation on a database that
|
205
|
+
# is case sensitive by default, you can use:
|
206
|
+
#
|
207
|
+
# :where=>(proc do |ds, obj, cols|
|
208
|
+
# ds.where(cols.map do |c|
|
209
|
+
# v = obj.send(c)
|
210
|
+
# v = v.downcase if v
|
211
|
+
# [Sequel.function(:lower, c), v]
|
212
|
+
# end)
|
213
|
+
# end)
|
199
214
|
def validates_unique(*atts)
|
200
215
|
opts = default_validation_helpers_options(:unique)
|
201
216
|
if atts.last.is_a?(Hash)
|
202
217
|
opts = opts.merge(atts.pop)
|
203
218
|
end
|
204
219
|
message = validation_error_message(opts[:message])
|
220
|
+
where = opts[:where]
|
205
221
|
atts.each do |a|
|
206
222
|
arr = Array(a)
|
207
223
|
next if opts[:only_if_modified] && !new? && !arr.any?{|x| changed_columns.include?(x)}
|
208
|
-
ds =
|
224
|
+
ds = if where
|
225
|
+
where.call(model.dataset, self, arr)
|
226
|
+
else
|
227
|
+
model.where(arr.map{|x| [x, send(x)]})
|
228
|
+
end
|
209
229
|
ds = yield(ds) if block_given?
|
210
230
|
ds = ds.exclude(pk_hash) unless new?
|
211
231
|
errors.add(a, message) unless ds.count == 0
|
data/lib/sequel/sql.rb
CHANGED
@@ -60,29 +60,38 @@ module Sequel
|
|
60
60
|
|
61
61
|
# Base class for all SQL expression objects.
|
62
62
|
class Expression
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
63
|
+
@comparison_attrs = []
|
64
|
+
|
65
|
+
class << self
|
66
|
+
# All attributes used for equality and hash methods.
|
67
|
+
attr_reader :comparison_attrs
|
68
|
+
|
69
|
+
# Expression objects are assumed to be value objects, where their
|
70
|
+
# attribute values can't change after assignment. In order to make
|
71
|
+
# it easy to define equality and hash methods, subclass
|
72
|
+
# instances assume that the only values that affect the results of
|
73
|
+
# such methods are the values of the object's attributes.
|
74
|
+
def attr_reader(*args)
|
75
|
+
super
|
76
|
+
comparison_attrs.concat(args)
|
77
|
+
end
|
72
78
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
79
|
+
# Copy the comparison_attrs into the subclass.
|
80
|
+
def inherited(subclass)
|
81
|
+
super
|
82
|
+
subclass.instance_variable_set(:@comparison_attrs, comparison_attrs.dup)
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
77
86
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
87
|
+
# Create a to_s instance method that takes a dataset, and calls
|
88
|
+
# the method provided on the dataset with args as the argument (self by default).
|
89
|
+
# Used to DRY up some code.
|
90
|
+
def to_s_method(meth, args=:self) # :nodoc:
|
91
|
+
class_eval("def to_s(ds) ds.#{meth}(#{args}) end", __FILE__, __LINE__)
|
92
|
+
class_eval("def to_s_append(ds, sql) ds.#{meth}_append(sql, #{args}) end", __FILE__, __LINE__)
|
93
|
+
end
|
84
94
|
end
|
85
|
-
private_class_method :to_s_method
|
86
95
|
|
87
96
|
# Alias of <tt>eql?</tt>
|
88
97
|
def ==(other)
|
@@ -140,6 +149,9 @@ module Sequel
|
|
140
149
|
# Bitwise mathematical operators used in +NumericMethods+
|
141
150
|
BITWISE_OPERATORS = [:&, :|, :^, :<<, :>>, :%]
|
142
151
|
|
152
|
+
# Operators that check for equality
|
153
|
+
EQUALITY_OPERATORS = [:'=', :'!=']
|
154
|
+
|
143
155
|
# Inequality operators used in +InequalityMethods+
|
144
156
|
INEQUALITY_OPERATORS = [:<, :>, :<=, :>=]
|
145
157
|
|
@@ -152,10 +164,14 @@ module Sequel
|
|
152
164
|
# Operators that use IS, used for special casing to override literal true/false values
|
153
165
|
IS_OPERATORS = [:IS, :'IS NOT']
|
154
166
|
|
167
|
+
# Operators that do pattern matching via regular expressions
|
168
|
+
REGEXP_OPERATORS = [:~, :'!~', :'~*', :'!~*']
|
169
|
+
|
170
|
+
# Operators that do pattern matching via LIKE
|
171
|
+
LIKE_OPERATORS = [:LIKE, :'NOT LIKE', :ILIKE, :'NOT ILIKE']
|
172
|
+
|
155
173
|
# Operator symbols that take exactly two arguments
|
156
|
-
TWO_ARITY_OPERATORS =
|
157
|
-
:~, :'!~', :'~*', :'!~*', :ILIKE, :'NOT ILIKE'] + \
|
158
|
-
INEQUALITY_OPERATORS + IS_OPERATORS + IN_OPERATORS
|
174
|
+
TWO_ARITY_OPERATORS = EQUALITY_OPERATORS + INEQUALITY_OPERATORS + IS_OPERATORS + IN_OPERATORS + REGEXP_OPERATORS + LIKE_OPERATORS
|
159
175
|
|
160
176
|
# Operator symbols that take one or more arguments
|
161
177
|
N_ARITY_OPERATORS = [:AND, :OR, :'||'] + MATHEMATICAL_OPERATORS + BITWISE_OPERATORS
|
@@ -352,6 +368,15 @@ module Sequel
|
|
352
368
|
cast(arg, sql_type || String).sql_string
|
353
369
|
end
|
354
370
|
|
371
|
+
# Return an emulated function call for getting the number of characters
|
372
|
+
# in the argument:
|
373
|
+
#
|
374
|
+
# Sequel.char_length(:a) # char_length(a) -- Most databases
|
375
|
+
# Sequel.char_length(:a) # length(a) -- SQLite
|
376
|
+
def char_length(arg)
|
377
|
+
SQL::EmulatedFunction.new(:char_length, arg)
|
378
|
+
end
|
379
|
+
|
355
380
|
# Order the given argument descending.
|
356
381
|
# Options:
|
357
382
|
#
|
@@ -567,6 +592,15 @@ module Sequel
|
|
567
592
|
SQL::Subscript.new(exp, subs.flatten)
|
568
593
|
end
|
569
594
|
|
595
|
+
# Return an emulated function call for trimming a string of spaces from
|
596
|
+
# both sides (similar to ruby's String#strip).
|
597
|
+
#
|
598
|
+
# Sequel.trim(:a) # trim(a) -- Most databases
|
599
|
+
# Sequel.trim(:a) # ltrim(rtrim(a)) -- Microsoft SQL Server
|
600
|
+
def trim(arg)
|
601
|
+
SQL::EmulatedFunction.new(:trim, arg)
|
602
|
+
end
|
603
|
+
|
570
604
|
# Return a <tt>SQL::ValueList</tt> created from the given array. Used if the array contains
|
571
605
|
# all two element arrays and you want it treated as an SQL value list (IN predicate)
|
572
606
|
# instead of as a conditions specifier (similar to a hash). This is not necessary if you are using
|
@@ -1071,7 +1105,7 @@ module Sequel
|
|
1071
1105
|
|
1072
1106
|
# Represents inverse boolean constants (currently only +NOTNULL+). A
|
1073
1107
|
# special class to allow for special behavior.
|
1074
|
-
class NegativeBooleanConstant <
|
1108
|
+
class NegativeBooleanConstant < Constant
|
1075
1109
|
to_s_method :negative_boolean_constant_sql, '@constant'
|
1076
1110
|
end
|
1077
1111
|
|
@@ -1110,6 +1144,12 @@ module Sequel
|
|
1110
1144
|
|
1111
1145
|
to_s_method :function_sql
|
1112
1146
|
end
|
1147
|
+
|
1148
|
+
# Represents an SQL function call that is translated/emulated
|
1149
|
+
# on databases that lack support for such a function.
|
1150
|
+
class EmulatedFunction < Function
|
1151
|
+
to_s_method :emulated_function_sql
|
1152
|
+
end
|
1113
1153
|
|
1114
1154
|
class GenericExpression
|
1115
1155
|
include AliasMethods
|
data/lib/sequel/timezones.rb
CHANGED
@@ -165,15 +165,23 @@ module Sequel
|
|
165
165
|
convert_input_timestamp(ary, input_timezone)
|
166
166
|
when Time
|
167
167
|
if datetime_class == DateTime
|
168
|
-
v.respond_to?(:to_datetime)
|
168
|
+
if v.respond_to?(:to_datetime)
|
169
|
+
v.to_datetime
|
170
|
+
else
|
171
|
+
# Ruby 1.8 code, %N not available and %z broken on Windows
|
172
|
+
offset_hours, offset_minutes = (v.utc_offset/60).divmod(60)
|
173
|
+
string_to_datetime(v.strftime("%Y-%m-%dT%H:%M:%S") << sprintf(".%06i%+03i%02i", v.usec, offset_hours, offset_minutes))
|
174
|
+
end
|
169
175
|
else
|
170
176
|
v
|
171
177
|
end
|
172
178
|
when DateTime
|
173
179
|
if datetime_class == DateTime
|
174
180
|
v
|
181
|
+
elsif v.respond_to?(:to_time)
|
182
|
+
v.to_time
|
175
183
|
else
|
176
|
-
|
184
|
+
string_to_datetime(v.strftime("%FT%T.%N%z"))
|
177
185
|
end
|
178
186
|
else
|
179
187
|
raise InvalidValue, "Invalid convert_input_timestamp type: #{v.inspect}"
|
data/lib/sequel/version.rb
CHANGED
@@ -3,7 +3,7 @@ module Sequel
|
|
3
3
|
MAJOR = 3
|
4
4
|
# The minor version of Sequel. Bumped for every non-patch level
|
5
5
|
# release, generally around once a month.
|
6
|
-
MINOR =
|
6
|
+
MINOR = 39
|
7
7
|
# The tiny version of Sequel. Usually 0, only bumped for bugfix
|
8
8
|
# releases that fix regressions from previous versions.
|
9
9
|
TINY = 0
|
data/spec/adapters/mssql_spec.rb
CHANGED
@@ -18,23 +18,6 @@ def logger.method_missing(m, msg)
|
|
18
18
|
end
|
19
19
|
MSSQL_DB.loggers = [logger]
|
20
20
|
|
21
|
-
MSSQL_DB.create_table! :test do
|
22
|
-
String :name, :type=>:text
|
23
|
-
Integer :value, :index => true
|
24
|
-
end
|
25
|
-
MSSQL_DB.create_table! :test2 do
|
26
|
-
String :name, :type=>:text
|
27
|
-
Integer :value
|
28
|
-
end
|
29
|
-
MSSQL_DB.create_table! :test3 do
|
30
|
-
Integer :value
|
31
|
-
Time :time
|
32
|
-
end
|
33
|
-
MSSQL_DB.create_table! :test4 do
|
34
|
-
String :name, :size => 20
|
35
|
-
column :value, 'varbinary(max)'
|
36
|
-
end
|
37
|
-
|
38
21
|
describe "A MSSQL database" do
|
39
22
|
before do
|
40
23
|
@db = MSSQL_DB
|
@@ -54,7 +37,20 @@ describe "A MSSQL database" do
|
|
54
37
|
proc{@db.server_version}.should_not raise_error
|
55
38
|
proc{@db.dataset.server_version}.should_not raise_error
|
56
39
|
end
|
40
|
+
end
|
57
41
|
|
42
|
+
describe "A MSSQL database" do
|
43
|
+
before do
|
44
|
+
@db = MSSQL_DB
|
45
|
+
@db.create_table! :test3 do
|
46
|
+
Integer :value
|
47
|
+
Time :time
|
48
|
+
end
|
49
|
+
end
|
50
|
+
after do
|
51
|
+
@db.drop_table?(:test3)
|
52
|
+
end
|
53
|
+
|
58
54
|
specify "should work with NOLOCK" do
|
59
55
|
@db.transaction{@db[:test3].nolock.all.should == []}
|
60
56
|
end
|
@@ -379,12 +375,15 @@ describe "MSSSQL::Dataset#insert" do
|
|
379
375
|
before do
|
380
376
|
@db = MSSQL_DB
|
381
377
|
@db.create_table!(:test5){primary_key :xid; Integer :value}
|
378
|
+
@db.create_table! :test4 do
|
379
|
+
String :name, :size => 20
|
380
|
+
column :value, 'varbinary(max)'
|
381
|
+
end
|
382
382
|
@db.sqls.clear
|
383
383
|
@ds = @db[:test5]
|
384
384
|
end
|
385
385
|
after do
|
386
|
-
@db
|
387
|
-
@db.drop_table?(:test5)
|
386
|
+
@db.drop_table?(:test5, :test4)
|
388
387
|
end
|
389
388
|
|
390
389
|
specify "should have insert_select return nil if disable_insert_output is used" do
|
@@ -409,11 +408,9 @@ describe "MSSSQL::Dataset#insert" do
|
|
409
408
|
b.length.should == blob.length
|
410
409
|
b.should == blob
|
411
410
|
end
|
412
|
-
end
|
413
411
|
|
414
|
-
describe "MSSSQL::Dataset#disable_insert_output" do
|
415
412
|
specify "should play nicely with simple_select_all?" do
|
416
|
-
MSSQL_DB[:
|
413
|
+
MSSQL_DB[:test4].disable_insert_output.send(:simple_select_all?).should == true
|
417
414
|
end
|
418
415
|
end
|
419
416
|
|
@@ -462,16 +459,20 @@ describe "A MSSQL database" do
|
|
462
459
|
end
|
463
460
|
|
464
461
|
describe "MSSQL::Database#rename_table" do
|
462
|
+
after do
|
463
|
+
MSSQL_DB.drop_table?(:foo)
|
464
|
+
end
|
465
|
+
|
465
466
|
specify "should work on non-schema bound tables which need escaping" do
|
466
467
|
MSSQL_DB.quote_identifiers = true
|
467
468
|
MSSQL_DB.create_table! :'foo bar' do
|
468
469
|
text :name
|
469
470
|
end
|
470
|
-
MSSQL_DB.drop_table? :
|
471
|
-
proc { MSSQL_DB.rename_table 'foo bar', '
|
471
|
+
MSSQL_DB.drop_table? :foo
|
472
|
+
proc { MSSQL_DB.rename_table 'foo bar', 'foo' }.should_not raise_error
|
472
473
|
end
|
473
474
|
|
474
|
-
specify "should
|
475
|
+
specify "should work on schema bound tables" do
|
475
476
|
MSSQL_DB.execute(<<-SQL)
|
476
477
|
IF NOT EXISTS (SELECT * FROM sys.schemas WHERE name = 'MY')
|
477
478
|
EXECUTE sp_executesql N'create schema MY'
|