sequel 5.9.0 → 5.10.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +34 -0
- data/doc/release_notes/5.10.0.txt +84 -0
- data/lib/sequel/adapters/jdbc/postgresql.rb +1 -1
- data/lib/sequel/adapters/postgres.rb +20 -4
- data/lib/sequel/adapters/shared/postgres.rb +12 -2
- data/lib/sequel/adapters/utils/mysql_mysql2.rb +1 -0
- data/lib/sequel/database/schema_generator.rb +3 -0
- data/lib/sequel/database/schema_methods.rb +2 -0
- data/lib/sequel/dataset/actions.rb +7 -6
- data/lib/sequel/dataset/misc.rb +14 -0
- data/lib/sequel/extensions/pg_array.rb +83 -79
- data/lib/sequel/extensions/pg_extended_date_support.rb +11 -4
- data/lib/sequel/extensions/pg_range.rb +4 -2
- data/lib/sequel/model/associations.rb +10 -2
- data/lib/sequel/plugins/list.rb +18 -8
- data/lib/sequel/plugins/pg_array_associations.rb +2 -2
- data/lib/sequel/plugins/tree.rb +28 -13
- data/lib/sequel/sql.rb +24 -4
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/postgres_spec.rb +94 -26
- data/spec/bin_spec.rb +2 -0
- data/spec/core/dataset_spec.rb +58 -32
- data/spec/core/expression_filters_spec.rb +16 -0
- data/spec/core/spec_helper.rb +1 -0
- data/spec/core_extensions_spec.rb +1 -0
- data/spec/extensions/list_spec.rb +16 -0
- data/spec/extensions/pg_array_associations_spec.rb +10 -10
- data/spec/extensions/pg_range_spec.rb +34 -2
- data/spec/extensions/spec_helper.rb +1 -0
- data/spec/extensions/tree_spec.rb +40 -0
- data/spec/guards_helper.rb +1 -0
- data/spec/model/associations_spec.rb +21 -0
- data/spec/model/spec_helper.rb +1 -0
- metadata +4 -2
@@ -83,12 +83,12 @@ module Sequel
|
|
83
83
|
# If convert_infinite_timestamps is true and the value is infinite, return an appropriate
|
84
84
|
# value based on the convert_infinite_timestamps setting.
|
85
85
|
def to_application_timestamp(value)
|
86
|
-
if value.is_a?(String) && (m = value.match(/(
|
87
|
-
if m[
|
86
|
+
if value.is_a?(String) && (m = value.match(/((?:[-+]\d\d:\d\d)(:\d\d)?)?( BC)?\z/)) && (m[2] || m[3])
|
87
|
+
if m[3]
|
88
88
|
value = value.sub(' BC', '').sub(' ', ' BC ')
|
89
89
|
conv = defined?(JRUBY_VERSION) && JRUBY_VERSION == '9.2.0.0'
|
90
90
|
end
|
91
|
-
if m[
|
91
|
+
if m[2] || conv
|
92
92
|
dt = DateTime.parse(value)
|
93
93
|
if conv
|
94
94
|
# :nocov:
|
@@ -99,7 +99,14 @@ module Sequel
|
|
99
99
|
end
|
100
100
|
# :nocov:
|
101
101
|
end
|
102
|
-
|
102
|
+
unless Sequel.datetime_class == DateTime
|
103
|
+
dt = dt.to_time
|
104
|
+
if conv && (timezone == nil || timezone == :local) && !m[1]
|
105
|
+
# :nocov:
|
106
|
+
dt = Sequel.send(:convert_input_timestamp, dt.strftime("%F %T.%6N"), :local)
|
107
|
+
# :nocov:
|
108
|
+
end
|
109
|
+
end
|
103
110
|
Sequel.convert_output_timestamp(dt, Sequel.application_timezone)
|
104
111
|
else
|
105
112
|
super(value)
|
@@ -452,13 +452,15 @@ module Sequel
|
|
452
452
|
end
|
453
453
|
end
|
454
454
|
|
455
|
+
ENDLESS_RANGE_NOT_SUPPORTED = RUBY_VERSION < '2.6'
|
456
|
+
|
455
457
|
# Return a ruby Range object for this instance, if one can be created.
|
456
458
|
def to_range
|
457
459
|
return @range if @range
|
458
460
|
raise(Error, "cannot create ruby range for an empty PostgreSQL range") if empty?
|
459
461
|
raise(Error, "cannot create ruby range when PostgreSQL range excludes beginning element") if exclude_begin?
|
460
462
|
raise(Error, "cannot create ruby range when PostgreSQL range has unbounded beginning") unless self.begin
|
461
|
-
raise(Error, "cannot create ruby range when PostgreSQL range has unbounded ending")
|
463
|
+
raise(Error, "cannot create ruby range when PostgreSQL range has unbounded ending") if ENDLESS_RANGE_NOT_SUPPORTED && !self.end
|
462
464
|
@range = Range.new(self.begin, self.end, exclude_end?)
|
463
465
|
end
|
464
466
|
|
@@ -466,7 +468,7 @@ module Sequel
|
|
466
468
|
# it must have a beginning and an ending (no unbounded ranges), and it cannot exclude
|
467
469
|
# the beginning element.
|
468
470
|
def valid_ruby_range?
|
469
|
-
!(empty? || exclude_begin? || !self.begin || !self.end)
|
471
|
+
!(empty? || exclude_begin? || !self.begin || (ENDLESS_RANGE_NOT_SUPPORTED && !self.end))
|
470
472
|
end
|
471
473
|
|
472
474
|
# Whether the beginning of the range is unbounded.
|
@@ -2401,6 +2401,14 @@ module Sequel
|
|
2401
2401
|
# cached associations.
|
2402
2402
|
def change_column_value(column, value)
|
2403
2403
|
if assocs = model.autoreloading_associations[column]
|
2404
|
+
if new?
|
2405
|
+
# Do deeper checking for new objects, so that associations are
|
2406
|
+
# not deleted when values do not change. This code is run at
|
2407
|
+
# a higher level for existing objects.
|
2408
|
+
vals = @values
|
2409
|
+
return super unless !vals.include?(column) || value != (c = vals[column]) || value.class != c.class
|
2410
|
+
end
|
2411
|
+
|
2404
2412
|
assocs.each{|a| associations.delete(a)}
|
2405
2413
|
end
|
2406
2414
|
super
|
@@ -2681,8 +2689,8 @@ module Sequel
|
|
2681
2689
|
# creates a subquery to the join table.
|
2682
2690
|
def complex_expression_sql_append(sql, op, args)
|
2683
2691
|
r = args[1]
|
2684
|
-
if (((op == :'=' || op == :'!=')
|
2685
|
-
(multiple = ((op == :IN || op == :'NOT IN')
|
2692
|
+
if (((op == :'=' || op == :'!=') && r.is_a?(Sequel::Model)) ||
|
2693
|
+
(multiple = ((op == :IN || op == :'NOT IN') && ((is_ds = r.is_a?(Sequel::Dataset)) || (r.respond_to?(:all?) && r.all?{|x| x.is_a?(Sequel::Model)})))))
|
2686
2694
|
l = args[0]
|
2687
2695
|
if ar = model.association_reflections[l]
|
2688
2696
|
if multiple
|
data/lib/sequel/plugins/list.rb
CHANGED
@@ -45,19 +45,26 @@ module Sequel
|
|
45
45
|
# race conditions, and is not safe when concurrent modifications are made
|
46
46
|
# to the same list.
|
47
47
|
#
|
48
|
-
#
|
49
|
-
#
|
48
|
+
# Note that by default, unlike ruby arrays, the list plugin assumes the first
|
49
|
+
# entry in the list has position 1, not position 0.
|
50
|
+
#
|
51
|
+
# You can change this by providing an integer <tt>:top</tt> option:
|
52
|
+
#
|
53
|
+
# Item.plugin :list, top: 0
|
50
54
|
#
|
51
55
|
# Copyright (c) 2007-2010 Sharon Rosner, Wayne E. Seguin, Aman Gupta, Adrian Madrid, Jeremy Evans
|
52
56
|
module List
|
53
|
-
# Set the +position_field+ and +
|
54
|
-
# using the <tt>:field</tt
|
57
|
+
# Set the +position_field+, +scope_proc+ and +top_of_list+ attributes for the model,
|
58
|
+
# using the <tt>:field</tt>, <tt>:scope</tt>, and <tt>:top</tt> options, respectively.
|
55
59
|
# The <tt>:scope</tt> option can be a symbol, array of symbols, or a proc that
|
56
60
|
# accepts a model instance and returns a dataset representing the list.
|
57
61
|
# Also, modify the model dataset's order to order by the position and scope fields.
|
58
62
|
def self.configure(model, opts = OPTS)
|
59
63
|
model.position_field = opts[:field] || :position
|
60
64
|
model.dataset = model.dataset.order_prepend(model.position_field)
|
65
|
+
model.instance_exec do
|
66
|
+
@top_of_list = opts[:top] || 1
|
67
|
+
end
|
61
68
|
|
62
69
|
model.scope_proc = case scope = opts[:scope]
|
63
70
|
when Symbol
|
@@ -80,7 +87,10 @@ module Sequel
|
|
80
87
|
# proc should accept an instance and return a dataset representing the list.
|
81
88
|
attr_accessor :scope_proc
|
82
89
|
|
83
|
-
|
90
|
+
# An Integer to use as the position of the top of the list. Defaults to 1.
|
91
|
+
attr_reader :top_of_list
|
92
|
+
|
93
|
+
Plugins.inherited_instance_variables(self, :@position_field=>nil, :@scope_proc=>nil, :@top_of_list=>nil)
|
84
94
|
end
|
85
95
|
|
86
96
|
module InstanceMethods
|
@@ -122,7 +132,7 @@ module Sequel
|
|
122
132
|
checked_transaction do
|
123
133
|
ds = list_dataset
|
124
134
|
op, ds = if target < current
|
125
|
-
target =
|
135
|
+
target = model.top_of_list if target < model.top_of_list
|
126
136
|
[:+, ds.where(position_field=>target...current)]
|
127
137
|
else
|
128
138
|
lp ||= last_position
|
@@ -142,9 +152,9 @@ module Sequel
|
|
142
152
|
move_to(lp, lp)
|
143
153
|
end
|
144
154
|
|
145
|
-
# Move this instance to the top (first position, position 1) of the list.
|
155
|
+
# Move this instance to the top (first position, usually position 1) of the list.
|
146
156
|
def move_to_top
|
147
|
-
move_to(
|
157
|
+
move_to(model.top_of_list)
|
148
158
|
end
|
149
159
|
|
150
160
|
# Move this instance the given number of places up in the list, or 1 place
|
@@ -160,7 +160,7 @@ module Sequel
|
|
160
160
|
|
161
161
|
def filter_by_associations_add_conditions_dataset_filter(ds)
|
162
162
|
key = qualify(associated_class.table_name, self[:key])
|
163
|
-
ds.
|
163
|
+
ds.cross_join(Sequel.function(:unnest, key).as(:_smtopgaa_, [:_smtopgaa_key_])).exclude(key=>nil).select(:_smtopgaa_key_)
|
164
164
|
end
|
165
165
|
|
166
166
|
def filter_by_associations_conditions_key
|
@@ -527,7 +527,7 @@ module Sequel
|
|
527
527
|
Sequel[pk=>assoc_pks]
|
528
528
|
end
|
529
529
|
when Sequel::Dataset
|
530
|
-
|
530
|
+
obj.select(ref.qualify(obj.model.table_name, ref[:key_column]).as(:key)).from_self.where{{pk=>any(:key)}}.select(1).exists
|
531
531
|
end
|
532
532
|
expr = Sequel::SQL::Constants::FALSE unless expr
|
533
533
|
expr = add_association_filter_conditions(ref, obj, expr)
|
data/lib/sequel/plugins/tree.rb
CHANGED
@@ -32,12 +32,8 @@ module Sequel
|
|
32
32
|
def self.apply(model, opts=OPTS)
|
33
33
|
opts = opts.dup
|
34
34
|
opts[:class] = model
|
35
|
+
opts[:key] ||= :parent_id
|
35
36
|
|
36
|
-
model.instance_exec do
|
37
|
-
@parent_column = (opts[:key] ||= :parent_id)
|
38
|
-
@tree_order = opts[:order]
|
39
|
-
end
|
40
|
-
|
41
37
|
par = opts.merge(opts.fetch(:parent, OPTS))
|
42
38
|
parent = par.fetch(:name, :parent)
|
43
39
|
|
@@ -47,10 +43,16 @@ module Sequel
|
|
47
43
|
par[:reciprocal] = children
|
48
44
|
chi[:reciprocal] = parent
|
49
45
|
|
50
|
-
model.
|
51
|
-
|
46
|
+
model.instance_exec do
|
47
|
+
@parent_column = opts[:key]
|
48
|
+
@tree_order = opts[:order]
|
49
|
+
@parent_association_name = parent
|
50
|
+
@children_association_name = children
|
52
51
|
|
53
|
-
|
52
|
+
many_to_one parent, par
|
53
|
+
one_to_many children, chi
|
54
|
+
plugin SingleRoot if opts[:single_root]
|
55
|
+
end
|
54
56
|
end
|
55
57
|
|
56
58
|
module ClassMethods
|
@@ -61,7 +63,13 @@ module Sequel
|
|
61
63
|
# parent of the leaf.
|
62
64
|
attr_accessor :parent_column
|
63
65
|
|
64
|
-
|
66
|
+
# The association name for the parent association
|
67
|
+
attr_reader :parent_association_name
|
68
|
+
|
69
|
+
# The association name for the children association
|
70
|
+
attr_reader :children_association_name
|
71
|
+
|
72
|
+
Plugins.inherited_instance_variables(self, :@parent_column=>nil, :@tree_order=>nil, :@parent_association_name=>nil, :@children_association_name=>nil)
|
65
73
|
|
66
74
|
# Should freeze tree order if it is an array when freezing the model class.
|
67
75
|
def freeze
|
@@ -93,7 +101,10 @@ module Sequel
|
|
93
101
|
# subchild1.ancestors # => [child1, root]
|
94
102
|
def ancestors
|
95
103
|
node, nodes = self, []
|
96
|
-
|
104
|
+
meth = model.parent_association_name
|
105
|
+
while par = node.send(meth)
|
106
|
+
nodes << node = par
|
107
|
+
end
|
97
108
|
nodes
|
98
109
|
end
|
99
110
|
|
@@ -101,8 +112,8 @@ module Sequel
|
|
101
112
|
#
|
102
113
|
# node.descendants # => [child1, child2, subchild1_1, subchild1_2, subchild2_1, subchild2_2]
|
103
114
|
def descendants
|
104
|
-
nodes =
|
105
|
-
|
115
|
+
nodes = send(model.children_association_name).dup
|
116
|
+
send(model.children_association_name).each{|child| nodes.concat(child.descendants)}
|
106
117
|
nodes
|
107
118
|
end
|
108
119
|
|
@@ -121,7 +132,11 @@ module Sequel
|
|
121
132
|
#
|
122
133
|
# subchild1.self_and_siblings # => [subchild1, subchild2]
|
123
134
|
def self_and_siblings
|
124
|
-
|
135
|
+
if parent = send(model.parent_association_name)
|
136
|
+
parent.send(model.children_association_name)
|
137
|
+
else
|
138
|
+
model.roots
|
139
|
+
end
|
125
140
|
end
|
126
141
|
|
127
142
|
# Returns all siblings of the current node.
|
data/lib/sequel/sql.rb
CHANGED
@@ -26,12 +26,27 @@ module Sequel
|
|
26
26
|
# Set the date used for SQLTime instances.
|
27
27
|
attr_writer :date
|
28
28
|
|
29
|
-
#
|
29
|
+
# Use the date explicitly set, or the current date if there is not a
|
30
30
|
# date set.
|
31
31
|
def date
|
32
32
|
@date || now
|
33
33
|
end
|
34
34
|
|
35
|
+
# Set the correct date and timezone when parsing times.
|
36
|
+
def parse(*)
|
37
|
+
t = super
|
38
|
+
|
39
|
+
utc = Sequel.application_timezone == :utc
|
40
|
+
d = @date
|
41
|
+
if d || utc
|
42
|
+
meth = utc ? :utc : :local
|
43
|
+
d ||= t
|
44
|
+
t = public_send(meth, d.year, d.month, d.day, t.hour, t.min, t.sec, t.usec)
|
45
|
+
end
|
46
|
+
|
47
|
+
t
|
48
|
+
end
|
49
|
+
|
35
50
|
# Create a new SQLTime instance given an hour, minute, second, and usec.
|
36
51
|
def create(hour, minute, second, usec = 0)
|
37
52
|
t = date
|
@@ -1059,7 +1074,11 @@ module Sequel
|
|
1059
1074
|
def self.from_value_pair(l, r)
|
1060
1075
|
case r
|
1061
1076
|
when Range
|
1062
|
-
|
1077
|
+
expr = new(:>=, l, r.begin)
|
1078
|
+
unless r.end.nil?
|
1079
|
+
expr = new(:AND, expr, new(r.exclude_end? ? :< : :<=, l, r.end))
|
1080
|
+
end
|
1081
|
+
expr
|
1063
1082
|
when ::Array, ::Sequel::Dataset
|
1064
1083
|
new(:IN, l, r)
|
1065
1084
|
when NegativeBooleanConstant
|
@@ -1846,7 +1865,7 @@ module Sequel
|
|
1846
1865
|
freeze
|
1847
1866
|
end
|
1848
1867
|
|
1849
|
-
|
1868
|
+
m = Module.new do
|
1850
1869
|
# Return an +Identifier+, +QualifiedIdentifier+, or +Function+, depending
|
1851
1870
|
# on arguments and whether a block is provided. Does not currently call the block.
|
1852
1871
|
# See the class level documentation.
|
@@ -1862,7 +1881,8 @@ module Sequel
|
|
1862
1881
|
Function.new(m, *args)
|
1863
1882
|
end
|
1864
1883
|
end
|
1865
|
-
end
|
1884
|
+
end
|
1885
|
+
include m
|
1866
1886
|
|
1867
1887
|
Sequel::VIRTUAL_ROW = new
|
1868
1888
|
end
|
data/lib/sequel/version.rb
CHANGED
@@ -5,7 +5,7 @@ module Sequel
|
|
5
5
|
MAJOR = 5
|
6
6
|
# The minor version of Sequel. Bumped for every non-patch level
|
7
7
|
# release, generally around once a month.
|
8
|
-
MINOR =
|
8
|
+
MINOR = 10
|
9
9
|
# The tiny version of Sequel. Usually 0, only bumped for bugfix
|
10
10
|
# releases that fix regressions from previous versions.
|
11
11
|
TINY = 0
|
@@ -271,6 +271,11 @@ describe "PostgreSQL views" do
|
|
271
271
|
@db.refresh_view(:items_view, :concurrently=>true)
|
272
272
|
end if DB.server_version >= 90400
|
273
273
|
|
274
|
+
it "should support specifying tablespaces for materialized views" do
|
275
|
+
@opts = {:materialized=>true}
|
276
|
+
@db.create_view(:items_view, @db[:items].where{number >= 10}, :materialized=>true, :tablespace=>:pg_default)
|
277
|
+
end if DB.server_version >= 90300
|
278
|
+
|
274
279
|
it "should support :if_exists=>true for not raising an error if the view does not exist" do
|
275
280
|
@db.drop_view(:items_view, :if_exists=>true)
|
276
281
|
end
|
@@ -720,6 +725,21 @@ describe "A PostgreSQL dataset" do
|
|
720
725
|
@db.add_index :test, [:name, :value], :if_not_exists=>true, :name=>'tnv3'
|
721
726
|
end if DB.server_version >= 90500
|
722
727
|
|
728
|
+
it "should support including columns in indexes" do
|
729
|
+
@db.create_table(:atest){Integer :a; Integer :b; Integer :c}
|
730
|
+
@db.add_index :atest, :a, :include=>[:b, :c]
|
731
|
+
@db.add_index :atest, :b, :include=>:a
|
732
|
+
end if DB.server_version >= 110000
|
733
|
+
|
734
|
+
it "should support specifying tablespaces for tables" do
|
735
|
+
@db.create_table(:atest, :tablespace=>:pg_default){Integer :a}
|
736
|
+
end
|
737
|
+
|
738
|
+
it "should support specifying tablespaces for indexes" do
|
739
|
+
@db.create_table(:atest){Integer :a}
|
740
|
+
@db.add_index :atest, :a, :tablespace=>:pg_default
|
741
|
+
end
|
742
|
+
|
723
743
|
it "#lock should lock table if inside a transaction" do
|
724
744
|
@db.transaction{@d.lock('EXCLUSIVE'); @d.insert(:name=>'a')}
|
725
745
|
end
|
@@ -849,6 +869,9 @@ describe "A PostgreSQL dataset with a timestamp field" do
|
|
849
869
|
end
|
850
870
|
after do
|
851
871
|
@db.convert_infinite_timestamps = false
|
872
|
+
Sequel.datetime_class = Time
|
873
|
+
Sequel::SQLTime.date = nil
|
874
|
+
Sequel.application_timezone = nil
|
852
875
|
end
|
853
876
|
after(:all) do
|
854
877
|
@db.drop_table?(:test3)
|
@@ -872,22 +895,62 @@ describe "A PostgreSQL dataset with a timestamp field" do
|
|
872
895
|
(t2.is_a?(Time) ? t2.usec : t2.strftime('%N').to_i/1000).must_equal t.strftime('%N').to_i/1000
|
873
896
|
end
|
874
897
|
|
898
|
+
it "should respect SQLTime.date setting for time columns" do
|
899
|
+
Sequel::SQLTime.date = Time.local(2000, 1, 2)
|
900
|
+
d = Sequel::SQLTime.create(10, 11, 12)
|
901
|
+
@db.get(Sequel.cast(d, :time)).must_equal d
|
902
|
+
@db.get(Sequel.cast(d, :timetz)).must_equal d
|
903
|
+
end
|
904
|
+
|
905
|
+
it "should respect Sequel.application_timezone for time columns" do
|
906
|
+
d = Sequel::SQLTime.create(10, 11, 12)
|
907
|
+
Sequel.application_timezone = :local
|
908
|
+
@db.get(Sequel.cast(d, :time)).utc_offset.must_equal Time.now.utc_offset
|
909
|
+
@db.get(Sequel.cast(d, :timetz)).utc_offset.must_equal Time.now.utc_offset
|
910
|
+
Sequel.application_timezone = :utc
|
911
|
+
@db.get(Sequel.cast(d, :time)).utc_offset.must_equal 0
|
912
|
+
@db.get(Sequel.cast(d, :timetz)).utc_offset.must_equal 0
|
913
|
+
end
|
914
|
+
|
915
|
+
it "should handle parsing dates and timestamps in with 1, 2, and 3 digit years" do
|
916
|
+
[1, 10, 100, -2, -20, -200].each do |year|
|
917
|
+
d = Date.new(year, 2, 3)
|
918
|
+
@db.get(Sequel.cast(d, Date)).must_equal d
|
919
|
+
d = Time.local(year, 2, 3, 10, 11, 12)
|
920
|
+
@db.get(Sequel.cast(d, Time)).must_equal d
|
921
|
+
begin
|
922
|
+
Sequel.datetime_class = DateTime
|
923
|
+
d = DateTime.new(year, 2, 3, 10, 11, 12)
|
924
|
+
@db.get(Sequel.cast(d, Time)).must_equal d
|
925
|
+
ensure
|
926
|
+
Sequel.datetime_class = Time
|
927
|
+
end
|
928
|
+
end
|
929
|
+
end
|
930
|
+
|
931
|
+
it "should handle parsing dates and timestamps in the distant future" do
|
932
|
+
d = Date.new(5874896, 2, 3)
|
933
|
+
@db.get(Sequel.cast(d, Date)).must_equal d
|
934
|
+
d = Time.local(294275, 2, 3, 10, 11, 12)
|
935
|
+
@db.get(Sequel.cast(d, Time)).must_equal d
|
936
|
+
Sequel.datetime_class = DateTime
|
937
|
+
d = DateTime.new(294275, 2, 3, 10, 11, 12)
|
938
|
+
@db.get(Sequel.cast(d, Time)).must_equal d
|
939
|
+
end
|
940
|
+
|
875
941
|
it "should handle BC times and dates" do
|
876
942
|
d = Date.new(-1234, 2, 3)
|
877
943
|
@db.get(Sequel.cast(d, Date)).must_equal d
|
878
|
-
|
879
|
-
|
880
|
-
|
881
|
-
|
882
|
-
|
883
|
-
|
884
|
-
|
885
|
-
|
886
|
-
|
887
|
-
|
888
|
-
Sequel.datetime_class = Time
|
889
|
-
Sequel.default_timezone = nil
|
890
|
-
end
|
944
|
+
Sequel.default_timezone = :utc
|
945
|
+
t = Time.at(-100000000000).utc + 0.5
|
946
|
+
@db.get(Sequel.cast(t, Time)).must_equal t
|
947
|
+
@db.get(Sequel.cast(t, :timestamptz)).must_equal t
|
948
|
+
Sequel.datetime_class = DateTime
|
949
|
+
dt = DateTime.new(-1234, 2, 3, 10, 20, Rational(30, 20))
|
950
|
+
@db.get(Sequel.cast(dt, DateTime)).must_equal dt
|
951
|
+
@db.get(Sequel.cast(dt, :timestamptz)).must_equal dt
|
952
|
+
Sequel.datetime_class = Time
|
953
|
+
Sequel.default_timezone = nil
|
891
954
|
end
|
892
955
|
|
893
956
|
it "should handle infinite timestamps if convert_infinite_timestamps is set" do
|
@@ -2343,13 +2406,13 @@ describe 'PostgreSQL array handling' do
|
|
2343
2406
|
end
|
2344
2407
|
|
2345
2408
|
it 'insert and retrieve custom array types' do
|
2346
|
-
|
2409
|
+
point= Class.new do
|
2347
2410
|
attr_reader :array
|
2348
2411
|
def initialize(array)
|
2349
2412
|
@array = array
|
2350
2413
|
end
|
2351
2414
|
def sql_literal_append(ds, sql)
|
2352
|
-
sql << "'#{array.join('
|
2415
|
+
sql << "'(#{array.join(',')})'"
|
2353
2416
|
end
|
2354
2417
|
def ==(other)
|
2355
2418
|
if other.is_a?(self.class)
|
@@ -2359,16 +2422,16 @@ describe 'PostgreSQL array handling' do
|
|
2359
2422
|
end
|
2360
2423
|
end
|
2361
2424
|
end
|
2362
|
-
@db.register_array_type(:
|
2425
|
+
@db.register_array_type(:point){|s| point.new(s[1...-1].split(',').map{|i| i.to_i})}
|
2363
2426
|
@db.create_table!(:items) do
|
2364
|
-
column :b, '
|
2427
|
+
column :b, 'point[]'
|
2365
2428
|
end
|
2366
|
-
@tp.call.must_equal [:
|
2367
|
-
|
2368
|
-
@ds.insert(Sequel.pg_array([
|
2429
|
+
@tp.call.must_equal [:point_array]
|
2430
|
+
pv = point.new([1, 2])
|
2431
|
+
@ds.insert(Sequel.pg_array([pv], :point))
|
2369
2432
|
@ds.count.must_equal 1
|
2370
2433
|
rs = @ds.all
|
2371
|
-
rs.must_equal [{:b=>[
|
2434
|
+
rs.must_equal [{:b=>[pv]}]
|
2372
2435
|
rs.first.values.each{|v| v.class.must_equal(Sequel::Postgres::PGArray)}
|
2373
2436
|
rs.first.values.each{|v| v.to_a.must_be_kind_of(Array)}
|
2374
2437
|
@ds.delete
|
@@ -2398,7 +2461,7 @@ describe 'PostgreSQL array handling' do
|
|
2398
2461
|
@ds.delete
|
2399
2462
|
@ds.insert(rs.first)
|
2400
2463
|
@ds.all.must_equal rs
|
2401
|
-
end
|
2464
|
+
end
|
2402
2465
|
|
2403
2466
|
it 'use arrays in bound variables' do
|
2404
2467
|
@db.create_table!(:items) do
|
@@ -3039,7 +3102,7 @@ describe 'PostgreSQL json type' do
|
|
3039
3102
|
j = Sequel.pg_json([{'a'=>1, 'b'=>'c'}, {'a'=>2, 'b'=>'d'}]).op
|
3040
3103
|
@db.from(j.populate_set(Sequel.cast(nil, :items))).select_order_map(:a).must_equal [1, 2]
|
3041
3104
|
@db.from(j.populate_set(Sequel.cast(nil, :items))).select_order_map(:b).must_equal %w'c d'
|
3042
|
-
end if DB.server_version >= 90300
|
3105
|
+
end if DB.server_version >= 90300
|
3043
3106
|
end
|
3044
3107
|
end if DB.server_version >= 90200
|
3045
3108
|
|
@@ -3189,6 +3252,11 @@ describe 'PostgreSQL inet/cidr types' do
|
|
3189
3252
|
|
3190
3253
|
@db.get(Sequel.pg_inet_op('1.2.3.4/24').abbrev).must_equal '1.2.3.4/24'
|
3191
3254
|
@db.get(Sequel.pg_inet_op('1.2.3.4/24').broadcast).must_equal IPAddr.new('1.2.3.255/24')
|
3255
|
+
@db.get(Sequel.pg_inet_op('1234:3456:5678:789a:9abc:bced:edf0:f012/96').broadcast).must_equal IPAddr.new('1234:3456:5678:789a:9abc:bced::/96')
|
3256
|
+
@db.get(Sequel.pg_inet_op('1234:3456:5678:789a:9abc:bced:edf0:f012/128').broadcast).must_equal IPAddr.new('1234:3456:5678:789a:9abc:bced:edf0:f012/128')
|
3257
|
+
@db.get(Sequel.pg_inet_op('1234:3456:5678:789a:9abc:bced:edf0:f012/64').broadcast).must_equal IPAddr.new('1234:3456:5678:789a::/64')
|
3258
|
+
@db.get(Sequel.pg_inet_op('1234:3456:5678:789a:9abc:bced:edf0:f012/32').broadcast).must_equal IPAddr.new('1234:3456::/32')
|
3259
|
+
@db.get(Sequel.pg_inet_op('1234:3456:5678:789a:9abc:bced:edf0:f012/0').broadcast).must_equal IPAddr.new('::/0')
|
3192
3260
|
@db.get(Sequel.pg_inet_op('1.2.3.4/24').family).must_equal 4
|
3193
3261
|
@db.get(Sequel.pg_inet_op('1.2.3.4/24').host).must_equal '1.2.3.4'
|
3194
3262
|
@db.get(Sequel.pg_inet_op('1.2.3.4/24').hostmask).must_equal IPAddr.new('0.0.0.255/32')
|
@@ -3218,7 +3286,7 @@ describe 'PostgreSQL custom range types' do
|
|
3218
3286
|
r = Sequel::SQLTime.create(10, 11, 12)..Sequel::SQLTime.create(11, 12, 13)
|
3219
3287
|
@db.get(Sequel.pg_range(r, :timerange)).to_range.must_equal r
|
3220
3288
|
end
|
3221
|
-
end if DB.server_version >= 90200
|
3289
|
+
end if DB.server_version >= 90200
|
3222
3290
|
|
3223
3291
|
describe 'PostgreSQL range types' do
|
3224
3292
|
before(:all) do
|
@@ -3570,7 +3638,7 @@ describe 'PostgreSQL row-valued/composite types' do
|
|
3570
3638
|
@db.drop_table(:domain_check)
|
3571
3639
|
@db << "DROP DOMAIN positive_integer"
|
3572
3640
|
end
|
3573
|
-
end
|
3641
|
+
end
|
3574
3642
|
|
3575
3643
|
it 'insert and retrieve arrays of row types' do
|
3576
3644
|
@ds = @db[:company]
|
@@ -3822,7 +3890,7 @@ describe 'PostgreSQL enum types' do
|
|
3822
3890
|
|
3823
3891
|
it "should add array parsers for enum values" do
|
3824
3892
|
@db.get(Sequel.pg_array(%w'a b', :test_enum)).must_equal %w'a b'
|
3825
|
-
end
|
3893
|
+
end
|
3826
3894
|
|
3827
3895
|
it "should set up model typecasting correctly" do
|
3828
3896
|
c = Class.new(Sequel::Model(:test_enumt))
|