sequel 3.44.0 → 3.45.0

Sign up to get free protection for your applications and to get access to all the features.
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