sequel 5.20.0 → 5.21.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 +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
|