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.
- data/CHANGELOG +44 -0
- data/Rakefile +12 -4
- data/doc/reflection.rdoc +3 -3
- data/doc/release_notes/3.45.0.txt +179 -0
- data/doc/schema_modification.rdoc +1 -1
- data/doc/transactions.rdoc +23 -0
- data/lib/sequel/adapters/db2.rb +1 -0
- data/lib/sequel/adapters/ibmdb.rb +19 -3
- data/lib/sequel/adapters/jdbc.rb +15 -0
- data/lib/sequel/adapters/jdbc/derby.rb +1 -5
- data/lib/sequel/adapters/jdbc/h2.rb +1 -0
- data/lib/sequel/adapters/jdbc/hsqldb.rb +2 -1
- data/lib/sequel/adapters/jdbc/jtds.rb +5 -0
- data/lib/sequel/adapters/jdbc/mysql.rb +5 -0
- data/lib/sequel/adapters/jdbc/oracle.rb +7 -1
- data/lib/sequel/adapters/jdbc/sqlite.rb +1 -1
- data/lib/sequel/adapters/jdbc/transactions.rb +28 -1
- data/lib/sequel/adapters/mysql.rb +4 -0
- data/lib/sequel/adapters/mysql2.rb +5 -1
- data/lib/sequel/adapters/oracle.rb +18 -0
- data/lib/sequel/adapters/postgres.rb +11 -1
- data/lib/sequel/adapters/shared/access.rb +14 -2
- data/lib/sequel/adapters/shared/cubrid.rb +1 -11
- data/lib/sequel/adapters/shared/db2.rb +11 -6
- data/lib/sequel/adapters/shared/mssql.rb +10 -10
- data/lib/sequel/adapters/shared/mysql.rb +11 -1
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +17 -1
- data/lib/sequel/adapters/shared/oracle.rb +16 -15
- data/lib/sequel/adapters/shared/postgres.rb +91 -59
- data/lib/sequel/adapters/shared/sqlite.rb +1 -4
- data/lib/sequel/adapters/tinytds.rb +15 -0
- data/lib/sequel/connection_pool/threaded.rb +1 -1
- data/lib/sequel/core.rb +10 -0
- data/lib/sequel/database/connecting.rb +2 -0
- data/lib/sequel/database/misc.rb +46 -4
- data/lib/sequel/database/query.rb +33 -14
- data/lib/sequel/database/schema_methods.rb +0 -5
- data/lib/sequel/dataset/misc.rb +9 -0
- data/lib/sequel/dataset/mutation.rb +9 -7
- data/lib/sequel/dataset/sql.rb +13 -0
- data/lib/sequel/exceptions.rb +3 -0
- data/lib/sequel/extensions/connection_validator.rb +1 -1
- data/lib/sequel/extensions/date_arithmetic.rb +0 -8
- data/lib/sequel/extensions/eval_inspect.rb +2 -0
- data/lib/sequel/extensions/named_timezones.rb +18 -2
- data/lib/sequel/extensions/pg_array.rb +5 -1
- data/lib/sequel/extensions/pg_array_ops.rb +2 -0
- data/lib/sequel/extensions/pg_hstore.rb +2 -0
- data/lib/sequel/extensions/pg_hstore_ops.rb +2 -0
- data/lib/sequel/extensions/pg_json.rb +3 -1
- data/lib/sequel/extensions/pg_range.rb +2 -0
- data/lib/sequel/extensions/pg_range_ops.rb +2 -0
- data/lib/sequel/extensions/pg_row.rb +2 -0
- data/lib/sequel/extensions/pg_row_ops.rb +2 -0
- data/lib/sequel/extensions/query.rb +18 -22
- data/lib/sequel/model/associations.rb +3 -4
- data/lib/sequel/model/base.rb +2 -0
- data/lib/sequel/plugins/force_encoding.rb +2 -0
- data/lib/sequel/plugins/json_serializer.rb +155 -39
- data/lib/sequel/plugins/serialization.rb +14 -2
- data/lib/sequel/plugins/unlimited_update.rb +31 -0
- data/lib/sequel/plugins/validation_class_methods.rb +6 -4
- data/lib/sequel/plugins/xml_serializer.rb +133 -30
- data/lib/sequel/sql.rb +2 -0
- data/lib/sequel/timezones.rb +4 -0
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/mysql_spec.rb +0 -11
- data/spec/adapters/postgres_spec.rb +86 -54
- data/spec/adapters/spec_helper.rb +6 -0
- data/spec/core/connection_pool_spec.rb +16 -0
- data/spec/core/database_spec.rb +77 -1
- data/spec/core/dataset_spec.rb +30 -15
- data/spec/core/expression_filters_spec.rb +55 -13
- data/spec/core/mock_adapter_spec.rb +4 -0
- data/spec/core/schema_spec.rb +0 -2
- data/spec/core/spec_helper.rb +5 -0
- data/spec/core_extensions_spec.rb +33 -28
- data/spec/extensions/constraint_validations_spec.rb +2 -2
- data/spec/extensions/core_refinements_spec.rb +12 -12
- data/spec/extensions/json_serializer_spec.rb +137 -31
- data/spec/extensions/named_timezones_spec.rb +10 -0
- data/spec/extensions/pg_auto_parameterize_spec.rb +5 -0
- data/spec/extensions/pg_json_spec.rb +14 -0
- data/spec/extensions/pg_row_spec.rb +11 -0
- data/spec/extensions/pretty_table_spec.rb +2 -2
- data/spec/extensions/query_spec.rb +11 -8
- data/spec/extensions/serialization_spec.rb +20 -0
- data/spec/extensions/spec_helper.rb +8 -2
- data/spec/extensions/sql_expr_spec.rb +1 -1
- data/spec/extensions/unlimited_update_spec.rb +20 -0
- data/spec/extensions/xml_serializer_spec.rb +68 -16
- data/spec/integration/dataset_test.rb +28 -0
- data/spec/integration/spec_helper.rb +6 -0
- data/spec/integration/transaction_test.rb +39 -0
- data/spec/model/model_spec.rb +1 -1
- data/spec/sequel_coverage.rb +15 -0
- 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 | 
| 436 | 
            -
             | 
| 437 | 
            -
                      when  | 
| 438 | 
            -
             | 
| 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 | 
            -
                #  | 
| 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 | 
            -
                #  | 
| 67 | 
            -
                #  | 
| 78 | 
            +
                # The array_from_xml class method exists to parse arrays of model instances
         | 
| 79 | 
            +
                # from xml:
         | 
| 68 80 | 
             
                #
         | 
| 69 | 
            -
                #    | 
| 81 | 
            +
                #   xml = Album.filter(:artist_id=>1).to_xml
         | 
| 82 | 
            +
                #   albums = Album.array_from_xml(xml)
         | 
| 70 83 | 
             
                #
         | 
| 71 | 
            -
                #  | 
| 72 | 
            -
                #  | 
| 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 | 
            -
                #  | 
| 78 | 
            -
                #  | 
| 92 | 
            +
                # If you want to update an existing instance, you can use the from_xml
         | 
| 93 | 
            +
                # instance method:
         | 
| 79 94 | 
             
                #
         | 
| 80 | 
            -
                #    | 
| 95 | 
            +
                #   album.from_xml(xml)
         | 
| 81 96 | 
             
                #
         | 
| 82 | 
            -
                #  | 
| 83 | 
            -
                #  | 
| 97 | 
            +
                # Both of these allow creation of cached associated objects, if you provide
         | 
| 98 | 
            +
                # the :associations option:
         | 
| 84 99 | 
             
                #
         | 
| 85 | 
            -
                #    | 
| 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 | 
| 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 | 
            -
                       | 
| 198 | 
            -
             | 
| 199 | 
            -
                       | 
| 200 | 
            -
                       | 
| 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  | 
| 206 | 
            -
                           | 
| 207 | 
            -
             | 
| 208 | 
            -
             | 
| 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 | 
            -
                             | 
| 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 |  | 
    
        data/lib/sequel/sql.rb
    CHANGED
    
    | @@ -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
         | 
    
        data/lib/sequel/timezones.rb
    CHANGED
    
    | @@ -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}"
         | 
    
        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 = 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
         | 
    
        data/spec/adapters/mysql_spec.rb
    CHANGED
    
    | @@ -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 | 
            -
                 | 
| 794 | 
            -
                 | 
| 795 | 
            -
                 | 
| 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 | 
            -
                 | 
| 799 | 
            -
                 | 
| 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 | 
            -
                 | 
| 804 | 
            -
                 | 
| 805 | 
            -
                 | 
| 806 | 
            -
                 | 
| 807 | 
            -
                 | 
| 808 | 
            -
                 | 
| 809 | 
            -
                 | 
| 810 | 
            -
                 | 
| 811 | 
            -
                 | 
| 812 | 
            -
                 | 
| 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 | 
            -
                 | 
| 817 | 
            -
                 | 
| 818 | 
            -
                 | 
| 819 | 
            -
                 | 
| 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 | 
            -
                 | 
| 824 | 
            -
                 | 
| 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 | 
            -
                 | 
| 829 | 
            -
                sch =  | 
| 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 | 
            -
                 | 
| 837 | 
            -
                 | 
| 838 | 
            -
                sch =  | 
| 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 | 
            -
                 | 
| 853 | 
            +
                @db.drop_table(:domains)
         | 
| 843 854 | 
             
              end
         | 
| 844 855 |  | 
| 845 | 
            -
              specify "#schema should  | 
| 846 | 
            -
                 | 
| 847 | 
            -
                 | 
| 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 | 
            -
                   | 
| 850 | 
            -
                   | 
| 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 | 
            -
                   | 
| 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 | 
            -
                 | 
| 859 | 
            -
                 | 
| 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 | 
            -
                 | 
| 864 | 
            -
                 | 
| 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 | 
            -
                 | 
| 869 | 
            -
                 | 
| 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 | 
            -
                 | 
| 874 | 
            -
                 | 
| 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 | 
            -
                 | 
| 879 | 
            -
                 | 
| 880 | 
            -
                 | 
| 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 | 
            -
                 | 
| 885 | 
            -
                 | 
| 886 | 
            -
                 | 
| 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 | 
            -
                 | 
| 891 | 
            -
                 | 
| 892 | 
            -
                 | 
| 893 | 
            -
                 | 
| 894 | 
            -
                 | 
| 895 | 
            -
                 | 
| 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 |  |