sequel 5.19.0 → 5.24.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +102 -0
- data/doc/dataset_filtering.rdoc +15 -0
- data/doc/opening_databases.rdoc +5 -1
- data/doc/release_notes/5.20.0.txt +89 -0
- data/doc/release_notes/5.21.0.txt +87 -0
- data/doc/release_notes/5.22.0.txt +48 -0
- data/doc/release_notes/5.23.0.txt +56 -0
- data/doc/release_notes/5.24.0.txt +56 -0
- data/doc/sharding.rdoc +2 -0
- data/doc/testing.rdoc +1 -0
- data/doc/transactions.rdoc +38 -0
- data/lib/sequel/adapters/ado.rb +27 -19
- data/lib/sequel/adapters/jdbc.rb +7 -1
- data/lib/sequel/adapters/jdbc/mysql.rb +2 -2
- data/lib/sequel/adapters/jdbc/postgresql.rb +1 -13
- data/lib/sequel/adapters/jdbc/sqlite.rb +29 -0
- data/lib/sequel/adapters/mysql2.rb +2 -3
- data/lib/sequel/adapters/shared/mssql.rb +7 -7
- data/lib/sequel/adapters/shared/postgres.rb +37 -19
- data/lib/sequel/adapters/shared/sqlite.rb +27 -3
- data/lib/sequel/adapters/sqlite.rb +1 -1
- data/lib/sequel/adapters/tinytds.rb +12 -0
- data/lib/sequel/adapters/utils/mysql_mysql2.rb +2 -0
- data/lib/sequel/database/logging.rb +7 -1
- data/lib/sequel/database/query.rb +1 -1
- data/lib/sequel/database/schema_generator.rb +12 -3
- data/lib/sequel/database/schema_methods.rb +2 -0
- data/lib/sequel/database/transactions.rb +57 -5
- data/lib/sequel/dataset.rb +4 -2
- data/lib/sequel/dataset/actions.rb +3 -2
- data/lib/sequel/dataset/placeholder_literalizer.rb +4 -1
- data/lib/sequel/dataset/query.rb +5 -1
- data/lib/sequel/dataset/sql.rb +11 -7
- data/lib/sequel/extensions/named_timezones.rb +52 -8
- data/lib/sequel/extensions/pg_array.rb +4 -0
- data/lib/sequel/extensions/pg_json.rb +387 -123
- data/lib/sequel/extensions/pg_range.rb +3 -2
- data/lib/sequel/extensions/pg_row.rb +3 -1
- data/lib/sequel/extensions/schema_dumper.rb +1 -1
- data/lib/sequel/extensions/server_block.rb +15 -4
- data/lib/sequel/model/associations.rb +35 -9
- data/lib/sequel/model/plugins.rb +104 -0
- data/lib/sequel/plugins/association_dependencies.rb +3 -3
- data/lib/sequel/plugins/association_pks.rb +14 -4
- data/lib/sequel/plugins/association_proxies.rb +3 -2
- data/lib/sequel/plugins/class_table_inheritance.rb +11 -0
- data/lib/sequel/plugins/composition.rb +13 -9
- data/lib/sequel/plugins/finder.rb +2 -2
- data/lib/sequel/plugins/hook_class_methods.rb +17 -5
- data/lib/sequel/plugins/insert_conflict.rb +72 -0
- data/lib/sequel/plugins/inverted_subsets.rb +2 -2
- data/lib/sequel/plugins/pg_auto_constraint_validations.rb +147 -59
- data/lib/sequel/plugins/rcte_tree.rb +6 -0
- data/lib/sequel/plugins/static_cache.rb +8 -3
- data/lib/sequel/plugins/static_cache_cache.rb +53 -0
- data/lib/sequel/plugins/subset_conditions.rb +2 -2
- data/lib/sequel/plugins/validation_class_methods.rb +5 -3
- data/lib/sequel/sql.rb +15 -3
- data/lib/sequel/timezones.rb +50 -11
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/mssql_spec.rb +24 -0
- data/spec/adapters/mysql_spec.rb +0 -5
- data/spec/adapters/postgres_spec.rb +319 -1
- data/spec/bin_spec.rb +1 -1
- data/spec/core/database_spec.rb +123 -2
- data/spec/core/dataset_spec.rb +33 -1
- data/spec/core/expression_filters_spec.rb +25 -1
- data/spec/core/schema_spec.rb +24 -0
- data/spec/extensions/class_table_inheritance_spec.rb +30 -8
- data/spec/extensions/core_refinements_spec.rb +1 -1
- data/spec/extensions/hook_class_methods_spec.rb +22 -0
- data/spec/extensions/insert_conflict_spec.rb +103 -0
- data/spec/extensions/migration_spec.rb +13 -0
- data/spec/extensions/named_timezones_spec.rb +109 -2
- data/spec/extensions/pg_auto_constraint_validations_spec.rb +45 -0
- data/spec/extensions/pg_json_spec.rb +218 -29
- data/spec/extensions/pg_range_spec.rb +76 -9
- data/spec/extensions/rcte_tree_spec.rb +6 -0
- data/spec/extensions/s_spec.rb +1 -1
- data/spec/extensions/schema_dumper_spec.rb +4 -2
- data/spec/extensions/server_block_spec.rb +38 -0
- data/spec/extensions/spec_helper.rb +8 -1
- data/spec/extensions/static_cache_cache_spec.rb +35 -0
- data/spec/integration/dataset_test.rb +25 -9
- data/spec/integration/plugin_test.rb +42 -0
- data/spec/integration/schema_test.rb +7 -2
- data/spec/integration/transaction_test.rb +50 -0
- data/spec/model/associations_spec.rb +84 -4
- data/spec/model/plugins_spec.rb +111 -0
- metadata +16 -2
@@ -195,6 +195,19 @@ describe "Reversible Migrations with Sequel.migration{change{}}" do
|
|
195
195
|
[:drop_table, :a, {:foo=>:bar}]]
|
196
196
|
end
|
197
197
|
|
198
|
+
it "should reverse add_foreign_key with :type option" do
|
199
|
+
Sequel.migration{change{alter_table(:t){add_foreign_key :b, :c, :type=>:f}}}.apply(@db, :down)
|
200
|
+
actions = @db.actions
|
201
|
+
actions.must_equal [[:alter_table, [[:drop_foreign_key, :b, {:type=>:f}]]]]
|
202
|
+
@db.sqls
|
203
|
+
db = Sequel.mock
|
204
|
+
args = nil
|
205
|
+
db.define_singleton_method(:foreign_key_list){|*a| args = a; [{:name=>:fbc, :columns=>[:b]}]}
|
206
|
+
db.alter_table(:t){send(*actions[0][1][0])}
|
207
|
+
db.sqls.must_equal ["ALTER TABLE t DROP CONSTRAINT fbc", "ALTER TABLE t DROP COLUMN b"]
|
208
|
+
args.must_equal [:t]
|
209
|
+
end
|
210
|
+
|
198
211
|
it "should reverse add_foreign_key with :foreign_key_constraint_name option" do
|
199
212
|
Sequel.migration{change{alter_table(:t){add_foreign_key :b, :c, :foreign_key_constraint_name=>:f}}}.apply(@db, :down)
|
200
213
|
actions = @db.actions
|
@@ -9,7 +9,7 @@ Sequel.extension :thread_local_timezones
|
|
9
9
|
Sequel.extension :named_timezones
|
10
10
|
Sequel.datetime_class = Time
|
11
11
|
|
12
|
-
describe "Sequel named_timezones extension" do
|
12
|
+
describe "Sequel named_timezones extension with DateTime class" do
|
13
13
|
before do
|
14
14
|
@tz_in = TZInfo::Timezone.get('America/Los_Angeles')
|
15
15
|
@tz_out = TZInfo::Timezone.get('America/New_York')
|
@@ -54,10 +54,12 @@ describe "Sequel named_timezones extension" do
|
|
54
54
|
|
55
55
|
it "should convert datetimes coming out of the database from database_timezone to application_timezone" do
|
56
56
|
dt = Sequel.database_to_application_timestamp('2009-06-01 06:20:30-0400')
|
57
|
+
dt.must_be_instance_of DateTime
|
57
58
|
dt.must_equal @dt
|
58
59
|
dt.offset.must_equal(-7/24.0)
|
59
60
|
|
60
61
|
dt = Sequel.database_to_application_timestamp('2009-06-01 10:20:30+0000')
|
62
|
+
dt.must_be_instance_of DateTime
|
61
63
|
dt.must_equal @dt
|
62
64
|
dt.offset.must_equal(-7/24.0)
|
63
65
|
end
|
@@ -68,7 +70,9 @@ describe "Sequel named_timezones extension" do
|
|
68
70
|
|
69
71
|
it "should support tzinfo_disambiguator= to handle ambiguous timezones automatically" do
|
70
72
|
Sequel.tzinfo_disambiguator = proc{|datetime, periods| periods.first}
|
71
|
-
Sequel.database_to_application_timestamp('2004-10-31T01:30:00')
|
73
|
+
dt = Sequel.database_to_application_timestamp('2004-10-31T01:30:00')
|
74
|
+
dt.must_equal DateTime.parse('2004-10-30T22:30:00-07:00')
|
75
|
+
dt.offset.must_equal(-7/24.0)
|
72
76
|
end
|
73
77
|
|
74
78
|
it "should assume datetimes coming out of the database that don't have an offset as coming from database_timezone" do
|
@@ -108,4 +112,107 @@ describe "Sequel named_timezones extension" do
|
|
108
112
|
tz2.must_equal @tz_in
|
109
113
|
end
|
110
114
|
end
|
115
|
+
|
116
|
+
describe "Sequel named_timezones extension with Time class" do
|
117
|
+
before do
|
118
|
+
@tz_in = TZInfo::Timezone.get('America/Los_Angeles')
|
119
|
+
@tz_out = TZInfo::Timezone.get('America/New_York')
|
120
|
+
@db = Sequel.mock
|
121
|
+
Sequel.application_timezone = 'America/Los_Angeles'
|
122
|
+
Sequel.database_timezone = 'America/New_York'
|
123
|
+
end
|
124
|
+
after do
|
125
|
+
Sequel.tzinfo_disambiguator = nil
|
126
|
+
Sequel.default_timezone = nil
|
127
|
+
Sequel.datetime_class = Time
|
128
|
+
end
|
129
|
+
|
130
|
+
it "should convert string arguments to *_timezone= to TZInfo::Timezone instances" do
|
131
|
+
Sequel.application_timezone.must_equal @tz_in
|
132
|
+
Sequel.database_timezone.must_equal @tz_out
|
133
|
+
end
|
134
|
+
|
135
|
+
it "should convert string arguments for Database#timezone= to TZInfo::Timezone instances for database-specific timezones" do
|
136
|
+
@db.extension :named_timezones
|
137
|
+
@db.timezone = 'America/Los_Angeles'
|
138
|
+
@db.timezone.must_equal @tz_in
|
139
|
+
end
|
140
|
+
|
141
|
+
it "should accept TZInfo::Timezone instances in *_timezone=" do
|
142
|
+
Sequel.application_timezone = @tz_in
|
143
|
+
Sequel.database_timezone = @tz_out
|
144
|
+
Sequel.application_timezone.must_equal @tz_in
|
145
|
+
Sequel.database_timezone.must_equal @tz_out
|
146
|
+
end
|
147
|
+
|
148
|
+
it "should convert datetimes going into the database to named database_timezone" do
|
149
|
+
ds = @db[:a].with_extend do
|
150
|
+
def supports_timestamp_timezones?; true; end
|
151
|
+
def supports_timestamp_usecs?; false; end
|
152
|
+
end
|
153
|
+
ds.insert([Time.new(2009,6,1,3,20,30, RUBY_VERSION >= '2.6' ? @tz_in : -25200), Time.new(2009,6,1,3,20,30,-25200), Time.new(2009,6,1,6,20,30,-14400)])
|
154
|
+
@db.sqls.must_equal ["INSERT INTO a VALUES ('2009-06-01 06:20:30-0400', '2009-06-01 06:20:30-0400', '2009-06-01 06:20:30-0400')"]
|
155
|
+
end
|
156
|
+
|
157
|
+
it "should convert datetimes coming out of the database from database_timezone to application_timezone" do
|
158
|
+
dt = Sequel.database_to_application_timestamp('2009-06-01 06:20:30-0400')
|
159
|
+
dt.must_be_instance_of Time
|
160
|
+
dt.must_equal Time.new(2009,6,1,3,20,30,-25200)
|
161
|
+
dt.utc_offset.must_equal -25200
|
162
|
+
|
163
|
+
dt = Sequel.database_to_application_timestamp('2009-06-01 10:20:30+0000')
|
164
|
+
dt.must_be_instance_of Time
|
165
|
+
dt.must_equal Time.new(2009,6,1,3,20,30,-25200)
|
166
|
+
dt.utc_offset.must_equal -25200
|
167
|
+
end
|
168
|
+
|
169
|
+
it "should raise an error for ambiguous timezones by default" do
|
170
|
+
proc{Sequel.database_to_application_timestamp('2004-10-31T01:30:00')}.must_raise(Sequel::InvalidValue)
|
171
|
+
end
|
172
|
+
|
173
|
+
it "should support tzinfo_disambiguator= to handle ambiguous timezones automatically" do
|
174
|
+
Sequel.tzinfo_disambiguator = proc{|datetime, periods| periods.first}
|
175
|
+
Sequel.database_to_application_timestamp('2004-10-31T01:30:00').must_equal Time.new(2004, 10, 30, 22, 30, 0, -25200)
|
176
|
+
dt = Sequel.database_to_application_timestamp('2004-10-31T01:30:00')
|
177
|
+
dt.must_equal Time.new(2004, 10, 30, 22, 30, 0, -25200)
|
178
|
+
dt.utc_offset.must_equal -25200
|
179
|
+
end
|
180
|
+
|
181
|
+
it "should assume datetimes coming out of the database that don't have an offset as coming from database_timezone" do
|
182
|
+
dt = Sequel.database_to_application_timestamp('2009-06-01 06:20:30')
|
183
|
+
dt.must_be_instance_of Time
|
184
|
+
dt.must_equal Time.new(2009,6,1,3,20,30, -25200)
|
185
|
+
dt.utc_offset.must_equal -25200
|
186
|
+
|
187
|
+
dt = Sequel.database_to_application_timestamp('2009-06-01 10:20:30')
|
188
|
+
dt.must_be_instance_of Time
|
189
|
+
dt.must_equal Time.new(2009,6,1,7,20,30, -25200)
|
190
|
+
dt.utc_offset.must_equal -25200
|
191
|
+
end
|
192
|
+
|
193
|
+
it "should work with the thread_local_timezones extension" do
|
194
|
+
q, q1, q2 = Queue.new, Queue.new, Queue.new
|
195
|
+
tz1, tz2 = nil, nil
|
196
|
+
t1 = Thread.new do
|
197
|
+
Sequel.thread_application_timezone = 'America/New_York'
|
198
|
+
q2.push nil
|
199
|
+
q.pop
|
200
|
+
tz1 = Sequel.application_timezone
|
201
|
+
end
|
202
|
+
t2 = Thread.new do
|
203
|
+
Sequel.thread_application_timezone = 'America/Los_Angeles'
|
204
|
+
q2.push nil
|
205
|
+
q1.pop
|
206
|
+
tz2 = Sequel.application_timezone
|
207
|
+
end
|
208
|
+
q2.pop
|
209
|
+
q2.pop
|
210
|
+
q.push nil
|
211
|
+
q1.push nil
|
212
|
+
t1.join
|
213
|
+
t2.join
|
214
|
+
tz1.must_equal @tz_out
|
215
|
+
tz2.must_equal @tz_in
|
216
|
+
end
|
217
|
+
end
|
111
218
|
end
|
@@ -161,4 +161,49 @@ describe "pg_auto_constraint_validations plugin" do
|
|
161
161
|
proc{o.save}.must_raise Sequel::ValidationFailed
|
162
162
|
o.errors.must_equal(:i=>['is invalid'], :id=>['is invalid'])
|
163
163
|
end
|
164
|
+
|
165
|
+
it "should handle overridden constraint failures as validation errors when updating" do
|
166
|
+
o = @c.load(:i=>3)
|
167
|
+
@c.pg_auto_constraint_validation_override(:items_i_ocheck, :i, "foo bar")
|
168
|
+
@set_error[Sequel::CheckConstraintViolation, :constraint=>'items_i_ocheck']
|
169
|
+
proc{o.update(:i=>12)}.must_raise Sequel::ValidationFailed
|
170
|
+
o.errors.must_equal(:i=>['foo bar'])
|
171
|
+
end
|
172
|
+
|
173
|
+
it "should handle dumping cached metadata and loading metadata from cache" do
|
174
|
+
cache_file = "spec/files/pgacv-spec-#{$$}.cache"
|
175
|
+
begin
|
176
|
+
@ds = @db[:items]
|
177
|
+
@ds.send(:columns=, [:id, :i])
|
178
|
+
@db.fetch = @metadata_results.dup
|
179
|
+
c = Sequel::Model(@ds)
|
180
|
+
def c.name; 'Foo' end
|
181
|
+
@db.sqls
|
182
|
+
c.plugin :pg_auto_constraint_validations, :cache_file=>cache_file
|
183
|
+
@db.sqls.length.must_equal 5
|
184
|
+
|
185
|
+
o = c.new(:i=>12)
|
186
|
+
@set_error[Sequel::CheckConstraintViolation, :constraint=>'items_i_id_check']
|
187
|
+
proc{o.save}.must_raise Sequel::ValidationFailed
|
188
|
+
|
189
|
+
c.dump_pg_auto_constraint_validations_cache
|
190
|
+
|
191
|
+
@db.fetch = []
|
192
|
+
c = Sequel::Model(@ds)
|
193
|
+
def c.name; 'Foo' end
|
194
|
+
@db.sqls
|
195
|
+
c.plugin :pg_auto_constraint_validations, :cache_file=>cache_file
|
196
|
+
@db.sqls.must_be_empty
|
197
|
+
|
198
|
+
o = c.new(:i=>12)
|
199
|
+
@set_error[Sequel::CheckConstraintViolation, :constraint=>'items_i_id_check']
|
200
|
+
proc{o.save}.must_raise Sequel::ValidationFailed
|
201
|
+
ensure
|
202
|
+
File.delete(cache_file) if File.file?(cache_file)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
it "should raise error if attempting to dump cached metadata when not using caching" do
|
207
|
+
proc{@c.dump_pg_auto_constraint_validations_cache}.must_raise Sequel::Error
|
208
|
+
end
|
164
209
|
end
|
@@ -3,6 +3,8 @@ require_relative "spec_helper"
|
|
3
3
|
Sequel.extension :pg_array, :pg_json
|
4
4
|
|
5
5
|
describe "pg_json extension" do
|
6
|
+
integer_class = RUBY_VERSION >= '2.4' ? Integer : Fixnum
|
7
|
+
|
6
8
|
before(:all) do
|
7
9
|
m = Sequel::Postgres
|
8
10
|
@m = m::JSONDatabaseMethods
|
@@ -29,7 +31,7 @@ describe "pg_json extension" do
|
|
29
31
|
cp[3807].call("{[]}").must_equal [@bac.new([])]
|
30
32
|
end
|
31
33
|
|
32
|
-
|
34
|
+
deprecated "should parse json strings correctly" do
|
33
35
|
@m.parse_json('[]').class.must_equal(@ac)
|
34
36
|
@m.parse_json('[]').to_a.must_equal []
|
35
37
|
@m.parse_json('[1]').to_a.must_equal [1]
|
@@ -40,46 +42,82 @@ describe "pg_json extension" do
|
|
40
42
|
@m.parse_json('{"a": "b"}').to_hash.must_equal('a'=>'b')
|
41
43
|
@m.parse_json('{"a": "b", "c": [1, 2, 3]}').to_hash.must_equal('a'=>'b', 'c'=>[1, 2, 3])
|
42
44
|
@m.parse_json('{"a": "b", "c": {"d": "e"}}').to_hash.must_equal('a'=>'b', 'c'=>{'d'=>'e'})
|
45
|
+
proc{@m.parse_json("a")}.must_raise Sequel::InvalidValue
|
46
|
+
|
47
|
+
begin
|
48
|
+
Sequel.instance_eval do
|
49
|
+
alias pj parse_json
|
50
|
+
def parse_json(v)
|
51
|
+
{'1'=>1, "'a'"=>'a', 'true'=>true, 'false'=>false, 'null'=>nil, 'o'=>Object.new, '[one]'=>[1]}.fetch(v){pj(v)}
|
52
|
+
end
|
53
|
+
end
|
54
|
+
proc{@m.parse_json('o')}.must_raise(Sequel::InvalidValue)
|
55
|
+
ensure
|
56
|
+
Sequel.instance_eval do
|
57
|
+
alias parse_json pj
|
58
|
+
end
|
59
|
+
end
|
43
60
|
end
|
44
61
|
|
45
|
-
|
62
|
+
deprecated "should parse json and non-json plain strings, integers, and floats correctly in db_parse_json" do
|
46
63
|
@m.db_parse_json('{"a": "b", "c": {"d": "e"}}').to_hash.must_equal('a'=>'b', 'c'=>{'d'=>'e'})
|
47
64
|
@m.db_parse_json('[1, [2], {"a": "b"}]').to_a.must_equal [1, [2], {'a'=>'b'}]
|
48
65
|
@m.db_parse_json('1').must_equal 1
|
49
66
|
@m.db_parse_json('"b"').must_equal 'b'
|
50
67
|
@m.db_parse_json('1.1').must_equal 1.1
|
68
|
+
proc{@m.db_parse_json("a")}.must_raise Sequel::InvalidValue
|
51
69
|
end
|
52
70
|
|
53
|
-
|
71
|
+
deprecated "should parse jsonb and non-jsonb plain strings, integers, and floats correctly in db_parse_jsonb" do
|
54
72
|
@m.db_parse_jsonb('{"a": "b", "c": {"d": "e"}}').to_hash.must_equal('a'=>'b', 'c'=>{'d'=>'e'})
|
55
73
|
@m.db_parse_jsonb('[1, [2], {"a": "b"}]').to_a.must_equal [1, [2], {'a'=>'b'}]
|
56
74
|
@m.db_parse_jsonb('1').must_equal 1
|
57
75
|
@m.db_parse_jsonb('"b"').must_equal 'b'
|
58
76
|
@m.db_parse_jsonb('1.1').must_equal 1.1
|
77
|
+
proc{@m.db_parse_jsonb("a")}.must_raise Sequel::InvalidValue
|
59
78
|
end
|
60
79
|
|
61
|
-
it "should
|
62
|
-
|
63
|
-
|
80
|
+
it "should parse json and non-json plain strings, integers, and floats correctly in conversion_proc" do
|
81
|
+
cp = @db.conversion_procs[114]
|
82
|
+
cp.call('{"a": "b", "c": {"d": "e"}}').to_hash.must_equal('a'=>'b', 'c'=>{'d'=>'e'})
|
83
|
+
cp.call('[1, [2], {"a": "b"}]').to_a.must_equal [1, [2], {'a'=>'b'}]
|
84
|
+
cp.call('1').must_equal 1
|
85
|
+
cp.call('"b"').must_equal 'b'
|
86
|
+
cp.call('1.1').must_equal 1.1
|
87
|
+
end
|
64
88
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
89
|
+
it "should parse jsonb and non-jsonb plain strings, integers, and floats correctly in conversion_proc" do
|
90
|
+
cp = @db.conversion_procs[3802]
|
91
|
+
cp.call('{"a": "b", "c": {"d": "e"}}').to_hash.must_equal('a'=>'b', 'c'=>{'d'=>'e'})
|
92
|
+
cp.call('[1, [2], {"a": "b"}]').to_a.must_equal [1, [2], {'a'=>'b'}]
|
93
|
+
cp.call('1').must_equal 1
|
94
|
+
cp.call('"b"').must_equal 'b'
|
95
|
+
cp.call('1.1').must_equal 1.1
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should raise an error when attempting to parse invalid json" do
|
99
|
+
[114, 3802].each do |oid|
|
100
|
+
cp = @db.conversion_procs[oid]
|
101
|
+
proc{cp.call('a')}.must_raise(Sequel::InvalidValue)
|
102
|
+
|
103
|
+
begin
|
104
|
+
Sequel.instance_eval do
|
105
|
+
alias pj parse_json
|
106
|
+
def parse_json(v)
|
107
|
+
{'1'=>1, "'a'"=>'a', 'true'=>true, 'false'=>false, 'null'=>nil, 'o'=>Object.new, '[one]'=>[1]}.fetch(v){pj(v)}
|
108
|
+
end
|
109
|
+
end
|
110
|
+
cp.call('1').must_equal 1
|
111
|
+
cp.call("'a'").must_equal 'a'
|
112
|
+
cp.call('true').must_equal true
|
113
|
+
cp.call('false').must_equal false
|
114
|
+
cp.call('null').must_be_nil
|
115
|
+
proc{cp.call('o')}.must_raise(Sequel::InvalidValue)
|
116
|
+
cp.call('one').must_equal 1
|
117
|
+
ensure
|
118
|
+
Sequel.instance_eval do
|
119
|
+
alias parse_json pj
|
70
120
|
end
|
71
|
-
end
|
72
|
-
@m.parse_json('1').must_equal 1
|
73
|
-
@m.parse_json("'a'").must_equal 'a'
|
74
|
-
@m.parse_json('true').must_equal true
|
75
|
-
@m.parse_json('false').must_equal false
|
76
|
-
@m.parse_json('null').must_be_nil
|
77
|
-
proc{@m.parse_json('o')}.must_raise(Sequel::InvalidValue)
|
78
|
-
@m.db_parse_json('one').must_equal 1
|
79
|
-
@m.db_parse_jsonb('one').must_equal 1
|
80
|
-
ensure
|
81
|
-
Sequel.instance_eval do
|
82
|
-
alias parse_json pj
|
83
121
|
end
|
84
122
|
end
|
85
123
|
end
|
@@ -173,6 +211,129 @@ describe "pg_json extension" do
|
|
173
211
|
@db.bound_variable_arg(Sequel.pg_array([Sequel.pg_jsonb([{"a"=>1}]), Sequel.pg_jsonb("b"=>[1, 2])]), nil).must_equal '{"[{\\"a\\":1}]","{\\"b\\":[1,2]}"}'
|
174
212
|
end
|
175
213
|
|
214
|
+
it "should support using wrapped JSON and JSONB primitives as bound variables" do
|
215
|
+
@db.bound_variable_arg(Sequel.pg_json_wrap(1), nil).must_equal '1'
|
216
|
+
@db.bound_variable_arg(Sequel.pg_json_wrap(2.5), nil).must_equal '2.5'
|
217
|
+
@db.bound_variable_arg(Sequel.pg_json_wrap('a'), nil).must_equal '"a"'
|
218
|
+
@db.bound_variable_arg(Sequel.pg_json_wrap(true), nil).must_equal 'true'
|
219
|
+
@db.bound_variable_arg(Sequel.pg_json_wrap(false), nil).must_equal 'false'
|
220
|
+
@db.bound_variable_arg(Sequel.pg_json_wrap(nil), nil).must_equal 'null'
|
221
|
+
end
|
222
|
+
|
223
|
+
it "should support using json[] and jsonb[] types in bound variables with ruby primitives" do
|
224
|
+
@db.bound_variable_arg(Sequel.pg_array([1, 2.5, 'a', true, false, nil].map{|v| Sequel.pg_json_wrap(v)}), nil).must_equal '{"1","2.5","\"a\"","true","false","null"}'
|
225
|
+
end
|
226
|
+
|
227
|
+
it "Sequel.pg_json_wrap should wrap Ruby primitives in JSON wrappers" do
|
228
|
+
Sequel.pg_json_wrap({}).class.must_equal Sequel::Postgres::JSONHash
|
229
|
+
Sequel.pg_json_wrap({}).must_equal({})
|
230
|
+
Sequel.pg_json_wrap([]).class.must_equal Sequel::Postgres::JSONArray
|
231
|
+
Sequel.pg_json_wrap([]).must_equal []
|
232
|
+
Sequel.pg_json_wrap('a').class.must_equal Sequel::Postgres::JSONString
|
233
|
+
Sequel.pg_json_wrap('a').must_equal 'a'
|
234
|
+
Sequel.pg_json_wrap(1).class.must_equal Sequel::Postgres::JSONInteger
|
235
|
+
Sequel.pg_json_wrap(1).must_equal 1
|
236
|
+
Sequel.pg_json_wrap(2.5).class.must_equal Sequel::Postgres::JSONFloat
|
237
|
+
Sequel.pg_json_wrap(2.5).must_equal 2.5
|
238
|
+
Sequel.pg_json_wrap(true).class.must_equal Sequel::Postgres::JSONTrue
|
239
|
+
Sequel.pg_json_wrap(true).must_equal true
|
240
|
+
Sequel.pg_json_wrap(false).class.must_equal Sequel::Postgres::JSONFalse
|
241
|
+
Sequel.pg_json_wrap(false).must_equal false
|
242
|
+
Sequel.pg_json_wrap(nil).class.must_equal Sequel::Postgres::JSONNull
|
243
|
+
Sequel.pg_json_wrap(nil).must_be_nil
|
244
|
+
|
245
|
+
c = Class.new(Hash).new
|
246
|
+
Sequel.pg_json_wrap(c).class.must_equal Sequel::Postgres::JSONHash
|
247
|
+
Sequel.pg_json_wrap(c).must_equal(c)
|
248
|
+
|
249
|
+
c = Class.new(Array).new
|
250
|
+
Sequel.pg_json_wrap(c).class.must_equal Sequel::Postgres::JSONArray
|
251
|
+
Sequel.pg_json_wrap(c).must_equal c
|
252
|
+
|
253
|
+
c = Class.new(String).new('a')
|
254
|
+
Sequel.pg_json_wrap(c).class.must_equal Sequel::Postgres::JSONString
|
255
|
+
Sequel.pg_json_wrap(c).must_equal c
|
256
|
+
end
|
257
|
+
|
258
|
+
it "Sequel.pg_json_wrap should fail when passed an unsupported object" do
|
259
|
+
proc{Sequel.pg_json_wrap(Object.new)}.must_raise Sequel::Error
|
260
|
+
end
|
261
|
+
|
262
|
+
it "Sequel.pg_jsonb_wrap should wrap Ruby primitives in JSONB wrappers" do
|
263
|
+
Sequel.pg_jsonb_wrap({}).class.must_equal Sequel::Postgres::JSONBHash
|
264
|
+
Sequel.pg_jsonb_wrap({}).must_equal({})
|
265
|
+
Sequel.pg_jsonb_wrap([]).class.must_equal Sequel::Postgres::JSONBArray
|
266
|
+
Sequel.pg_jsonb_wrap([]).must_equal []
|
267
|
+
Sequel.pg_jsonb_wrap('a').class.must_equal Sequel::Postgres::JSONBString
|
268
|
+
Sequel.pg_jsonb_wrap('a').must_equal 'a'
|
269
|
+
Sequel.pg_jsonb_wrap(1).class.must_equal Sequel::Postgres::JSONBInteger
|
270
|
+
Sequel.pg_jsonb_wrap(1).must_equal 1
|
271
|
+
Sequel.pg_jsonb_wrap(2.5).class.must_equal Sequel::Postgres::JSONBFloat
|
272
|
+
Sequel.pg_jsonb_wrap(2.5).must_equal 2.5
|
273
|
+
Sequel.pg_jsonb_wrap(true).class.must_equal Sequel::Postgres::JSONBTrue
|
274
|
+
Sequel.pg_jsonb_wrap(true).must_equal true
|
275
|
+
Sequel.pg_jsonb_wrap(false).class.must_equal Sequel::Postgres::JSONBFalse
|
276
|
+
Sequel.pg_jsonb_wrap(false).must_equal false
|
277
|
+
Sequel.pg_jsonb_wrap(nil).class.must_equal Sequel::Postgres::JSONBNull
|
278
|
+
Sequel.pg_jsonb_wrap(nil).must_be_nil
|
279
|
+
end
|
280
|
+
|
281
|
+
it "Sequel.pg_jsonb_wrap should fail when passed an unsupported object" do
|
282
|
+
proc{Sequel.pg_jsonb_wrap(Object.new)}.must_raise Sequel::Error
|
283
|
+
end
|
284
|
+
|
285
|
+
it "should not wrap JSON primitives in json and jsonb conversion_proc when not setting wrap_json_primitives" do
|
286
|
+
[114, 3802].each do |oid|
|
287
|
+
cp = @db.conversion_procs[oid]
|
288
|
+
cp.call('1').class.must_equal(integer_class)
|
289
|
+
cp.call('1').must_equal 1
|
290
|
+
cp.call('2.5').class.must_equal Float
|
291
|
+
cp.call('2.5').must_equal 2.5
|
292
|
+
cp.call('"a"').class.must_equal String
|
293
|
+
cp.call('"a"').must_equal 'a'
|
294
|
+
cp.call('true').class.must_equal TrueClass
|
295
|
+
cp.call('true').must_equal true
|
296
|
+
cp.call('false').class.must_equal FalseClass
|
297
|
+
cp.call('false').must_equal false
|
298
|
+
cp.call('null').class.must_equal NilClass
|
299
|
+
cp.call('null').must_be_nil
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
it "should wrap JSON primitives in json conversion_proc when setting wrap_json_primitives" do
|
304
|
+
cp = @db.conversion_procs[114]
|
305
|
+
@db.wrap_json_primitives = true
|
306
|
+
cp.call('1').class.must_equal Sequel::Postgres::JSONInteger
|
307
|
+
cp.call('1').must_equal 1
|
308
|
+
cp.call('2.5').class.must_equal Sequel::Postgres::JSONFloat
|
309
|
+
cp.call('2.5').must_equal 2.5
|
310
|
+
cp.call('"a"').class.must_equal Sequel::Postgres::JSONString
|
311
|
+
cp.call('"a"').must_equal "a"
|
312
|
+
cp.call('true').class.must_equal Sequel::Postgres::JSONTrue
|
313
|
+
cp.call('true').must_equal true
|
314
|
+
cp.call('false').class.must_equal Sequel::Postgres::JSONFalse
|
315
|
+
cp.call('false').must_equal false
|
316
|
+
cp.call('null').class.must_equal Sequel::Postgres::JSONNull
|
317
|
+
cp.call('null').must_be_nil
|
318
|
+
end
|
319
|
+
|
320
|
+
it "should wrap JSON primitives in jsonb conversion_proc when setting wrap_json_primitives" do
|
321
|
+
cp = @db.conversion_procs[3802]
|
322
|
+
@db.wrap_json_primitives = true
|
323
|
+
cp.call('1').class.must_equal Sequel::Postgres::JSONBInteger
|
324
|
+
cp.call('1').must_equal 1
|
325
|
+
cp.call('2.5').class.must_equal Sequel::Postgres::JSONBFloat
|
326
|
+
cp.call('2.5').must_equal 2.5
|
327
|
+
cp.call('"a"').class.must_equal Sequel::Postgres::JSONBString
|
328
|
+
cp.call('"a"').must_equal "a"
|
329
|
+
cp.call('true').class.must_equal Sequel::Postgres::JSONBTrue
|
330
|
+
cp.call('true').must_equal true
|
331
|
+
cp.call('false').class.must_equal Sequel::Postgres::JSONBFalse
|
332
|
+
cp.call('false').must_equal false
|
333
|
+
cp.call('null').class.must_equal Sequel::Postgres::JSONBNull
|
334
|
+
cp.call('null').must_be_nil
|
335
|
+
end
|
336
|
+
|
176
337
|
it "should parse json type from the schema correctly" do
|
177
338
|
@db.fetch = [{:name=>'id', :db_type=>'integer'}, {:name=>'i', :db_type=>'json'}]
|
178
339
|
@db.schema(:items).map{|e| e[1][:type]}.must_equal [:integer, :json]
|
@@ -229,8 +390,22 @@ describe "pg_json extension" do
|
|
229
390
|
@db.typecast_value(:json, '[]').class.must_equal(@ac)
|
230
391
|
@db.typecast_value(:json, '{"a": "b"}').must_equal Sequel.pg_json("a"=>"b")
|
231
392
|
@db.typecast_value(:json, '{"a": "b"}').class.must_equal(@hc)
|
232
|
-
|
233
|
-
|
393
|
+
@db.typecast_value(:json, 1).class.must_equal Sequel::Postgres::JSONInteger
|
394
|
+
@db.typecast_value(:json, 1).must_equal 1
|
395
|
+
@db.typecast_value(:json, 2.5).class.must_equal Sequel::Postgres::JSONFloat
|
396
|
+
@db.typecast_value(:json, 2.5).must_equal 2.5
|
397
|
+
@db.typecast_value(:json, true).class.must_equal Sequel::Postgres::JSONTrue
|
398
|
+
@db.typecast_value(:json, true).must_equal true
|
399
|
+
@db.typecast_value(:json, false).class.must_equal Sequel::Postgres::JSONFalse
|
400
|
+
@db.typecast_value(:json, false).must_equal false
|
401
|
+
@db.typecast_value(:json, nil).class.must_equal NilClass
|
402
|
+
@db.typecast_value(:json, nil).must_be_nil
|
403
|
+
proc{@db.typecast_value(:json, 'a')}.must_raise(Sequel::InvalidValue)
|
404
|
+
proc{@db.typecast_value(:json, Object.new)}.must_raise(Sequel::InvalidValue)
|
405
|
+
|
406
|
+
@db.typecast_json_strings = true
|
407
|
+
@db.typecast_value(:json, '[]').class.must_equal(Sequel::Postgres::JSONString)
|
408
|
+
@db.typecast_value(:json, '[]').must_equal '[]'
|
234
409
|
end
|
235
410
|
|
236
411
|
it "should support typecasting for the jsonb type" do
|
@@ -250,13 +425,27 @@ describe "pg_json extension" do
|
|
250
425
|
@db.typecast_value(:jsonb, '[]').class.must_equal(@bac)
|
251
426
|
@db.typecast_value(:jsonb, '{"a": "b"}').must_equal Sequel.pg_jsonb("a"=>"b")
|
252
427
|
@db.typecast_value(:jsonb, '{"a": "b"}').class.must_equal(@bhc)
|
253
|
-
|
254
|
-
|
428
|
+
@db.typecast_value(:jsonb, 1).class.must_equal Sequel::Postgres::JSONBInteger
|
429
|
+
@db.typecast_value(:jsonb, 1).must_equal 1
|
430
|
+
@db.typecast_value(:jsonb, 2.5).class.must_equal Sequel::Postgres::JSONBFloat
|
431
|
+
@db.typecast_value(:jsonb, 2.5).must_equal 2.5
|
432
|
+
@db.typecast_value(:jsonb, true).class.must_equal Sequel::Postgres::JSONBTrue
|
433
|
+
@db.typecast_value(:jsonb, true).must_equal true
|
434
|
+
@db.typecast_value(:jsonb, false).class.must_equal Sequel::Postgres::JSONBFalse
|
435
|
+
@db.typecast_value(:jsonb, false).must_equal false
|
436
|
+
@db.typecast_value(:jsonb, nil).class.must_equal NilClass
|
437
|
+
@db.typecast_value(:jsonb, nil).must_be_nil
|
438
|
+
proc{@db.typecast_value(:jsonb, 'a')}.must_raise(Sequel::InvalidValue)
|
439
|
+
proc{@db.typecast_value(:jsonb, Object.new)}.must_raise(Sequel::InvalidValue)
|
440
|
+
|
441
|
+
@db.typecast_json_strings = true
|
442
|
+
@db.typecast_value(:jsonb, '[]').class.must_equal(Sequel::Postgres::JSONBString)
|
443
|
+
@db.typecast_value(:jsonb, '[]').must_equal '[]'
|
255
444
|
end
|
256
445
|
|
257
446
|
it "should return correct results for Database#schema_type_class" do
|
258
|
-
@db.schema_type_class(:json).must_equal [Sequel::Postgres::
|
259
|
-
@db.schema_type_class(:jsonb).must_equal [Sequel::Postgres::
|
447
|
+
@db.schema_type_class(:json).must_equal [Sequel::Postgres::JSONObject]
|
448
|
+
@db.schema_type_class(:jsonb).must_equal [Sequel::Postgres::JSONBObject]
|
260
449
|
@db.schema_type_class(:integer).must_equal Integer
|
261
450
|
end
|
262
451
|
end
|