sequel 3.44.0 → 3.45.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 (97) hide show
  1. data/CHANGELOG +44 -0
  2. data/Rakefile +12 -4
  3. data/doc/reflection.rdoc +3 -3
  4. data/doc/release_notes/3.45.0.txt +179 -0
  5. data/doc/schema_modification.rdoc +1 -1
  6. data/doc/transactions.rdoc +23 -0
  7. data/lib/sequel/adapters/db2.rb +1 -0
  8. data/lib/sequel/adapters/ibmdb.rb +19 -3
  9. data/lib/sequel/adapters/jdbc.rb +15 -0
  10. data/lib/sequel/adapters/jdbc/derby.rb +1 -5
  11. data/lib/sequel/adapters/jdbc/h2.rb +1 -0
  12. data/lib/sequel/adapters/jdbc/hsqldb.rb +2 -1
  13. data/lib/sequel/adapters/jdbc/jtds.rb +5 -0
  14. data/lib/sequel/adapters/jdbc/mysql.rb +5 -0
  15. data/lib/sequel/adapters/jdbc/oracle.rb +7 -1
  16. data/lib/sequel/adapters/jdbc/sqlite.rb +1 -1
  17. data/lib/sequel/adapters/jdbc/transactions.rb +28 -1
  18. data/lib/sequel/adapters/mysql.rb +4 -0
  19. data/lib/sequel/adapters/mysql2.rb +5 -1
  20. data/lib/sequel/adapters/oracle.rb +18 -0
  21. data/lib/sequel/adapters/postgres.rb +11 -1
  22. data/lib/sequel/adapters/shared/access.rb +14 -2
  23. data/lib/sequel/adapters/shared/cubrid.rb +1 -11
  24. data/lib/sequel/adapters/shared/db2.rb +11 -6
  25. data/lib/sequel/adapters/shared/mssql.rb +10 -10
  26. data/lib/sequel/adapters/shared/mysql.rb +11 -1
  27. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +17 -1
  28. data/lib/sequel/adapters/shared/oracle.rb +16 -15
  29. data/lib/sequel/adapters/shared/postgres.rb +91 -59
  30. data/lib/sequel/adapters/shared/sqlite.rb +1 -4
  31. data/lib/sequel/adapters/tinytds.rb +15 -0
  32. data/lib/sequel/connection_pool/threaded.rb +1 -1
  33. data/lib/sequel/core.rb +10 -0
  34. data/lib/sequel/database/connecting.rb +2 -0
  35. data/lib/sequel/database/misc.rb +46 -4
  36. data/lib/sequel/database/query.rb +33 -14
  37. data/lib/sequel/database/schema_methods.rb +0 -5
  38. data/lib/sequel/dataset/misc.rb +9 -0
  39. data/lib/sequel/dataset/mutation.rb +9 -7
  40. data/lib/sequel/dataset/sql.rb +13 -0
  41. data/lib/sequel/exceptions.rb +3 -0
  42. data/lib/sequel/extensions/connection_validator.rb +1 -1
  43. data/lib/sequel/extensions/date_arithmetic.rb +0 -8
  44. data/lib/sequel/extensions/eval_inspect.rb +2 -0
  45. data/lib/sequel/extensions/named_timezones.rb +18 -2
  46. data/lib/sequel/extensions/pg_array.rb +5 -1
  47. data/lib/sequel/extensions/pg_array_ops.rb +2 -0
  48. data/lib/sequel/extensions/pg_hstore.rb +2 -0
  49. data/lib/sequel/extensions/pg_hstore_ops.rb +2 -0
  50. data/lib/sequel/extensions/pg_json.rb +3 -1
  51. data/lib/sequel/extensions/pg_range.rb +2 -0
  52. data/lib/sequel/extensions/pg_range_ops.rb +2 -0
  53. data/lib/sequel/extensions/pg_row.rb +2 -0
  54. data/lib/sequel/extensions/pg_row_ops.rb +2 -0
  55. data/lib/sequel/extensions/query.rb +18 -22
  56. data/lib/sequel/model/associations.rb +3 -4
  57. data/lib/sequel/model/base.rb +2 -0
  58. data/lib/sequel/plugins/force_encoding.rb +2 -0
  59. data/lib/sequel/plugins/json_serializer.rb +155 -39
  60. data/lib/sequel/plugins/serialization.rb +14 -2
  61. data/lib/sequel/plugins/unlimited_update.rb +31 -0
  62. data/lib/sequel/plugins/validation_class_methods.rb +6 -4
  63. data/lib/sequel/plugins/xml_serializer.rb +133 -30
  64. data/lib/sequel/sql.rb +2 -0
  65. data/lib/sequel/timezones.rb +4 -0
  66. data/lib/sequel/version.rb +1 -1
  67. data/spec/adapters/mysql_spec.rb +0 -11
  68. data/spec/adapters/postgres_spec.rb +86 -54
  69. data/spec/adapters/spec_helper.rb +6 -0
  70. data/spec/core/connection_pool_spec.rb +16 -0
  71. data/spec/core/database_spec.rb +77 -1
  72. data/spec/core/dataset_spec.rb +30 -15
  73. data/spec/core/expression_filters_spec.rb +55 -13
  74. data/spec/core/mock_adapter_spec.rb +4 -0
  75. data/spec/core/schema_spec.rb +0 -2
  76. data/spec/core/spec_helper.rb +5 -0
  77. data/spec/core_extensions_spec.rb +33 -28
  78. data/spec/extensions/constraint_validations_spec.rb +2 -2
  79. data/spec/extensions/core_refinements_spec.rb +12 -12
  80. data/spec/extensions/json_serializer_spec.rb +137 -31
  81. data/spec/extensions/named_timezones_spec.rb +10 -0
  82. data/spec/extensions/pg_auto_parameterize_spec.rb +5 -0
  83. data/spec/extensions/pg_json_spec.rb +14 -0
  84. data/spec/extensions/pg_row_spec.rb +11 -0
  85. data/spec/extensions/pretty_table_spec.rb +2 -2
  86. data/spec/extensions/query_spec.rb +11 -8
  87. data/spec/extensions/serialization_spec.rb +20 -0
  88. data/spec/extensions/spec_helper.rb +8 -2
  89. data/spec/extensions/sql_expr_spec.rb +1 -1
  90. data/spec/extensions/unlimited_update_spec.rb +20 -0
  91. data/spec/extensions/xml_serializer_spec.rb +68 -16
  92. data/spec/integration/dataset_test.rb +28 -0
  93. data/spec/integration/spec_helper.rb +6 -0
  94. data/spec/integration/transaction_test.rb +39 -0
  95. data/spec/model/model_spec.rb +1 -1
  96. data/spec/sequel_coverage.rb +15 -0
  97. metadata +8 -3
@@ -0,0 +1,31 @@
1
+ module Sequel
2
+ module Plugins
3
+ # The unlimited_update plugin is designed to work around a
4
+ # MySQL warning in replicated environments, which occurs if
5
+ # you issue an UPDATE with a LIMIT clause. No other
6
+ # database Sequel supports will create an UPDATE clause with
7
+ # a LIMIT, and in non-replicated MySQL environments, MySQL
8
+ # doesn't issue a warning. Note that even in replicated
9
+ # environments the MySQL warning is harmless, as Sequel
10
+ # restricts an update to rows with a matching primary key,
11
+ # which should be unique.
12
+ #
13
+ # Usage:
14
+ #
15
+ # # Make all model subclass not use a limit for update
16
+ # Sequel::Model.plugin :unlimited_update
17
+ #
18
+ # # Make the Album class not use a limit for update
19
+ # Album.plugin :unlimited_update
20
+ module UnlimitedUpdate
21
+ module InstanceMethods
22
+ private
23
+
24
+ # Use an unlimited dataset for updates.
25
+ def _update_dataset
26
+ super.unlimited
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -432,10 +432,12 @@ module Sequel
432
432
  # Handle the :if option for validations
433
433
  def validation_if_proc(o, i)
434
434
  case i
435
- when Symbol then o.send(i)
436
- when Proc then o.instance_eval(&i)
437
- when nil then true
438
- else raise(::Sequel::Error, "invalid value for :if validation option")
435
+ when Symbol
436
+ o.send(i)
437
+ when Proc
438
+ o.instance_eval(&i)
439
+ else
440
+ raise(::Sequel::Error, "invalid value for :if validation option")
439
441
  end
440
442
  end
441
443
  end
@@ -57,32 +57,54 @@ module Sequel
57
57
  # </artist>
58
58
  # </album>
59
59
  #
60
+ # +to_xml+ also exists as a class and dataset method, both
61
+ # of which return all objects in the dataset:
62
+ #
63
+ # Album.to_xml
64
+ # Album.filter(:artist_id=>1).to_xml(:include=>:tags)
65
+ #
66
+ # If you have an existing array of model instances you want to convert to
67
+ # XML, you can call the class to_xml method with the :array option:
68
+ #
69
+ # Album.to_xml(:array=>[Album[1], Album[2]])
70
+ #
60
71
  # In addition to creating XML, this plugin also enables Sequel::Model
61
- # objects to be created by parsing XML:
72
+ # classes to create instances directly from XML using the from_xml class
73
+ # method:
62
74
  #
63
75
  # xml = album.to_xml
64
76
  # album = Album.from_xml(xml)
65
77
  #
66
- # In addition, you can update existing model objects directly from XML
67
- # using +from_xml+:
78
+ # The array_from_xml class method exists to parse arrays of model instances
79
+ # from xml:
68
80
  #
69
- # album.from_xml(xml)
81
+ # xml = Album.filter(:artist_id=>1).to_xml
82
+ # albums = Album.array_from_xml(xml)
70
83
  #
71
- # Additionally, +to_xml+ also exists as a class and dataset method, both
72
- # of which return all objects in the dataset:
84
+ # These does not necessarily round trip, since doing so would let users
85
+ # create model objects with arbitrary values. By default, from_xml will
86
+ # call set using values from the tags in the xml. If you want to specify the allowed
87
+ # fields, you can use the :fields option, which will call set_fields with
88
+ # the given fields:
73
89
  #
74
- # Album.to_xml
75
- # Album.filter(:artist_id=>1).to_xml(:include=>:tags)
90
+ # Album.from_xml(album.to_xml, :fields=>%w'id name')
76
91
  #
77
- # Such XML can be loaded back into an array of Sequel::Model objects using
78
- # +array_from_xml+:
92
+ # If you want to update an existing instance, you can use the from_xml
93
+ # instance method:
79
94
  #
80
- # Album.array_from_xml(Album.to_xml) # same as Album.all
95
+ # album.from_xml(xml)
81
96
  #
82
- # If you have an existing array of model instances you want to convert to
83
- # XML, you can call the class to_xml method with the :array option:
97
+ # Both of these allow creation of cached associated objects, if you provide
98
+ # the :associations option:
84
99
  #
85
- # Album.to_xml(:array=>[Album[1], Album[2]])
100
+ # album.from_xml(xml, :associations=>:artist)
101
+ #
102
+ # You can even provide options when setting up the associated objects:
103
+ #
104
+ # album.from_xml(xml, :associations=>{:artist=>{:fields=>%w'id name', :associations=>:tags}})
105
+ #
106
+ # If the xml is trusted and should be allowed to set all column and association
107
+ # values, you can use the :all_columns and :all_associations options.
86
108
  #
87
109
  # Usage:
88
110
  #
@@ -109,7 +131,11 @@ module Sequel
109
131
  # Return an array of instances of this class based on
110
132
  # the provided XML.
111
133
  def array_from_xml(xml, opts={})
112
- Nokogiri::XML(xml).children.first.children.reject{|c| c.is_a?(Nokogiri::XML::Text)}.map{|c| from_xml_node(c, opts)}
134
+ node = Nokogiri::XML(xml).children.first
135
+ unless node
136
+ raise Error, "Malformed XML used"
137
+ end
138
+ node.children.reject{|c| c.is_a?(Nokogiri::XML::Text)}.map{|c| from_xml_node(c, opts)}
113
139
  end
114
140
 
115
141
  # Return an instance of this class based on the provided
@@ -193,30 +219,107 @@ module Sequel
193
219
 
194
220
  # Update the contents of this instance based on the given
195
221
  # XML node, which should be a Nokogiri::XML::Node instance.
222
+ # By default, just calls set with a hash created from the content of the node.
223
+ #
224
+ # Options:
225
+ # :all_associations :: Indicates that all associations supported by the model should be tried.
226
+ # This option also cascades to associations if used. It is better to use the
227
+ # :associations option instead of this option. This option only exists for
228
+ # backwards compatibility.
229
+ # :all_columns :: Overrides the setting logic allowing all setter methods be used,
230
+ # even if access to the setter method is restricted.
231
+ # This option cascades to associations if used, and can be reset in those associations
232
+ # using the :all_columns=>false or :fields options. This option is considered a
233
+ # security risk, and only exists for backwards compatibility. It is better to use
234
+ # the :fields option appropriately instead of this option, or no option at all.
235
+ # :associations :: Indicates that the associations cache should be updated by creating
236
+ # a new associated object using data from the hash. Should be a Symbol
237
+ # for a single association, an array of symbols for multiple associations,
238
+ # or a hash with symbol keys and dependent association option hash values.
239
+ # :fields :: Changes the behavior to call set_fields using the provided fields, instead of calling set.
196
240
  def from_xml_node(parent, opts={})
197
- cols = model.columns.map{|x| x.to_s}
198
- assocs = {}
199
- model.associations.map{|x| assocs[x.to_s] = model.association_reflection(x)}
200
- meths = send(:setter_methods, nil, nil)
241
+ unless parent
242
+ raise Error, "Malformed XML used"
243
+ end
244
+ if !parent.children.empty? && parent.children.all?{|node| node.is_a?(Nokogiri::XML::Text)}
245
+ raise Error, "XML consisting of just text nodes used"
246
+ end
247
+
248
+ unless assocs = opts[:associations]
249
+ if opts[:all_associations]
250
+ assocs = {}
251
+ model.associations.each{|v| assocs[v] = {:all_associations=>true}}
252
+ end
253
+ end
254
+
255
+ if assocs
256
+ assocs = case assocs
257
+ when Symbol
258
+ {assocs=>{}}
259
+ when Array
260
+ assocs_tmp = {}
261
+ assocs.each{|v| assocs_tmp[v] = {}}
262
+ assocs_tmp
263
+ when Hash
264
+ assocs
265
+ else
266
+ raise Error, ":associations should be Symbol, Array, or Hash if present"
267
+ end
268
+
269
+ if opts[:all_columns]
270
+ assocs.each_value do |assoc_opts|
271
+ assoc_opts[:all_columns] = true unless assoc_opts.has_key?(:fields) || assoc_opts.has_key?(:all_columns)
272
+ end
273
+ end
274
+
275
+ assocs_hash = {}
276
+ assocs.each{|k,v| assocs_hash[k.to_s] = v}
277
+ assocs_present = []
278
+ end
279
+
280
+ hash = {}
201
281
  name_proc = model.xml_deserialize_name_proc(opts)
202
282
  parent.children.each do |node|
203
283
  next if node.is_a?(Nokogiri::XML::Text)
204
284
  k = name_proc[node.name]
205
- if ar = assocs[k]
206
- klass = ar.associated_class
207
- associations[k.to_sym] = if ar.returns_array?
208
- node.children.reject{|c| c.is_a?(Nokogiri::XML::Text)}.map{|c| klass.from_xml_node(c)}
285
+ if assocs_hash && (assoc = assocs_hash[k])
286
+ assocs_present << [k.to_sym, node]
287
+ else
288
+ hash[k] = node.key?('nil') ? nil : node.children.first.to_s
289
+ end
290
+ end
291
+
292
+ if assocs_present
293
+ assocs_present.each do |assoc, node|
294
+ assoc_opts = assocs[assoc]
295
+
296
+ unless r = model.association_reflection(assoc)
297
+ raise Error, "Association #{assoc} is not defined for #{model}"
298
+ end
299
+
300
+ associations[assoc] = if r.returns_array?
301
+ node.children.reject{|c| c.is_a?(Nokogiri::XML::Text)}.map{|c| r.associated_class.from_xml_node(c, assoc_opts)}
209
302
  else
210
- klass.from_xml_node(node)
303
+ r.associated_class.from_xml_node(node, assoc_opts)
304
+ end
305
+ end
306
+ end
307
+
308
+ if fields = opts[:fields]
309
+ set_fields(hash, fields, opts)
310
+ elsif opts[:all_columns]
311
+ meths = methods.collect{|x| x.to_s}.grep(Model::SETTER_METHOD_REGEXP) - Model::RESTRICTED_SETTER_METHODS
312
+ hash.each do |k, v|
313
+ if meths.include?(setter_meth = "#{k}=")
314
+ send(setter_meth, v)
315
+ else
316
+ raise Error, "Entry in XML does not have a matching setter method: #{k}"
211
317
  end
212
- elsif cols.include?(k)
213
- self[k.to_sym] = node.key?('nil') ? nil : node.children.first.to_s
214
- elsif meths.include?("#{k}=")
215
- send("#{k}=", node.key?('nil') ? nil : node.children.first.to_s)
216
- else
217
- raise Error, "Entry in XML not an association or column and no setter method exists: #{k}"
218
318
  end
319
+ else
320
+ set(hash)
219
321
  end
322
+
220
323
  self
221
324
  end
222
325
 
@@ -1,5 +1,6 @@
1
1
  module Sequel
2
2
  if RUBY_VERSION < '1.9.0'
3
+ # :nocov:
3
4
  # If on Ruby 1.8, create a <tt>Sequel::BasicObject</tt> class that is similar to the
4
5
  # the Ruby 1.9 +BasicObject+ class. This is used in a few places where proxy
5
6
  # objects are needed that respond to any method call.
@@ -16,6 +17,7 @@ module Sequel
16
17
  end
17
18
  remove_methods!
18
19
  end
20
+ # :nocov:
19
21
  else
20
22
  # If on 1.9, create a <tt>Sequel::BasicObject</tt> class that is just like the
21
23
  # default +BasicObject+ class, except that missing constants are resolved in
@@ -168,9 +168,11 @@ module Sequel
168
168
  if v.respond_to?(:to_datetime)
169
169
  v.to_datetime
170
170
  else
171
+ # :nocov:
171
172
  # Ruby 1.8 code, %N not available and %z broken on Windows
172
173
  offset_hours, offset_minutes = (v.utc_offset/60).divmod(60)
173
174
  string_to_datetime(v.strftime("%Y-%m-%dT%H:%M:%S") << sprintf(".%06i%+03i%02i", v.usec, offset_hours, offset_minutes))
175
+ # :nocov:
174
176
  end
175
177
  else
176
178
  v
@@ -181,7 +183,9 @@ module Sequel
181
183
  elsif v.respond_to?(:to_time)
182
184
  v.to_time
183
185
  else
186
+ # :nocov:
184
187
  string_to_datetime(v.strftime("%FT%T.%N%z"))
188
+ # :nocov:
185
189
  end
186
190
  else
187
191
  raise InvalidValue, "Invalid convert_input_timestamp type: #{v.inspect}"
@@ -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 = 44
6
+ MINOR = 45
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
@@ -1105,17 +1105,6 @@ describe "MySQL::Dataset#complex_expression_sql" do
1105
1105
  @d = MYSQL_DB.dataset
1106
1106
  end
1107
1107
 
1108
- specify "should handle pattern matches correctly" do
1109
- @d.literal(Sequel.expr(:x).like('a')).should == "(`x` LIKE BINARY 'a')"
1110
- @d.literal(~Sequel.expr(:x).like('a')).should == "(`x` NOT LIKE BINARY 'a')"
1111
- @d.literal(Sequel.expr(:x).ilike('a')).should == "(`x` LIKE 'a')"
1112
- @d.literal(~Sequel.expr(:x).ilike('a')).should == "(`x` NOT LIKE 'a')"
1113
- @d.literal(Sequel.expr(:x).like(/a/)).should == "(`x` REGEXP BINARY 'a')"
1114
- @d.literal(~Sequel.expr(:x).like(/a/)).should == "(`x` NOT REGEXP BINARY 'a')"
1115
- @d.literal(Sequel.expr(:x).like(/a/i)).should == "(`x` REGEXP 'a')"
1116
- @d.literal(~Sequel.expr(:x).like(/a/i)).should == "(`x` NOT REGEXP 'a')"
1117
- end
1118
-
1119
1108
  specify "should handle string concatenation with CONCAT if more than one record" do
1120
1109
  @d.literal(Sequel.join([:x, :y])).should == "CONCAT(`x`, `y`)"
1121
1110
  @d.literal(Sequel.join([:x, :y], ' ')).should == "CONCAT(`x`, ' ', `y`)"
@@ -83,6 +83,16 @@ describe "A PostgreSQL database" do
83
83
  @db.server_version.should > 70000
84
84
  end
85
85
 
86
+ specify "should support a :qualify option to tables and views" do
87
+ @db.tables(:qualify=>true).should include(Sequel.qualify(:public, :testfk))
88
+ begin
89
+ @db.create_view(:testfkv, @db[:testfk])
90
+ @db.views(:qualify=>true).should include(Sequel.qualify(:public, :testfkv))
91
+ ensure
92
+ @db.drop_view(:testfkv)
93
+ end
94
+ end
95
+
86
96
  specify "should not typecast the int2vector type incorrectly" do
87
97
  @db.get(Sequel.cast('10 20', :int2vector)).should_not == 10
88
98
  end
@@ -790,109 +800,131 @@ end
790
800
 
791
801
  describe "Postgres::Database schema qualified tables" do
792
802
  before do
793
- POSTGRES_DB << "CREATE SCHEMA schema_test"
794
- POSTGRES_DB.instance_variable_set(:@primary_keys, {})
795
- POSTGRES_DB.instance_variable_set(:@primary_key_sequences, {})
803
+ @db = POSTGRES_DB
804
+ @db << "CREATE SCHEMA schema_test"
805
+ @db.instance_variable_set(:@primary_keys, {})
806
+ @db.instance_variable_set(:@primary_key_sequences, {})
796
807
  end
797
808
  after do
798
- POSTGRES_DB << "DROP SCHEMA schema_test CASCADE"
799
- POSTGRES_DB.default_schema = nil
809
+ @db << "DROP SCHEMA schema_test CASCADE"
810
+ @db.default_schema = nil
800
811
  end
801
812
 
802
813
  specify "should be able to create, drop, select and insert into tables in a given schema" do
803
- POSTGRES_DB.create_table(:schema_test__schema_test){primary_key :i}
804
- POSTGRES_DB[:schema_test__schema_test].first.should == nil
805
- POSTGRES_DB[:schema_test__schema_test].insert(:i=>1).should == 1
806
- POSTGRES_DB[:schema_test__schema_test].first.should == {:i=>1}
807
- POSTGRES_DB.from(Sequel.lit('schema_test.schema_test')).first.should == {:i=>1}
808
- POSTGRES_DB.drop_table(:schema_test__schema_test)
809
- POSTGRES_DB.create_table(Sequel.qualify(:schema_test, :schema_test)){integer :i}
810
- POSTGRES_DB[:schema_test__schema_test].first.should == nil
811
- POSTGRES_DB.from(Sequel.lit('schema_test.schema_test')).first.should == nil
812
- POSTGRES_DB.drop_table(Sequel.qualify(:schema_test, :schema_test))
814
+ @db.create_table(:schema_test__schema_test){primary_key :i}
815
+ @db[:schema_test__schema_test].first.should == nil
816
+ @db[:schema_test__schema_test].insert(:i=>1).should == 1
817
+ @db[:schema_test__schema_test].first.should == {:i=>1}
818
+ @db.from(Sequel.lit('schema_test.schema_test')).first.should == {:i=>1}
819
+ @db.drop_table(:schema_test__schema_test)
820
+ @db.create_table(Sequel.qualify(:schema_test, :schema_test)){integer :i}
821
+ @db[:schema_test__schema_test].first.should == nil
822
+ @db.from(Sequel.lit('schema_test.schema_test')).first.should == nil
823
+ @db.drop_table(Sequel.qualify(:schema_test, :schema_test))
813
824
  end
814
825
 
815
826
  specify "#tables should not include tables in a default non-public schema" do
816
- POSTGRES_DB.create_table(:schema_test__schema_test){integer :i}
817
- POSTGRES_DB.tables.should include(:schema_test)
818
- POSTGRES_DB.tables.should_not include(:pg_am)
819
- POSTGRES_DB.tables.should_not include(:domain_udt_usage)
827
+ @db.create_table(:schema_test__schema_test){integer :i}
828
+ @db.tables.should include(:schema_test)
829
+ @db.tables.should_not include(:pg_am)
830
+ @db.tables.should_not include(:domain_udt_usage)
820
831
  end
821
832
 
822
833
  specify "#tables should return tables in the schema provided by the :schema argument" do
823
- POSTGRES_DB.create_table(:schema_test__schema_test){integer :i}
824
- POSTGRES_DB.tables(:schema=>:schema_test).should == [:schema_test]
834
+ @db.create_table(:schema_test__schema_test){integer :i}
835
+ @db.tables(:schema=>:schema_test).should == [:schema_test]
825
836
  end
826
837
 
827
838
  specify "#schema should not include columns from tables in a default non-public schema" do
828
- POSTGRES_DB.create_table(:schema_test__domains){integer :i}
829
- sch = POSTGRES_DB.schema(:domains)
839
+ @db.create_table(:schema_test__domains){integer :i}
840
+ sch = @db.schema(:schema_test__domains)
830
841
  cs = sch.map{|x| x.first}
831
842
  cs.should include(:i)
832
843
  cs.should_not include(:data_type)
833
844
  end
834
845
 
835
846
  specify "#schema should only include columns from the table in the given :schema argument" do
836
- POSTGRES_DB.create_table!(:domains){integer :d}
837
- POSTGRES_DB.create_table(:schema_test__domains){integer :i}
838
- sch = POSTGRES_DB.schema(:domains, :schema=>:schema_test)
847
+ @db.create_table!(:domains){integer :d}
848
+ @db.create_table(:schema_test__domains){integer :i}
849
+ sch = @db.schema(:domains, :schema=>:schema_test)
839
850
  cs = sch.map{|x| x.first}
840
851
  cs.should include(:i)
841
852
  cs.should_not include(:d)
842
- POSTGRES_DB.drop_table(:domains)
853
+ @db.drop_table(:domains)
843
854
  end
844
855
 
845
- specify "#schema should raise an exception if columns from tables in two separate schema are returned" do
846
- POSTGRES_DB.create_table!(:public__domains){integer :d}
847
- POSTGRES_DB.create_table(:schema_test__domains){integer :i}
856
+ specify "#schema should not include columns in tables from other domains by default" do
857
+ @db.create_table!(:public__domains){integer :d}
858
+ @db.create_table(:schema_test__domains){integer :i}
848
859
  begin
849
- proc{POSTGRES_DB.schema(:domains)}.should raise_error(Sequel::Error)
850
- POSTGRES_DB.schema(:public__domains).map{|x| x.first}.should == [:d]
851
- POSTGRES_DB.schema(:schema_test__domains).map{|x| x.first}.should == [:i]
860
+ @db.schema(:domains).map{|x| x.first}.should == [:d]
861
+ @db.schema(:schema_test__domains).map{|x| x.first}.should == [:i]
852
862
  ensure
853
- POSTGRES_DB.drop_table?(:public__domains)
863
+ @db.drop_table?(:public__domains)
854
864
  end
855
865
  end
856
866
 
857
867
  specify "#table_exists? should see if the table is in a given schema" do
858
- POSTGRES_DB.create_table(:schema_test__schema_test){integer :i}
859
- POSTGRES_DB.table_exists?(:schema_test__schema_test).should == true
868
+ @db.create_table(:schema_test__schema_test){integer :i}
869
+ @db.table_exists?(:schema_test__schema_test).should == true
860
870
  end
861
871
 
862
872
  specify "should be able to get primary keys for tables in a given schema" do
863
- POSTGRES_DB.create_table(:schema_test__schema_test){primary_key :i}
864
- POSTGRES_DB.primary_key(:schema_test__schema_test).should == 'i'
873
+ @db.create_table(:schema_test__schema_test){primary_key :i}
874
+ @db.primary_key(:schema_test__schema_test).should == 'i'
865
875
  end
866
876
 
867
877
  specify "should be able to get serial sequences for tables in a given schema" do
868
- POSTGRES_DB.create_table(:schema_test__schema_test){primary_key :i}
869
- POSTGRES_DB.primary_key_sequence(:schema_test__schema_test).should == '"schema_test"."schema_test_i_seq"'
878
+ @db.create_table(:schema_test__schema_test){primary_key :i}
879
+ @db.primary_key_sequence(:schema_test__schema_test).should == '"schema_test"."schema_test_i_seq"'
870
880
  end
871
881
 
872
882
  specify "should be able to get serial sequences for tables that have spaces in the name in a given schema" do
873
- POSTGRES_DB.create_table(:"schema_test__schema test"){primary_key :i}
874
- POSTGRES_DB.primary_key_sequence(:"schema_test__schema test").should == '"schema_test"."schema test_i_seq"'
883
+ @db.create_table(:"schema_test__schema test"){primary_key :i}
884
+ @db.primary_key_sequence(:"schema_test__schema test").should == '"schema_test"."schema test_i_seq"'
875
885
  end
876
886
 
877
887
  specify "should be able to get custom sequences for tables in a given schema" do
878
- POSTGRES_DB << "CREATE SEQUENCE schema_test.kseq"
879
- POSTGRES_DB.create_table(:schema_test__schema_test){integer :j; primary_key :k, :type=>:integer, :default=>Sequel.lit("nextval('schema_test.kseq'::regclass)")}
880
- POSTGRES_DB.primary_key_sequence(:schema_test__schema_test).should == '"schema_test".kseq'
888
+ @db << "CREATE SEQUENCE schema_test.kseq"
889
+ @db.create_table(:schema_test__schema_test){integer :j; primary_key :k, :type=>:integer, :default=>Sequel.lit("nextval('schema_test.kseq'::regclass)")}
890
+ @db.primary_key_sequence(:schema_test__schema_test).should == '"schema_test".kseq'
881
891
  end
882
892
 
883
893
  specify "should be able to get custom sequences for tables that have spaces in the name in a given schema" do
884
- POSTGRES_DB << "CREATE SEQUENCE schema_test.\"ks eq\""
885
- POSTGRES_DB.create_table(:"schema_test__schema test"){integer :j; primary_key :k, :type=>:integer, :default=>Sequel.lit("nextval('schema_test.\"ks eq\"'::regclass)")}
886
- POSTGRES_DB.primary_key_sequence(:"schema_test__schema test").should == '"schema_test"."ks eq"'
894
+ @db << "CREATE SEQUENCE schema_test.\"ks eq\""
895
+ @db.create_table(:"schema_test__schema test"){integer :j; primary_key :k, :type=>:integer, :default=>Sequel.lit("nextval('schema_test.\"ks eq\"'::regclass)")}
896
+ @db.primary_key_sequence(:"schema_test__schema test").should == '"schema_test"."ks eq"'
887
897
  end
888
898
 
889
899
  specify "#default_schema= should change the default schema used from public" do
890
- POSTGRES_DB.create_table(:schema_test__schema_test){primary_key :i}
891
- POSTGRES_DB.default_schema = :schema_test
892
- POSTGRES_DB.table_exists?(:schema_test).should == true
893
- POSTGRES_DB.tables.should == [:schema_test]
894
- POSTGRES_DB.primary_key(:schema_test__schema_test).should == 'i'
895
- POSTGRES_DB.primary_key_sequence(:schema_test__schema_test).should == '"schema_test"."schema_test_i_seq"'
900
+ @db.create_table(:schema_test__schema_test){primary_key :i}
901
+ @db.default_schema = :schema_test
902
+ @db.table_exists?(:schema_test).should == true
903
+ @db.tables.should == [:schema_test]
904
+ @db.primary_key(:schema_test__schema_test).should == 'i'
905
+ @db.primary_key_sequence(:schema_test__schema_test).should == '"schema_test"."schema_test_i_seq"'
906
+ end
907
+
908
+ specify "should handle schema introspection cases with tables with same name in multiple schemas" do
909
+ begin
910
+ @db.create_table(:schema_test__schema_test) do
911
+ primary_key :id
912
+ foreign_key :i, :schema_test__schema_test, :index=>{:name=>:schema_test_sti}
913
+ end
914
+ @db.create_table!(:public__schema_test) do
915
+ primary_key :id
916
+ foreign_key :j, :public__schema_test, :index=>{:name=>:public_test_sti}
917
+ end
918
+
919
+ h = @db.schema(:schema_test)
920
+ h.length.should == 2
921
+ h.last.first.should == :j
922
+
923
+ @db.indexes(:schema_test).should == {:public_test_sti=>{:unique=>false, :columns=>[:j], :deferrable=>nil}}
924
+ @db.foreign_key_list(:schema_test).should == [{:on_update=>:no_action, :columns=>[:j], :deferrable=>false, :key=>[:id], :table=>:schema_test, :on_delete=>:no_action, :name=>:schema_test_j_fkey}]
925
+ ensure
926
+ @db.drop_table?(:public__schema_test)
927
+ end
896
928
  end
897
929
  end
898
930