sequel 3.40.0 → 3.41.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. data/CHANGELOG +40 -0
  2. data/README.rdoc +2 -2
  3. data/doc/advanced_associations.rdoc +12 -0
  4. data/doc/bin_sequel.rdoc +144 -0
  5. data/doc/migration.rdoc +1 -1
  6. data/doc/object_model.rdoc +29 -0
  7. data/doc/release_notes/3.41.0.txt +155 -0
  8. data/lib/sequel/adapters/ado.rb +4 -4
  9. data/lib/sequel/adapters/amalgalite.rb +0 -5
  10. data/lib/sequel/adapters/cubrid.rb +2 -2
  11. data/lib/sequel/adapters/db2.rb +9 -5
  12. data/lib/sequel/adapters/dbi.rb +4 -6
  13. data/lib/sequel/adapters/do.rb +4 -5
  14. data/lib/sequel/adapters/firebird.rb +8 -4
  15. data/lib/sequel/adapters/ibmdb.rb +2 -3
  16. data/lib/sequel/adapters/informix.rb +0 -6
  17. data/lib/sequel/adapters/jdbc.rb +11 -7
  18. data/lib/sequel/adapters/jdbc/db2.rb +22 -0
  19. data/lib/sequel/adapters/jdbc/derby.rb +5 -5
  20. data/lib/sequel/adapters/jdbc/h2.rb +0 -5
  21. data/lib/sequel/adapters/jdbc/jtds.rb +1 -1
  22. data/lib/sequel/adapters/jdbc/sqlserver.rb +6 -0
  23. data/lib/sequel/adapters/mock.rb +3 -3
  24. data/lib/sequel/adapters/mysql.rb +7 -7
  25. data/lib/sequel/adapters/mysql2.rb +0 -5
  26. data/lib/sequel/adapters/odbc.rb +4 -4
  27. data/lib/sequel/adapters/openbase.rb +4 -6
  28. data/lib/sequel/adapters/oracle.rb +14 -6
  29. data/lib/sequel/adapters/postgres.rb +12 -8
  30. data/lib/sequel/adapters/shared/db2.rb +5 -0
  31. data/lib/sequel/adapters/shared/firebird.rb +10 -0
  32. data/lib/sequel/adapters/shared/mssql.rb +43 -1
  33. data/lib/sequel/adapters/shared/mysql.rb +1 -0
  34. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +1 -1
  35. data/lib/sequel/adapters/shared/postgres.rb +12 -0
  36. data/lib/sequel/adapters/shared/sqlite.rb +32 -0
  37. data/lib/sequel/adapters/sqlite.rb +9 -8
  38. data/lib/sequel/adapters/swift.rb +3 -8
  39. data/lib/sequel/adapters/tinytds.rb +5 -5
  40. data/lib/sequel/connection_pool.rb +13 -19
  41. data/lib/sequel/connection_pool/sharded_single.rb +12 -12
  42. data/lib/sequel/connection_pool/sharded_threaded.rb +37 -17
  43. data/lib/sequel/connection_pool/single.rb +6 -3
  44. data/lib/sequel/connection_pool/threaded.rb +33 -13
  45. data/lib/sequel/database/connecting.rb +28 -1
  46. data/lib/sequel/database/logging.rb +1 -1
  47. data/lib/sequel/database/misc.rb +2 -5
  48. data/lib/sequel/database/query.rb +2 -2
  49. data/lib/sequel/database/schema_generator.rb +1 -1
  50. data/lib/sequel/database/schema_methods.rb +3 -0
  51. data/lib/sequel/dataset/query.rb +8 -4
  52. data/lib/sequel/dataset/sql.rb +7 -0
  53. data/lib/sequel/extensions/arbitrary_servers.rb +1 -1
  54. data/lib/sequel/extensions/connection_validator.rb +109 -0
  55. data/lib/sequel/extensions/pg_array.rb +2 -0
  56. data/lib/sequel/extensions/pg_hstore.rb +2 -0
  57. data/lib/sequel/extensions/pg_json.rb +4 -0
  58. data/lib/sequel/extensions/pg_range.rb +1 -0
  59. data/lib/sequel/extensions/pg_row.rb +4 -0
  60. data/lib/sequel/plugins/prepared_statements.rb +2 -1
  61. data/lib/sequel/plugins/single_table_inheritance.rb +53 -10
  62. data/lib/sequel/plugins/touch.rb +18 -6
  63. data/lib/sequel/plugins/validation_class_methods.rb +1 -0
  64. data/lib/sequel/plugins/validation_helpers.rb +3 -1
  65. data/lib/sequel/sql.rb +61 -19
  66. data/lib/sequel/version.rb +1 -1
  67. data/spec/adapters/firebird_spec.rb +52 -38
  68. data/spec/adapters/mssql_spec.rb +67 -0
  69. data/spec/adapters/mysql_spec.rb +192 -116
  70. data/spec/adapters/postgres_spec.rb +133 -70
  71. data/spec/adapters/spec_helper.rb +7 -0
  72. data/spec/adapters/sqlite_spec.rb +34 -1
  73. data/spec/core/connection_pool_spec.rb +79 -75
  74. data/spec/core/database_spec.rb +9 -4
  75. data/spec/core/dataset_spec.rb +15 -0
  76. data/spec/core/expression_filters_spec.rb +40 -2
  77. data/spec/extensions/connection_validator_spec.rb +118 -0
  78. data/spec/extensions/pg_array_spec.rb +4 -0
  79. data/spec/extensions/single_table_inheritance_spec.rb +42 -0
  80. data/spec/extensions/touch_spec.rb +40 -0
  81. data/spec/extensions/validation_class_methods_spec.rb +19 -1
  82. data/spec/extensions/validation_helpers_spec.rb +17 -0
  83. data/spec/integration/database_test.rb +14 -0
  84. data/spec/integration/dataset_test.rb +3 -3
  85. data/spec/integration/plugin_test.rb +41 -12
  86. data/spec/integration/schema_test.rb +14 -0
  87. data/spec/integration/spec_helper.rb +7 -0
  88. data/spec/integration/type_test.rb +3 -0
  89. metadata +9 -3
@@ -99,6 +99,8 @@ module Sequel
99
99
  module Postgres
100
100
  # Represents a PostgreSQL array column value.
101
101
  class PGArray < DelegateClass(Array)
102
+ include Sequel::SQL::AliasMethods
103
+
102
104
  ARRAY = "ARRAY".freeze
103
105
  DOUBLE_COLON = '::'.freeze
104
106
  EMPTY_BRACKET = '[]'.freeze
@@ -86,6 +86,8 @@ require 'strscan'
86
86
  module Sequel
87
87
  module Postgres
88
88
  class HStore < DelegateClass(Hash)
89
+ include Sequel::SQL::AliasMethods
90
+
89
91
  # Parser for PostgreSQL hstore output format.
90
92
  class Parser < StringScanner
91
93
  QUOTE_RE = /"/.freeze
@@ -63,6 +63,8 @@ module Sequel
63
63
 
64
64
  # Class representating PostgreSQL JSON column array values.
65
65
  class JSONArray < DelegateClass(Array)
66
+ include Sequel::SQL::AliasMethods
67
+
66
68
  # Convert the array to a string using to_json, append a
67
69
  # literalized version of the string to the sql, and explicitly
68
70
  # cast the string to json.
@@ -74,6 +76,8 @@ module Sequel
74
76
 
75
77
  # Class representating PostgreSQL JSON column hash/object values.
76
78
  class JSONHash < DelegateClass(Hash)
79
+ include Sequel::SQL::AliasMethods
80
+
77
81
  # Convert the array to a string using to_json, append a
78
82
  # literalized version of the string to the sql, and explicitly
79
83
  # cast the string to json.
@@ -59,6 +59,7 @@ Sequel.require 'adapters/utils/pg_types'
59
59
  module Sequel
60
60
  module Postgres
61
61
  class PGRange
62
+ include Sequel::SQL::AliasMethods
62
63
 
63
64
  # Map of string database type names to type symbols (e.g. 'int4range' => :int4range),
64
65
  # used in the schema parsing.
@@ -81,6 +81,8 @@ module Sequel
81
81
  # this is only used for generic PostgreSQL record types, as registered
82
82
  # types use HashRow by default.
83
83
  class ArrayRow < DelegateClass(Array)
84
+ include Sequel::SQL::AliasMethods
85
+
84
86
  class << self
85
87
  # The database type for this class. May be nil if this class
86
88
  # done not have a specific database type.
@@ -125,6 +127,8 @@ module Sequel
125
127
  # Types registered via Database#register_row_type will use this
126
128
  # class by default.
127
129
  class HashRow < DelegateClass(Hash)
130
+ include Sequel::SQL::AliasMethods
131
+
128
132
  class << self
129
133
  # The columns associated with this class.
130
134
  attr_accessor :columns
@@ -11,7 +11,8 @@ module Sequel
11
11
  # of prepared statements that can be created, unless you tightly control how your
12
12
  # model instances are saved.
13
13
  #
14
- # This plugin probably does not work correctly with the instance filters plugin.
14
+ # This plugin does not work correctly with the instance filters plugin
15
+ # or the update_primary_key plugin.
15
16
  #
16
17
  # Usage:
17
18
  #
@@ -35,6 +35,17 @@ module Sequel
35
35
  # Employee.plugin :single_table_inheritance, :type,
36
36
  # :model_map=>{'line staff'=>:Staff, 'supervisor'=>:Manager}
37
37
  #
38
+ # # By default the plugin sets the respective column value
39
+ # # when a new instance is created.
40
+ # Staff.create.type == 'line staff'
41
+ # Manager.create.type == 'supervisor'
42
+ #
43
+ # # You can customize this behavior with the :key_chooser option.
44
+ # # This is most useful when using a non-bijective mapping.
45
+ # Employee.plugin :single_table_inheritance, :type,
46
+ # :model_map=>{'line staff'=>:Staff, 'supervisor'=>:Manager},
47
+ # :key_chooser=>proc{|instance| instance.model.sti_key_map[instance.model.to_s].first || 'stranger' }
48
+ #
38
49
  # # Using custom procs, with :model_map taking column values
39
50
  # # and yielding either a class, string, symbol, or nil,
40
51
  # # and :key_map taking a class object and returning the column
@@ -43,6 +54,15 @@ module Sequel
43
54
  # :model_map=>proc{|v| v.reverse},
44
55
  # :key_map=>proc{|klass| klass.name.reverse}
45
56
  #
57
+ # # You can use the same class for multiple values.
58
+ # # This is mainly useful when the sti_key column contains multiple values
59
+ # # which are different but do not require different code.
60
+ # Employee.plugin :single_table_inheritance, :type,
61
+ # :model_map=>{'staff' => "Staff",
62
+ # 'manager => "Manager",
63
+ # 'overpayed staff => "Staff",
64
+ # 'underpayed staff' => "Staff"}
65
+ #
46
66
  # One minor issue to note is that if you specify the <tt>:key_map</tt>
47
67
  # option as a hash, instead of having it inferred from the <tt>:model_map</tt>,
48
68
  # you should only use class name strings as keys, you should not use symbols
@@ -57,20 +77,38 @@ module Sequel
57
77
  @sti_model_map = opts[:model_map] || lambda{|v| v if v && v != ''}
58
78
  @sti_key_map = if km = opts[:key_map]
59
79
  if km.is_a?(Hash)
60
- h = Hash.new{|h,k| h[k.to_s] unless k.is_a?(String)}
61
- h.merge!(km)
80
+ h = Hash.new do |h,k|
81
+ unless k.is_a?(String)
82
+ h[k.to_s]
83
+ else
84
+ []
85
+ end
86
+ end
87
+ km.each do |k,v|
88
+ h[k.to_s] = [ ] unless h.key?(k.to_s)
89
+ h[k.to_s].push( *Array(v) )
90
+ end
91
+ h
62
92
  else
63
93
  km
64
94
  end
65
95
  elsif sti_model_map.is_a?(Hash)
66
- h = Hash.new{|h,k| h[k.to_s] unless k.is_a?(String)}
96
+ h = Hash.new do |h,k|
97
+ unless k.is_a?(String)
98
+ h[k.to_s]
99
+ else
100
+ []
101
+ end
102
+ end
67
103
  sti_model_map.each do |k,v|
68
- h[v.to_s] = k
104
+ h[v.to_s] = [ ] unless h.key?(v.to_s)
105
+ h[v.to_s] << k
69
106
  end
70
107
  h
71
108
  else
72
109
  lambda{|klass| klass.name.to_s}
73
110
  end
111
+ @sti_key_chooser = opts[:key_chooser] || lambda{|inst| Array(inst.model.sti_key_map[inst.model]).last }
74
112
  dataset.row_proc = lambda{|r| model.sti_load(r)}
75
113
  end
76
114
  end
@@ -97,6 +135,10 @@ module Sequel
97
135
  # the value of the sti_key column to the appropriate class to use.
98
136
  attr_reader :sti_model_map
99
137
 
138
+ # A proc which returns the value to use for new instances.
139
+ # This defaults to a lookup in the key map.
140
+ attr_reader :sti_key_chooser
141
+
100
142
  # Copy the necessary attributes to the subclasses, and filter the
101
143
  # subclass's dataset based on the sti_kep_map entry for the class.
102
144
  def inherited(subclass)
@@ -105,18 +147,19 @@ module Sequel
105
147
  sd = sti_dataset
106
148
  skm = sti_key_map
107
149
  smm = sti_model_map
108
- key = skm[subclass]
150
+ skc = sti_key_chooser
151
+ key = Array(skm[subclass]).dup
109
152
  sti_subclass_added(key)
110
- ska = [key]
111
153
  rp = dataset.row_proc
112
- subclass.set_dataset(sd.filter(SQL::QualifiedIdentifier.new(table_name, sk)=>ska), :inherited=>true)
154
+ subclass.set_dataset(sd.filter(SQL::QualifiedIdentifier.new(table_name, sk)=>key), :inherited=>true)
113
155
  subclass.instance_eval do
114
156
  dataset.row_proc = rp
115
157
  @sti_key = sk
116
- @sti_key_array = ska
158
+ @sti_key_array = key
117
159
  @sti_dataset = sd
118
160
  @sti_key_map = skm
119
161
  @sti_model_map = smm
162
+ @sti_key_chooser = skc
120
163
  self.simple_table = nil
121
164
  end
122
165
  end
@@ -131,7 +174,7 @@ module Sequel
131
174
  # keys for all of their descendant classes.
132
175
  def sti_subclass_added(key)
133
176
  if sti_key_array
134
- Sequel.synchronize{sti_key_array << key}
177
+ Sequel.synchronize{sti_key_array.push(*Array(key))}
135
178
  superclass.sti_subclass_added(key)
136
179
  end
137
180
  end
@@ -159,7 +202,7 @@ module Sequel
159
202
  module InstanceMethods
160
203
  # Set the sti_key column based on the sti_key_map.
161
204
  def before_create
162
- send("#{model.sti_key}=", model.sti_key_map[model]) unless self[model.sti_key]
205
+ send("#{model.sti_key}=", model.sti_key_chooser.call(self)) unless self[model.sti_key]
163
206
  super
164
207
  end
165
208
  end
@@ -52,7 +52,7 @@ module Sequel
52
52
  attr_accessor :touch_column
53
53
 
54
54
  # A hash specifying the associations to touch when instances are
55
- # updated or destroyed. Keys are association dataset method name symbols and values
55
+ # updated or destroyed. Keys are association name symbols and values
56
56
  # are column name symbols.
57
57
  attr_reader :touched_associations
58
58
 
@@ -71,8 +71,8 @@ module Sequel
71
71
  associations.flatten.each do |a|
72
72
  a = {a=>touch_column} if a.is_a?(Symbol)
73
73
  a.each do |k,v|
74
- raise(Error, "invalid association: #{k}") unless r = association_reflection(k)
75
- touched_associations[r.dataset_method] = v
74
+ raise(Error, "invalid association: #{k}") unless association_reflection(k)
75
+ touched_associations[k] = v
76
76
  end
77
77
  end
78
78
  end
@@ -113,10 +113,22 @@ module Sequel
113
113
  Sequel::CURRENT_TIMESTAMP
114
114
  end
115
115
 
116
- # Directly update the database using the association dataset for each association.
116
+ # Update the updated at field for all associated objects that should be touched.
117
117
  def touch_associations
118
- model.touched_associations.each do |meth, column|
119
- send(meth).update(column=>touch_association_value)
118
+ model.touched_associations.each do |assoc, column|
119
+ r = model.association_reflection(assoc)
120
+ next unless r.can_have_associated_objects?(self)
121
+ ds = send(r.dataset_method)
122
+
123
+ if ds.send(:joined_dataset?)
124
+ # Can't update all values at once, so update each instance individually.
125
+ # Instead if doing a simple save, update via the instance's dataset,
126
+ # to avoid going into an infinite loop in some cases.
127
+ send(r[:name]).each{|x| x.this.update(column=>touch_association_value)}
128
+ else
129
+ # Update all values at once for performance reasons.
130
+ ds.update(column=>touch_association_value)
131
+ end
120
132
  end
121
133
  end
122
134
 
@@ -385,6 +385,7 @@ module Sequel
385
385
  error_field = a
386
386
  a = Array(a)
387
387
  v = Array(v)
388
+ next if v.empty? || !v.all?
388
389
  ds = o.class.filter(a.zip(v))
389
390
  num_dups = ds.count
390
391
  allow = if num_dups == 0
@@ -224,7 +224,9 @@ module Sequel
224
224
  ds = if where
225
225
  where.call(model.dataset, self, arr)
226
226
  else
227
- model.where(arr.map{|x| [x, send(x)]})
227
+ vals = arr.map{|x| send(x)}
228
+ next unless vals.all?
229
+ model.where(arr.zip(vals))
228
230
  end
229
231
  ds = yield(ds) if block_given?
230
232
  ds = ds.exclude(pk_hash) unless new?
data/lib/sequel/sql.rb CHANGED
@@ -377,6 +377,27 @@ module Sequel
377
377
  SQL::EmulatedFunction.new(:char_length, arg)
378
378
  end
379
379
 
380
+ # Return a delayed evaluation that uses the passed block. This is used
381
+ # to delay evaluations of the code to runtime. For example, with
382
+ # the following code:
383
+ #
384
+ # ds = DB[:table].where{column > Time.now}
385
+ #
386
+ # The filter is fixed to the time that where was called. Unless you are
387
+ # only using the dataset once immediately after creating it, that's
388
+ # probably not desired. If you just want to set it to the time when the
389
+ # query is sent to the database, you can wrap it in Sequel.delay:
390
+ #
391
+ # ds = DB[:table].where{column > Sequel.delay{Time.now}}
392
+ #
393
+ # Note that for dates and timestamps, you are probably better off using
394
+ # Sequel::CURRENT_DATE and Sequel::CURRENT_TIMESTAMP instead of this
395
+ # generic delayed evaluation facility.
396
+ def delay(&block)
397
+ raise(Error, "Sequel.delay requires a block") unless block
398
+ SQL::DelayedEvaluation.new(block)
399
+ end
400
+
380
401
  # Order the given argument descending.
381
402
  # Options:
382
403
  #
@@ -941,27 +962,33 @@ module Sequel
941
962
  # ~from_value_pairs(hash)
942
963
  # from_value_pairs(hash, :OR, true)
943
964
  def self.from_value_pairs(pairs, op=:AND, negate=false)
944
- pairs = pairs.collect do |l,r|
945
- ce = case r
946
- when Range
947
- new(:AND, new(:>=, l, r.begin), new(r.exclude_end? ? :< : :<=, l, r.end))
948
- when ::Array, ::Sequel::Dataset
949
- new(:IN, l, r)
950
- when NegativeBooleanConstant
951
- new(:"IS NOT", l, r.constant)
952
- when BooleanConstant
953
- new(:IS, l, r.constant)
954
- when NilClass, TrueClass, FalseClass
955
- new(:IS, l, r)
956
- when Regexp
957
- StringExpression.like(l, r)
958
- else
959
- new(:'=', l, r)
960
- end
961
- negate ? invert(ce) : ce
962
- end
965
+ pairs = pairs.map{|l,r| from_value_pair(l, r)}
966
+ pairs.map!{|ce| invert(ce)} if negate
963
967
  pairs.length == 1 ? pairs.at(0) : new(op, *pairs)
964
968
  end
969
+
970
+ # Return a BooleanExpression based on the right side of the pair.
971
+ def self.from_value_pair(l, r)
972
+ case r
973
+ when Range
974
+ new(:AND, new(:>=, l, r.begin), new(r.exclude_end? ? :< : :<=, l, r.end))
975
+ when ::Array, ::Sequel::Dataset
976
+ new(:IN, l, r)
977
+ when NegativeBooleanConstant
978
+ new(:"IS NOT", l, r.constant)
979
+ when BooleanConstant
980
+ new(:IS, l, r.constant)
981
+ when NilClass, TrueClass, FalseClass
982
+ new(:IS, l, r)
983
+ when Regexp
984
+ StringExpression.like(l, r)
985
+ when DelayedEvaluation
986
+ Sequel.delay{from_value_pair(l, r.callable.call)}
987
+ else
988
+ new(:'=', l, r)
989
+ end
990
+ end
991
+ private_class_method :from_value_pair
965
992
 
966
993
  # Invert the expression, if possible. If the expression cannot
967
994
  # be inverted, raise an error. An inverted expression should match everything that the
@@ -1140,6 +1167,21 @@ module Sequel
1140
1167
  Constants::NULL=>Constants::NOTNULL, Constants::NOTNULL=>Constants::NULL}
1141
1168
  end
1142
1169
 
1170
+ # Represents a delayed evaluation, encapsulating a callable
1171
+ # object which returns the value to use when called.
1172
+ class DelayedEvaluation < GenericExpression
1173
+ # A callable object that returns the value of the evaluation
1174
+ # when called.
1175
+ attr_reader :callable
1176
+
1177
+ # Set the callable object
1178
+ def initialize(callable)
1179
+ @callable = callable
1180
+ end
1181
+
1182
+ to_s_method :delayed_evaluation_sql, '@callable'
1183
+ end
1184
+
1143
1185
  # Represents an SQL function call.
1144
1186
  class Function < GenericExpression
1145
1187
  # The SQL function to call
@@ -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 = 40
6
+ MINOR = 41
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
@@ -253,68 +253,82 @@ describe "A Firebird database" do
253
253
 
254
254
  specify "should allow us to name the sequences" do
255
255
  @db.create_table(:posts){primary_key :id, :sequence_name => "seq_test"}
256
- @db.sqls.should == [
257
- "DROP SEQUENCE SEQ_TEST",
258
- "CREATE TABLE POSTS (ID integer PRIMARY KEY )",
259
- "CREATE SEQUENCE SEQ_TEST",
260
- " CREATE TRIGGER BI_POSTS_ID for POSTS\n ACTIVE BEFORE INSERT position 0\n as begin\n if ((new.ID is null) or (new.ID = 0)) then\n begin\n new.ID = next value for seq_test;\n end\n end\n\n"
261
- ]
256
+ check_sqls do
257
+ @db.sqls.should == [
258
+ "DROP SEQUENCE SEQ_TEST",
259
+ "CREATE TABLE POSTS (ID integer PRIMARY KEY )",
260
+ "CREATE SEQUENCE SEQ_TEST",
261
+ " CREATE TRIGGER BI_POSTS_ID for POSTS\n ACTIVE BEFORE INSERT position 0\n as begin\n if ((new.ID is null) or (new.ID = 0)) then\n begin\n new.ID = next value for seq_test;\n end\n end\n\n"
262
+ ]
263
+ end
262
264
  end
263
265
 
264
266
  specify "should allow us to set the starting position for the sequences" do
265
267
  @db.create_table(:posts){primary_key :id, :sequence_start_position => 999}
266
- @db.sqls.should == [
267
- "DROP SEQUENCE SEQ_POSTS_ID",
268
- "CREATE TABLE POSTS (ID integer PRIMARY KEY )",
269
- "CREATE SEQUENCE SEQ_POSTS_ID",
270
- "ALTER SEQUENCE SEQ_POSTS_ID RESTART WITH 999",
271
- " CREATE TRIGGER BI_POSTS_ID for POSTS\n ACTIVE BEFORE INSERT position 0\n as begin\n if ((new.ID is null) or (new.ID = 0)) then\n begin\n new.ID = next value for seq_posts_id;\n end\n end\n\n"
272
- ]
268
+ check_sqls do
269
+ @db.sqls.should == [
270
+ "DROP SEQUENCE SEQ_POSTS_ID",
271
+ "CREATE TABLE POSTS (ID integer PRIMARY KEY )",
272
+ "CREATE SEQUENCE SEQ_POSTS_ID",
273
+ "ALTER SEQUENCE SEQ_POSTS_ID RESTART WITH 999",
274
+ " CREATE TRIGGER BI_POSTS_ID for POSTS\n ACTIVE BEFORE INSERT position 0\n as begin\n if ((new.ID is null) or (new.ID = 0)) then\n begin\n new.ID = next value for seq_posts_id;\n end\n end\n\n"
275
+ ]
276
+ end
273
277
  end
274
278
 
275
279
  specify "should allow us to name and set the starting position for the sequences" do
276
280
  @db.create_table(:posts){primary_key :id, :sequence_name => "seq_test", :sequence_start_position => 999}
277
- @db.sqls.should == [
278
- "DROP SEQUENCE SEQ_TEST",
279
- "CREATE TABLE POSTS (ID integer PRIMARY KEY )",
280
- "CREATE SEQUENCE SEQ_TEST",
281
- "ALTER SEQUENCE SEQ_TEST RESTART WITH 999",
282
- " CREATE TRIGGER BI_POSTS_ID for POSTS\n ACTIVE BEFORE INSERT position 0\n as begin\n if ((new.ID is null) or (new.ID = 0)) then\n begin\n new.ID = next value for seq_test;\n end\n end\n\n"
283
- ]
281
+ check_sqls do
282
+ @db.sqls.should == [
283
+ "DROP SEQUENCE SEQ_TEST",
284
+ "CREATE TABLE POSTS (ID integer PRIMARY KEY )",
285
+ "CREATE SEQUENCE SEQ_TEST",
286
+ "ALTER SEQUENCE SEQ_TEST RESTART WITH 999",
287
+ " CREATE TRIGGER BI_POSTS_ID for POSTS\n ACTIVE BEFORE INSERT position 0\n as begin\n if ((new.ID is null) or (new.ID = 0)) then\n begin\n new.ID = next value for seq_test;\n end\n end\n\n"
288
+ ]
289
+ end
284
290
  end
285
291
 
286
292
  specify "should allow us to name the triggers" do
287
293
  @db.create_table(:posts){primary_key :id, :trigger_name => "trig_test"}
288
- @db.sqls.should == [
289
- "DROP SEQUENCE SEQ_POSTS_ID",
290
- "CREATE TABLE POSTS (ID integer PRIMARY KEY )",
291
- "CREATE SEQUENCE SEQ_POSTS_ID",
292
- " CREATE TRIGGER TRIG_TEST for POSTS\n ACTIVE BEFORE INSERT position 0\n as begin\n if ((new.ID is null) or (new.ID = 0)) then\n begin\n new.ID = next value for seq_posts_id;\n end\n end\n\n"
293
- ]
294
+ check_sqls do
295
+ @db.sqls.should == [
296
+ "DROP SEQUENCE SEQ_POSTS_ID",
297
+ "CREATE TABLE POSTS (ID integer PRIMARY KEY )",
298
+ "CREATE SEQUENCE SEQ_POSTS_ID",
299
+ " CREATE TRIGGER TRIG_TEST for POSTS\n ACTIVE BEFORE INSERT position 0\n as begin\n if ((new.ID is null) or (new.ID = 0)) then\n begin\n new.ID = next value for seq_posts_id;\n end\n end\n\n"
300
+ ]
301
+ end
294
302
  end
295
303
 
296
304
  specify "should allow us to not create the sequence" do
297
305
  @db.create_table(:posts){primary_key :id, :create_sequence => false}
298
- @db.sqls.should == [
299
- "CREATE TABLE POSTS (ID integer PRIMARY KEY )",
300
- " CREATE TRIGGER BI_POSTS_ID for POSTS\n ACTIVE BEFORE INSERT position 0\n as begin\n if ((new.ID is null) or (new.ID = 0)) then\n begin\n new.ID = next value for seq_posts_id;\n end\n end\n\n"
301
- ]
306
+ check_sqls do
307
+ @db.sqls.should == [
308
+ "CREATE TABLE POSTS (ID integer PRIMARY KEY )",
309
+ " CREATE TRIGGER BI_POSTS_ID for POSTS\n ACTIVE BEFORE INSERT position 0\n as begin\n if ((new.ID is null) or (new.ID = 0)) then\n begin\n new.ID = next value for seq_posts_id;\n end\n end\n\n"
310
+ ]
311
+ end
302
312
  end
303
313
 
304
314
  specify "should allow us to not create the trigger" do
305
315
  @db.create_table(:posts){primary_key :id, :create_trigger => false}
306
- @db.sqls.should == [
307
- "DROP SEQUENCE SEQ_POSTS_ID",
308
- "CREATE TABLE POSTS (ID integer PRIMARY KEY )",
309
- "CREATE SEQUENCE SEQ_POSTS_ID",
310
- ]
316
+ check_sqls do
317
+ @db.sqls.should == [
318
+ "DROP SEQUENCE SEQ_POSTS_ID",
319
+ "CREATE TABLE POSTS (ID integer PRIMARY KEY )",
320
+ "CREATE SEQUENCE SEQ_POSTS_ID",
321
+ ]
322
+ end
311
323
  end
312
324
 
313
325
  specify "should allow us to not create either the sequence nor the trigger" do
314
326
  @db.create_table(:posts){primary_key :id, :create_sequence => false, :create_trigger => false}
315
- @db.sqls.should == [
316
- "CREATE TABLE POSTS (ID integer PRIMARY KEY )"
317
- ]
327
+ check_sqls do
328
+ @db.sqls.should == [
329
+ "CREATE TABLE POSTS (ID integer PRIMARY KEY )"
330
+ ]
331
+ end
318
332
  end
319
333
 
320
334
  specify "should support column operations" do