1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
|
require_relative "spec_helper"
begin
require 'active_support/duration'
begin
require 'active_support/gem_version'
rescue LoadError
end
begin
require 'active_support/version'
rescue LoadError
end
rescue LoadError
warn "Skipping test of pg_interval plugin: can't load active_support/duration"
else
describe "pg_interval extension" do
before do
@db = Sequel.connect('mock://postgres')
@db.extend_datasets{def quote_identifiers?; false end}
@db.extension(:pg_array, :pg_interval)
end
it "should literalize ActiveSupport::Duration instances to strings correctly" do
@db.literal(ActiveSupport::Duration.new(0, [])).must_equal "'0'::interval"
@db.literal(ActiveSupport::Duration.new(0, [[:seconds, 0]])).must_equal "'0'::interval"
@db.literal(ActiveSupport::Duration.new(0, [[:seconds, 10], [:minutes, 20], [:days, 3], [:months, 4], [:years, 6]])).must_equal "'6 years 4 months 3 days 20 minutes 10 seconds '::interval"
@db.literal(ActiveSupport::Duration.new(0, [[:seconds, 10], [:minutes, 20], [:hours, 8], [:days, 3], [:weeks, 2], [:months, 4], [:years, 6]])).must_equal "'6 years 4 months 2 weeks 3 days 8 hours 20 minutes 10 seconds '::interval"
@db.literal(ActiveSupport::Duration.new(0, [[:seconds, -10.000001], [:minutes, -20], [:days, -3], [:months, -4], [:years, -6]])).must_equal "'-6 years -4 months -3 days -20 minutes -10.000001 seconds '::interval"
end
it "should literalize ActiveSupport::Duration instances with repeated parts correctly" do
if defined?(ActiveSupport::VERSION::STRING) && ActiveSupport::VERSION::STRING >= '5.1' && ActiveSupport::VERSION::STRING < '6.1'
@db.literal(ActiveSupport::Duration.new(0, [[:seconds, 2], [:seconds, 1]])).must_equal "'1 seconds '::interval"
@db.literal(ActiveSupport::Duration.new(0, [[:seconds, 2], [:seconds, 1], [:days, 1], [:days, 4]])).must_equal "'4 days 1 seconds '::interval"
else
@db.literal(ActiveSupport::Duration.new(0, [[:seconds, 2], [:seconds, 1]])).must_equal "'3 seconds '::interval"
@db.literal(ActiveSupport::Duration.new(0, [[:seconds, 2], [:seconds, 1], [:days, 1], [:days, 4]])).must_equal "'5 days 3 seconds '::interval"
end
end
it "should set up conversion procs correctly" do
cp = @db.conversion_procs
cp[1186].call("1 sec").must_equal ActiveSupport::Duration.new(1, [[:seconds, 1]])
end
it "should set up conversion procs for arrays correctly" do
cp = @db.conversion_procs
cp[1187].call("{1 sec}").must_equal [ActiveSupport::Duration.new(1, [[:seconds, 1]])]
end
it "should setup conversion proc without array conversion proc if pg_array extension is not loaded" do
@db = Sequel.connect('mock://postgres')
@db.extension(:pg_interval, :pg_array)
cp = @db.conversion_procs
cp[1186].call("1 sec").must_equal ActiveSupport::Duration.new(1, [[:seconds, 1]])
cp[1187].must_be_nil
end
it "should not affect literalization of custom objects" do
o = Object.new
def o.sql_literal(ds) 'v' end
@db.literal(o).must_equal 'v'
end
it "should support using ActiveSupport::Duration instances as bound variables" do
@db.bound_variable_arg(1, nil).must_equal 1
@db.bound_variable_arg(ActiveSupport::Duration.new(0, [[:seconds, 0]]), nil).must_equal '0'
@db.bound_variable_arg(ActiveSupport::Duration.new(0, [[:seconds, -10.000001], [:minutes, -20], [:days, -3], [:months, -4], [:years, -6]]), nil).must_equal '-6 years -4 months -3 days -20 minutes -10.000001 seconds '
end
it "should support using ActiveSupport::Duration instances in array types in bound variables" do
@db.bound_variable_arg(Sequel.pg_array([ActiveSupport::Duration.new(0, [[:seconds, 0]])]), nil).must_equal '{"0"}'
@db.bound_variable_arg(Sequel.pg_array([ActiveSupport::Duration.new(0, [[:seconds, -10.000001], [:minutes, -20], [:days, -3], [:months, -4], [:years, -6]])]), nil).must_equal '{"-6 years -4 months -3 days -20 minutes -10.000001 seconds "}'
end
it "should parse interval type from the schema correctly" do
@db.fetch = [{:name=>'id', :db_type=>'integer'}, {:name=>'i', :db_type=>'interval'}]
@db.schema(:items).map{|e| e[1][:type]}.must_equal [:integer, :interval]
end
it "should set :ruby_default schema entries if default value is recognized" do
@db.fetch = [{:name=>'id', :db_type=>'integer', :default=>'1'}, {:name=>'t', :db_type=>'interval', :default=>"'3 days'::interval"}]
s = @db.schema(:items)
s[1][1][:ruby_default].must_equal ActiveSupport::Duration.new(3*86400, :days=>3)
end
it "should support typecasting for the interval type" do
m = Sequel::Postgres::IntervalDatabaseMethods::Parser
seconds = m::SECONDS_PER_YEAR + 2*m::SECONDS_PER_MONTH + 3*86400*7 + 4*86400 + 5*3600 + 6*60 + 7
parts = {:years => 1, :months => 2, :days => 25, :seconds => 18367}
if !defined?(ActiveSupport::VERSION::STRING) || ActiveSupport::VERSION::STRING < '5.1'
parts = parts.to_a
end
d = ActiveSupport::Duration.new(seconds, parts)
@db.typecast_value(:interval, d).object_id.must_equal d.object_id
@db.typecast_value(:interval, "1 year 2 mons 25 days 05:06:07").is_a?(ActiveSupport::Duration).must_equal true
@db.typecast_value(:interval, "1 year 2 mons 25 days 05:06:07").must_equal d
@db.typecast_value(:interval, "1 year 2 mons 25 days -05:06:07").is_a?(ActiveSupport::Duration).must_equal true
@db.typecast_value(:interval, "1 year 2 mons 25 days -05:06:07").must_equal(d-10*3600-12*60-14)
@db.typecast_value(:interval, "1 year 2 mons 25 days 05:06:07").parts.sort_by{|k,v| k.to_s}.must_equal d.parts.sort_by{|k,v| k.to_s}
@db.typecast_value(:interval, "1 year 2 mons 25 days 05:06:07.0").parts.sort_by{|k,v| k.to_s}.must_equal d.parts.sort_by{|k,v| k.to_s}
@db.typecast_value(:interval, "1 year 2 mons 25 days 5 hours 6 mins").is_a?(ActiveSupport::Duration).must_equal true
@db.typecast_value(:interval, "1 year 2 mons 25 days 5 hours 6 mins").must_equal(d-7)
@db.typecast_value(:interval, "1 year 2 mons 25 days 5 hours 6 mins 7 secs").is_a?(ActiveSupport::Duration).must_equal true
@db.typecast_value(:interval, "1 year 2 mons 25 days 5 hours 6 mins 7 secs").must_equal d
@db.typecast_value(:interval, "1 year 2 mons 25 days 5 hours 6 mins 7 secs").parts.sort_by{|k,v| k.to_s}.must_equal d.parts.sort_by{|k,v| k.to_s}
@db.typecast_value(:interval, "1 year 2 mons 25 days 5 hours 6 mins 7.0 secs").parts.sort_by{|k,v| k.to_s}.must_equal d.parts.sort_by{|k,v| k.to_s}
d2 = ActiveSupport::Duration.new(1, [[:seconds, 1]])
@db.typecast_value(:interval, 1).is_a?(ActiveSupport::Duration).must_equal true
@db.typecast_value(:interval, 1).must_equal d2
@db.typecast_value(:interval, 1).parts.sort_by{|k,v| k.to_s}.must_equal d2.parts.sort_by{|k,v| k.to_s}
proc{@db.typecast_value(:interval, 'foo')}.must_raise(Sequel::InvalidValue)
proc{@db.typecast_value(:interval, Object.new)}.must_raise(Sequel::InvalidValue)
end
it "should return correct results for Database#schema_type_class" do
@db.schema_type_class(:interval).must_equal ActiveSupport::Duration
@db.schema_type_class(:integer).must_equal Integer
end
end
end
|