sequel 5.20.0 → 5.21.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +24 -0
- data/doc/opening_databases.rdoc +2 -1
- data/doc/release_notes/5.21.0.txt +87 -0
- data/doc/sharding.rdoc +2 -0
- data/lib/sequel/adapters/ado.rb +27 -19
- data/lib/sequel/adapters/jdbc/mysql.rb +2 -2
- data/lib/sequel/adapters/shared/sqlite.rb +11 -1
- data/lib/sequel/adapters/sqlite.rb +1 -1
- data/lib/sequel/adapters/utils/mysql_mysql2.rb +2 -0
- data/lib/sequel/extensions/named_timezones.rb +2 -0
- data/lib/sequel/extensions/pg_json.rb +316 -123
- data/lib/sequel/extensions/server_block.rb +15 -4
- data/lib/sequel/plugins/rcte_tree.rb +6 -0
- 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 +180 -1
- data/spec/extensions/pg_json_spec.rb +206 -29
- data/spec/extensions/rcte_tree_spec.rb +6 -0
- data/spec/extensions/server_block_spec.rb +38 -0
- data/spec/integration/dataset_test.rb +1 -1
- metadata +4 -2
@@ -52,6 +52,12 @@
|
|
52
52
|
# DB[:a].server(:read_only).delete # Uses shard2
|
53
53
|
# end
|
54
54
|
#
|
55
|
+
# If you use an invalid server when calling with_server, it will be
|
56
|
+
# treated the same way as if you called Dataset#server with an invalid
|
57
|
+
# server. By default, the default server will be used in such cases.
|
58
|
+
# If you would like a different server to be used, or an exception to
|
59
|
+
# be raised, then use the :servers_hash Database option.
|
60
|
+
#
|
55
61
|
# Related modules: Sequel::ServerBlock, Sequel::UnthreadedServerBlock,
|
56
62
|
# Sequel::ThreadedServerBlock
|
57
63
|
|
@@ -110,9 +116,9 @@ module Sequel
|
|
110
116
|
else
|
111
117
|
case server
|
112
118
|
when :default, nil
|
113
|
-
@default_servers[-1][0]
|
119
|
+
@servers[@default_servers[-1][0]]
|
114
120
|
when :read_only
|
115
|
-
@default_servers[-1][1]
|
121
|
+
@servers[@default_servers[-1][1]]
|
116
122
|
else
|
117
123
|
super
|
118
124
|
end
|
@@ -155,11 +161,16 @@ module Sequel
|
|
155
161
|
if !a || a.empty?
|
156
162
|
super
|
157
163
|
else
|
164
|
+
# Hash handling required to work when loaded after arbitrary servers plugin.
|
158
165
|
case server
|
159
166
|
when :default, nil
|
160
|
-
a[-1][0]
|
167
|
+
v = a[-1][0]
|
168
|
+
v = @servers[v] unless v.is_a?(Hash)
|
169
|
+
v
|
161
170
|
when :read_only
|
162
|
-
a[-1][1]
|
171
|
+
v = a[-1][1]
|
172
|
+
v = @servers[v] unless v.is_a?(Hash)
|
173
|
+
v
|
163
174
|
else
|
164
175
|
super
|
165
176
|
end
|
@@ -126,6 +126,9 @@ module Sequel
|
|
126
126
|
a = opts.merge(opts.fetch(:ancestors, OPTS))
|
127
127
|
ancestors = a.fetch(:name, :ancestors)
|
128
128
|
a[:read_only] = true unless a.has_key?(:read_only)
|
129
|
+
a[:eager_grapher] = proc do |_|
|
130
|
+
raise Sequel::Error, "the #{ancestors} association for #{self} does not support eager graphing"
|
131
|
+
end
|
129
132
|
a[:eager_loader_key] = key
|
130
133
|
a[:dataset] ||= proc do
|
131
134
|
base_ds = model.where(prkey_array.zip(key_array.map{|k| get_column_value(k)}))
|
@@ -221,6 +224,9 @@ module Sequel
|
|
221
224
|
d = opts.merge(opts.fetch(:descendants, OPTS))
|
222
225
|
descendants = d.fetch(:name, :descendants)
|
223
226
|
d[:read_only] = true unless d.has_key?(:read_only)
|
227
|
+
d[:eager_grapher] = proc do |_|
|
228
|
+
raise Sequel::Error, "the #{descendants} association for #{self} does not support eager graphing"
|
229
|
+
end
|
224
230
|
la = d[:level_alias] ||= :x_level_x
|
225
231
|
d[:dataset] ||= proc do
|
226
232
|
base_ds = model.where(key_array.zip(prkey_array.map{|k| get_column_value(k)}))
|
data/lib/sequel/version.rb
CHANGED
@@ -6,7 +6,7 @@ module Sequel
|
|
6
6
|
|
7
7
|
# The minor version of Sequel. Bumped for every non-patch level
|
8
8
|
# release, generally around once a month.
|
9
|
-
MINOR =
|
9
|
+
MINOR = 21
|
10
10
|
|
11
11
|
# The tiny version of Sequel. Usually 0, only bumped for bugfix
|
12
12
|
# releases that fix regressions from previous versions.
|
data/spec/adapters/mssql_spec.rb
CHANGED
@@ -40,6 +40,30 @@ describe "A MSSQL database" do
|
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
|
+
describe "MSSQL decimal locale handling" do
|
44
|
+
before do
|
45
|
+
@locale = WIN32OLE.locale
|
46
|
+
@decimal = BigDecimal('1234.56')
|
47
|
+
end
|
48
|
+
after do
|
49
|
+
WIN32OLE.locale = @locale
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should work with current locale" do
|
53
|
+
DB.get(Sequel.cast(@decimal, 'decimal(16,4)').as(:v)).must_equal @decimal
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should work with 1031 locale" do
|
57
|
+
WIN32OLE.locale = 1031
|
58
|
+
DB.get(Sequel.cast(@decimal, 'decimal(16,4)').as(:v)).must_equal @decimal
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should work with 1033 locale" do
|
62
|
+
WIN32OLE.locale = 1033
|
63
|
+
DB.get(Sequel.cast(@decimal, 'decimal(16,4)').as(:v)).must_equal @decimal
|
64
|
+
end
|
65
|
+
end if DB.adapter_scheme == :ado
|
66
|
+
|
43
67
|
describe "MSSQL" do
|
44
68
|
before(:all) do
|
45
69
|
@db = DB
|
data/spec/adapters/mysql_spec.rb
CHANGED
@@ -551,11 +551,6 @@ describe "A MySQL database" do
|
|
551
551
|
db = Sequel.connect(DB.opts.merge(:read_timeout=>22342))
|
552
552
|
db.test_connection
|
553
553
|
end
|
554
|
-
|
555
|
-
it "should accept a connect_timeout option when connecting" do
|
556
|
-
db = Sequel.connect(DB.opts.merge(:connect_timeout=>22342))
|
557
|
-
db.test_connection
|
558
|
-
end
|
559
554
|
end
|
560
555
|
|
561
556
|
describe "MySQL foreign key support" do
|
@@ -2944,6 +2944,8 @@ describe 'PostgreSQL json type' do
|
|
2944
2944
|
@h = {'a'=>'b', '1'=>[3, 4, 5]}
|
2945
2945
|
end
|
2946
2946
|
after do
|
2947
|
+
@db.wrap_json_primitives = nil
|
2948
|
+
@db.typecast_json_strings = nil
|
2947
2949
|
@db.drop_table?(:items)
|
2948
2950
|
end
|
2949
2951
|
|
@@ -2951,9 +2953,12 @@ describe 'PostgreSQL json type' do
|
|
2951
2953
|
json_types << :jsonb if DB.server_version >= 90400
|
2952
2954
|
json_types.each do |json_type|
|
2953
2955
|
json_array_type = "#{json_type}[]"
|
2954
|
-
pg_json =
|
2956
|
+
pg_json = Sequel.method(:"pg_#{json_type}")
|
2957
|
+
pg_json_wrap = Sequel.method(:"pg_#{json_type}_wrap")
|
2955
2958
|
hash_class = json_type == :jsonb ? Sequel::Postgres::JSONBHash : Sequel::Postgres::JSONHash
|
2956
2959
|
array_class = json_type == :jsonb ? Sequel::Postgres::JSONBArray : Sequel::Postgres::JSONArray
|
2960
|
+
str_class = json_type == :jsonb ? Sequel::Postgres::JSONBString : Sequel::Postgres::JSONString
|
2961
|
+
object_class = json_type == :jsonb ? Sequel::Postgres::JSONBObject : Sequel::Postgres::JSONObject
|
2957
2962
|
|
2958
2963
|
it 'insert and retrieve json values' do
|
2959
2964
|
@db.create_table!(:items){column :j, json_type}
|
@@ -2983,6 +2988,44 @@ describe 'PostgreSQL json type' do
|
|
2983
2988
|
@ds.all.must_equal rs
|
2984
2989
|
end
|
2985
2990
|
|
2991
|
+
it 'insert and retrieve json primitive values' do
|
2992
|
+
@db.create_table!(:items){column :j, json_type}
|
2993
|
+
['str', 1, 2.5, nil, true, false].each do |rv|
|
2994
|
+
@ds.delete
|
2995
|
+
@ds.insert(pg_json_wrap.call(rv))
|
2996
|
+
@ds.count.must_equal 1
|
2997
|
+
rs = @ds.all
|
2998
|
+
v = rs.first[:j]
|
2999
|
+
v.class.must_equal(rv.class)
|
3000
|
+
if rv.nil?
|
3001
|
+
v.must_be_nil
|
3002
|
+
else
|
3003
|
+
v.must_equal rv
|
3004
|
+
end
|
3005
|
+
end
|
3006
|
+
|
3007
|
+
@db.wrap_json_primitives = true
|
3008
|
+
['str', 1, 2.5, nil, true, false].each do |rv|
|
3009
|
+
@ds.delete
|
3010
|
+
@ds.insert(pg_json_wrap.call(rv))
|
3011
|
+
@ds.count.must_equal 1
|
3012
|
+
rs = @ds.all
|
3013
|
+
v = rs.first[:j]
|
3014
|
+
v.class.ancestors.must_include(object_class)
|
3015
|
+
v.__getobj__.must_be_kind_of(rv.class)
|
3016
|
+
if rv.nil?
|
3017
|
+
v.must_be_nil
|
3018
|
+
v.__getobj__.must_be_nil
|
3019
|
+
else
|
3020
|
+
v.must_equal rv
|
3021
|
+
v.__getobj__.must_equal rv
|
3022
|
+
end
|
3023
|
+
@ds.delete
|
3024
|
+
@ds.insert(rs.first)
|
3025
|
+
@ds.all[0][:j].must_equal rs[0][:j]
|
3026
|
+
end
|
3027
|
+
end
|
3028
|
+
|
2986
3029
|
it 'insert and retrieve json[] values' do
|
2987
3030
|
@db.create_table!(:items){column :j, json_array_type}
|
2988
3031
|
j = Sequel.pg_array([pg_json.call('a'=>1), pg_json.call(['b', 2])])
|
@@ -2999,16 +3042,122 @@ describe 'PostgreSQL json type' do
|
|
2999
3042
|
@ds.all.must_equal rs
|
3000
3043
|
end
|
3001
3044
|
|
3045
|
+
it 'insert and retrieve json[] values with json primitives' do
|
3046
|
+
@db.create_table!(:items){column :j, json_array_type}
|
3047
|
+
raw = ['str', 1, 2.5, nil, true, false]
|
3048
|
+
j = Sequel.pg_array(raw.map(&pg_json_wrap), json_type)
|
3049
|
+
@ds.insert(j)
|
3050
|
+
@ds.count.must_equal 1
|
3051
|
+
rs = @ds.all
|
3052
|
+
v = rs.first[:j]
|
3053
|
+
v.class.must_equal(Sequel::Postgres::PGArray)
|
3054
|
+
v.to_a.must_be_kind_of(Array)
|
3055
|
+
v.map(&:class).must_equal raw.map(&:class)
|
3056
|
+
v.must_equal raw
|
3057
|
+
v.to_a.must_equal raw
|
3058
|
+
|
3059
|
+
@db.wrap_json_primitives = true
|
3060
|
+
j = Sequel.pg_array(raw.map(&pg_json_wrap), json_type)
|
3061
|
+
@ds.insert(j)
|
3062
|
+
rs = @ds.all
|
3063
|
+
v = rs.first[:j]
|
3064
|
+
v.class.must_equal(Sequel::Postgres::PGArray)
|
3065
|
+
v.to_a.must_be_kind_of(Array)
|
3066
|
+
v.map(&:class).each{|c| c.ancestors.must_include(object_class)}
|
3067
|
+
[v, v.to_a].each do |v0|
|
3068
|
+
v0.zip(raw) do |v1, r1|
|
3069
|
+
if r1.nil?
|
3070
|
+
v1.must_be_nil
|
3071
|
+
v1.__getobj__.must_be_nil
|
3072
|
+
else
|
3073
|
+
v1.must_equal r1
|
3074
|
+
v1.__getobj__.must_equal r1
|
3075
|
+
end
|
3076
|
+
end
|
3077
|
+
end
|
3078
|
+
@ds.delete
|
3079
|
+
@ds.insert(rs.first)
|
3080
|
+
@ds.all[0][:j].zip(rs[0][:j]) do |v1, r1|
|
3081
|
+
if v1.__getobj__.nil?
|
3082
|
+
v1.must_be_nil
|
3083
|
+
v1.__getobj__.must_be_nil
|
3084
|
+
else
|
3085
|
+
v1.must_equal r1
|
3086
|
+
v1.must_equal r1.__getobj__
|
3087
|
+
v1.__getobj__.must_equal r1
|
3088
|
+
v1.__getobj__.must_equal r1.__getobj__
|
3089
|
+
end
|
3090
|
+
end
|
3091
|
+
end
|
3092
|
+
|
3002
3093
|
it 'with models' do
|
3003
3094
|
@db.create_table!(:items) do
|
3004
3095
|
primary_key :id
|
3005
3096
|
column :h, json_type
|
3006
3097
|
end
|
3007
3098
|
c = Class.new(Sequel::Model(@db[:items]))
|
3099
|
+
c.create(:h=>@h).h.must_equal @h
|
3100
|
+
c.create(:h=>@a).h.must_equal @a
|
3008
3101
|
c.create(:h=>pg_json.call(@h)).h.must_equal @h
|
3009
3102
|
c.create(:h=>pg_json.call(@a)).h.must_equal @a
|
3010
3103
|
end
|
3011
3104
|
|
3105
|
+
it 'with models with json primitives' do
|
3106
|
+
@db.create_table!(:items) do
|
3107
|
+
primary_key :id
|
3108
|
+
column :h, json_type
|
3109
|
+
end
|
3110
|
+
c = Class.new(Sequel::Model(@db[:items]))
|
3111
|
+
|
3112
|
+
['str', 1, 2.5, nil, true, false].each do |v|
|
3113
|
+
@db.wrap_json_primitives = nil
|
3114
|
+
cv = c[c.insert(:h=>pg_json_wrap.call(v))]
|
3115
|
+
cv.h.class.ancestors.wont_include(object_class)
|
3116
|
+
if v.nil?
|
3117
|
+
cv.h.must_be_nil
|
3118
|
+
else
|
3119
|
+
cv.h.must_equal v
|
3120
|
+
end
|
3121
|
+
|
3122
|
+
@db.wrap_json_primitives = true
|
3123
|
+
cv.refresh
|
3124
|
+
cv.h.class.ancestors.must_include(object_class)
|
3125
|
+
cv.save
|
3126
|
+
cv.refresh
|
3127
|
+
cv.h.class
|
3128
|
+
|
3129
|
+
if v.nil?
|
3130
|
+
cv.h.must_be_nil
|
3131
|
+
else
|
3132
|
+
cv.h.must_equal v
|
3133
|
+
end
|
3134
|
+
|
3135
|
+
c.new(:h=>cv.h).h.class.ancestors.must_include(object_class)
|
3136
|
+
end
|
3137
|
+
|
3138
|
+
v = c.new(:h=>'{}').h
|
3139
|
+
v.class.must_equal hash_class
|
3140
|
+
v.must_equal({})
|
3141
|
+
@db.typecast_json_strings = true
|
3142
|
+
v = c.new(:h=>'{}').h
|
3143
|
+
v.class.must_equal str_class
|
3144
|
+
v.must_equal '{}'
|
3145
|
+
|
3146
|
+
c.new(:h=>'str').h.class.ancestors.must_include(object_class)
|
3147
|
+
c.new(:h=>'str').h.must_equal 'str'
|
3148
|
+
c.new(:h=>1).h.class.ancestors.must_include(object_class)
|
3149
|
+
c.new(:h=>1).h.must_equal 1
|
3150
|
+
c.new(:h=>2.5).h.class.ancestors.must_include(object_class)
|
3151
|
+
c.new(:h=>2.5).h.must_equal 2.5
|
3152
|
+
c.new(:h=>true).h.class.ancestors.must_include(object_class)
|
3153
|
+
c.new(:h=>true).h.must_equal true
|
3154
|
+
c.new(:h=>false).h.class.ancestors.must_include(object_class)
|
3155
|
+
c.new(:h=>false).h.must_equal false
|
3156
|
+
|
3157
|
+
c.new(:h=>nil).h.class.ancestors.wont_include(object_class)
|
3158
|
+
c.new(:h=>nil).h.must_be_nil
|
3159
|
+
end
|
3160
|
+
|
3012
3161
|
it 'with empty json default values and defaults_setter plugin' do
|
3013
3162
|
@db.create_table!(:items) do
|
3014
3163
|
column :h, json_type, :default=>hash_class.new({})
|
@@ -3043,6 +3192,36 @@ describe 'PostgreSQL json type' do
|
|
3043
3192
|
@ds.get(:i).must_equal j
|
3044
3193
|
end if uses_pg_or_jdbc
|
3045
3194
|
|
3195
|
+
it 'use json primitives in bound variables' do
|
3196
|
+
@db.create_table!(:items){column :i, json_type}
|
3197
|
+
@db.wrap_json_primitives = true
|
3198
|
+
raw = ['str', 1, 2.5, nil, true, false]
|
3199
|
+
raw.each do |v|
|
3200
|
+
@ds.delete
|
3201
|
+
@ds.call(:insert, {:i=>@db.get(pg_json_wrap.call(v))}, {:i=>:$i})
|
3202
|
+
rv = @ds.get(:i)
|
3203
|
+
rv.class.ancestors.must_include(object_class)
|
3204
|
+
if v.nil?
|
3205
|
+
rv.must_be_nil
|
3206
|
+
else
|
3207
|
+
rv.must_equal v
|
3208
|
+
end
|
3209
|
+
end
|
3210
|
+
|
3211
|
+
@db.create_table!(:items){column :i, json_array_type}
|
3212
|
+
j = Sequel.pg_array(raw.map(&pg_json_wrap), json_type)
|
3213
|
+
@ds.call(:insert, {:i=>j}, {:i=>:$i})
|
3214
|
+
@ds.all[0][:i].zip(raw) do |v1, r1|
|
3215
|
+
if v1.__getobj__.nil?
|
3216
|
+
v1.must_be_nil
|
3217
|
+
v1.__getobj__.must_be_nil
|
3218
|
+
else
|
3219
|
+
v1.must_equal r1
|
3220
|
+
v1.__getobj__.must_equal r1
|
3221
|
+
end
|
3222
|
+
end
|
3223
|
+
end if uses_pg_or_jdbc
|
3224
|
+
|
3046
3225
|
it 'operations/functions with pg_json_ops' do
|
3047
3226
|
Sequel.extension :pg_json_ops
|
3048
3227
|
jo = pg_json.call('a'=>1, 'b'=>{'c'=>2, 'd'=>{'e'=>3}}).op
|
@@ -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,117 @@ 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
|
+
end
|
245
|
+
|
246
|
+
it "Sequel.pg_json_wrap should fail when passed an unsupported object" do
|
247
|
+
proc{Sequel.pg_json_wrap(Object.new)}.must_raise Sequel::Error
|
248
|
+
end
|
249
|
+
|
250
|
+
it "Sequel.pg_jsonb_wrap should wrap Ruby primitives in JSONB wrappers" do
|
251
|
+
Sequel.pg_jsonb_wrap({}).class.must_equal Sequel::Postgres::JSONBHash
|
252
|
+
Sequel.pg_jsonb_wrap({}).must_equal({})
|
253
|
+
Sequel.pg_jsonb_wrap([]).class.must_equal Sequel::Postgres::JSONBArray
|
254
|
+
Sequel.pg_jsonb_wrap([]).must_equal []
|
255
|
+
Sequel.pg_jsonb_wrap('a').class.must_equal Sequel::Postgres::JSONBString
|
256
|
+
Sequel.pg_jsonb_wrap('a').must_equal 'a'
|
257
|
+
Sequel.pg_jsonb_wrap(1).class.must_equal Sequel::Postgres::JSONBInteger
|
258
|
+
Sequel.pg_jsonb_wrap(1).must_equal 1
|
259
|
+
Sequel.pg_jsonb_wrap(2.5).class.must_equal Sequel::Postgres::JSONBFloat
|
260
|
+
Sequel.pg_jsonb_wrap(2.5).must_equal 2.5
|
261
|
+
Sequel.pg_jsonb_wrap(true).class.must_equal Sequel::Postgres::JSONBTrue
|
262
|
+
Sequel.pg_jsonb_wrap(true).must_equal true
|
263
|
+
Sequel.pg_jsonb_wrap(false).class.must_equal Sequel::Postgres::JSONBFalse
|
264
|
+
Sequel.pg_jsonb_wrap(false).must_equal false
|
265
|
+
Sequel.pg_jsonb_wrap(nil).class.must_equal Sequel::Postgres::JSONBNull
|
266
|
+
Sequel.pg_jsonb_wrap(nil).must_be_nil
|
267
|
+
end
|
268
|
+
|
269
|
+
it "Sequel.pg_jsonb_wrap should fail when passed an unsupported object" do
|
270
|
+
proc{Sequel.pg_jsonb_wrap(Object.new)}.must_raise Sequel::Error
|
271
|
+
end
|
272
|
+
|
273
|
+
it "should not wrap JSON primitives in json and jsonb conversion_proc when not setting wrap_json_primitives" do
|
274
|
+
[114, 3802].each do |oid|
|
275
|
+
cp = @db.conversion_procs[oid]
|
276
|
+
cp.call('1').class.must_equal(integer_class)
|
277
|
+
cp.call('1').must_equal 1
|
278
|
+
cp.call('2.5').class.must_equal Float
|
279
|
+
cp.call('2.5').must_equal 2.5
|
280
|
+
cp.call('"a"').class.must_equal String
|
281
|
+
cp.call('"a"').must_equal 'a'
|
282
|
+
cp.call('true').class.must_equal TrueClass
|
283
|
+
cp.call('true').must_equal true
|
284
|
+
cp.call('false').class.must_equal FalseClass
|
285
|
+
cp.call('false').must_equal false
|
286
|
+
cp.call('null').class.must_equal NilClass
|
287
|
+
cp.call('null').must_be_nil
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
it "should wrap JSON primitives in json conversion_proc when setting wrap_json_primitives" do
|
292
|
+
cp = @db.conversion_procs[114]
|
293
|
+
@db.wrap_json_primitives = true
|
294
|
+
cp.call('1').class.must_equal Sequel::Postgres::JSONInteger
|
295
|
+
cp.call('1').must_equal 1
|
296
|
+
cp.call('2.5').class.must_equal Sequel::Postgres::JSONFloat
|
297
|
+
cp.call('2.5').must_equal 2.5
|
298
|
+
cp.call('"a"').class.must_equal Sequel::Postgres::JSONString
|
299
|
+
cp.call('"a"').must_equal "a"
|
300
|
+
cp.call('true').class.must_equal Sequel::Postgres::JSONTrue
|
301
|
+
cp.call('true').must_equal true
|
302
|
+
cp.call('false').class.must_equal Sequel::Postgres::JSONFalse
|
303
|
+
cp.call('false').must_equal false
|
304
|
+
cp.call('null').class.must_equal Sequel::Postgres::JSONNull
|
305
|
+
cp.call('null').must_be_nil
|
306
|
+
end
|
307
|
+
|
308
|
+
it "should wrap JSON primitives in jsonb conversion_proc when setting wrap_json_primitives" do
|
309
|
+
cp = @db.conversion_procs[3802]
|
310
|
+
@db.wrap_json_primitives = true
|
311
|
+
cp.call('1').class.must_equal Sequel::Postgres::JSONBInteger
|
312
|
+
cp.call('1').must_equal 1
|
313
|
+
cp.call('2.5').class.must_equal Sequel::Postgres::JSONBFloat
|
314
|
+
cp.call('2.5').must_equal 2.5
|
315
|
+
cp.call('"a"').class.must_equal Sequel::Postgres::JSONBString
|
316
|
+
cp.call('"a"').must_equal "a"
|
317
|
+
cp.call('true').class.must_equal Sequel::Postgres::JSONBTrue
|
318
|
+
cp.call('true').must_equal true
|
319
|
+
cp.call('false').class.must_equal Sequel::Postgres::JSONBFalse
|
320
|
+
cp.call('false').must_equal false
|
321
|
+
cp.call('null').class.must_equal Sequel::Postgres::JSONBNull
|
322
|
+
cp.call('null').must_be_nil
|
323
|
+
end
|
324
|
+
|
176
325
|
it "should parse json type from the schema correctly" do
|
177
326
|
@db.fetch = [{:name=>'id', :db_type=>'integer'}, {:name=>'i', :db_type=>'json'}]
|
178
327
|
@db.schema(:items).map{|e| e[1][:type]}.must_equal [:integer, :json]
|
@@ -229,8 +378,22 @@ describe "pg_json extension" do
|
|
229
378
|
@db.typecast_value(:json, '[]').class.must_equal(@ac)
|
230
379
|
@db.typecast_value(:json, '{"a": "b"}').must_equal Sequel.pg_json("a"=>"b")
|
231
380
|
@db.typecast_value(:json, '{"a": "b"}').class.must_equal(@hc)
|
232
|
-
|
233
|
-
|
381
|
+
@db.typecast_value(:json, 1).class.must_equal Sequel::Postgres::JSONInteger
|
382
|
+
@db.typecast_value(:json, 1).must_equal 1
|
383
|
+
@db.typecast_value(:json, 2.5).class.must_equal Sequel::Postgres::JSONFloat
|
384
|
+
@db.typecast_value(:json, 2.5).must_equal 2.5
|
385
|
+
@db.typecast_value(:json, true).class.must_equal Sequel::Postgres::JSONTrue
|
386
|
+
@db.typecast_value(:json, true).must_equal true
|
387
|
+
@db.typecast_value(:json, false).class.must_equal Sequel::Postgres::JSONFalse
|
388
|
+
@db.typecast_value(:json, false).must_equal false
|
389
|
+
@db.typecast_value(:json, nil).class.must_equal NilClass
|
390
|
+
@db.typecast_value(:json, nil).must_be_nil
|
391
|
+
proc{@db.typecast_value(:json, 'a')}.must_raise(Sequel::InvalidValue)
|
392
|
+
proc{@db.typecast_value(:json, Object.new)}.must_raise(Sequel::InvalidValue)
|
393
|
+
|
394
|
+
@db.typecast_json_strings = true
|
395
|
+
@db.typecast_value(:json, '[]').class.must_equal(Sequel::Postgres::JSONString)
|
396
|
+
@db.typecast_value(:json, '[]').must_equal '[]'
|
234
397
|
end
|
235
398
|
|
236
399
|
it "should support typecasting for the jsonb type" do
|
@@ -250,13 +413,27 @@ describe "pg_json extension" do
|
|
250
413
|
@db.typecast_value(:jsonb, '[]').class.must_equal(@bac)
|
251
414
|
@db.typecast_value(:jsonb, '{"a": "b"}').must_equal Sequel.pg_jsonb("a"=>"b")
|
252
415
|
@db.typecast_value(:jsonb, '{"a": "b"}').class.must_equal(@bhc)
|
253
|
-
|
254
|
-
|
416
|
+
@db.typecast_value(:jsonb, 1).class.must_equal Sequel::Postgres::JSONBInteger
|
417
|
+
@db.typecast_value(:jsonb, 1).must_equal 1
|
418
|
+
@db.typecast_value(:jsonb, 2.5).class.must_equal Sequel::Postgres::JSONBFloat
|
419
|
+
@db.typecast_value(:jsonb, 2.5).must_equal 2.5
|
420
|
+
@db.typecast_value(:jsonb, true).class.must_equal Sequel::Postgres::JSONBTrue
|
421
|
+
@db.typecast_value(:jsonb, true).must_equal true
|
422
|
+
@db.typecast_value(:jsonb, false).class.must_equal Sequel::Postgres::JSONBFalse
|
423
|
+
@db.typecast_value(:jsonb, false).must_equal false
|
424
|
+
@db.typecast_value(:jsonb, nil).class.must_equal NilClass
|
425
|
+
@db.typecast_value(:jsonb, nil).must_be_nil
|
426
|
+
proc{@db.typecast_value(:jsonb, 'a')}.must_raise(Sequel::InvalidValue)
|
427
|
+
proc{@db.typecast_value(:jsonb, Object.new)}.must_raise(Sequel::InvalidValue)
|
428
|
+
|
429
|
+
@db.typecast_json_strings = true
|
430
|
+
@db.typecast_value(:jsonb, '[]').class.must_equal(Sequel::Postgres::JSONBString)
|
431
|
+
@db.typecast_value(:jsonb, '[]').must_equal '[]'
|
255
432
|
end
|
256
433
|
|
257
434
|
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::
|
435
|
+
@db.schema_type_class(:json).must_equal [Sequel::Postgres::JSONObject]
|
436
|
+
@db.schema_type_class(:jsonb).must_equal [Sequel::Postgres::JSONBObject]
|
260
437
|
@db.schema_type_class(:integer).must_equal Integer
|
261
438
|
end
|
262
439
|
end
|