sequel 5.9.0 → 5.10.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.
- 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))
|