sequel 3.44.0 → 3.45.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.
- data/CHANGELOG +44 -0
- data/Rakefile +12 -4
- data/doc/reflection.rdoc +3 -3
- data/doc/release_notes/3.45.0.txt +179 -0
- data/doc/schema_modification.rdoc +1 -1
- data/doc/transactions.rdoc +23 -0
- data/lib/sequel/adapters/db2.rb +1 -0
- data/lib/sequel/adapters/ibmdb.rb +19 -3
- data/lib/sequel/adapters/jdbc.rb +15 -0
- data/lib/sequel/adapters/jdbc/derby.rb +1 -5
- data/lib/sequel/adapters/jdbc/h2.rb +1 -0
- data/lib/sequel/adapters/jdbc/hsqldb.rb +2 -1
- data/lib/sequel/adapters/jdbc/jtds.rb +5 -0
- data/lib/sequel/adapters/jdbc/mysql.rb +5 -0
- data/lib/sequel/adapters/jdbc/oracle.rb +7 -1
- data/lib/sequel/adapters/jdbc/sqlite.rb +1 -1
- data/lib/sequel/adapters/jdbc/transactions.rb +28 -1
- data/lib/sequel/adapters/mysql.rb +4 -0
- data/lib/sequel/adapters/mysql2.rb +5 -1
- data/lib/sequel/adapters/oracle.rb +18 -0
- data/lib/sequel/adapters/postgres.rb +11 -1
- data/lib/sequel/adapters/shared/access.rb +14 -2
- data/lib/sequel/adapters/shared/cubrid.rb +1 -11
- data/lib/sequel/adapters/shared/db2.rb +11 -6
- data/lib/sequel/adapters/shared/mssql.rb +10 -10
- data/lib/sequel/adapters/shared/mysql.rb +11 -1
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +17 -1
- data/lib/sequel/adapters/shared/oracle.rb +16 -15
- data/lib/sequel/adapters/shared/postgres.rb +91 -59
- data/lib/sequel/adapters/shared/sqlite.rb +1 -4
- data/lib/sequel/adapters/tinytds.rb +15 -0
- data/lib/sequel/connection_pool/threaded.rb +1 -1
- data/lib/sequel/core.rb +10 -0
- data/lib/sequel/database/connecting.rb +2 -0
- data/lib/sequel/database/misc.rb +46 -4
- data/lib/sequel/database/query.rb +33 -14
- data/lib/sequel/database/schema_methods.rb +0 -5
- data/lib/sequel/dataset/misc.rb +9 -0
- data/lib/sequel/dataset/mutation.rb +9 -7
- data/lib/sequel/dataset/sql.rb +13 -0
- data/lib/sequel/exceptions.rb +3 -0
- data/lib/sequel/extensions/connection_validator.rb +1 -1
- data/lib/sequel/extensions/date_arithmetic.rb +0 -8
- data/lib/sequel/extensions/eval_inspect.rb +2 -0
- data/lib/sequel/extensions/named_timezones.rb +18 -2
- data/lib/sequel/extensions/pg_array.rb +5 -1
- data/lib/sequel/extensions/pg_array_ops.rb +2 -0
- data/lib/sequel/extensions/pg_hstore.rb +2 -0
- data/lib/sequel/extensions/pg_hstore_ops.rb +2 -0
- data/lib/sequel/extensions/pg_json.rb +3 -1
- data/lib/sequel/extensions/pg_range.rb +2 -0
- data/lib/sequel/extensions/pg_range_ops.rb +2 -0
- data/lib/sequel/extensions/pg_row.rb +2 -0
- data/lib/sequel/extensions/pg_row_ops.rb +2 -0
- data/lib/sequel/extensions/query.rb +18 -22
- data/lib/sequel/model/associations.rb +3 -4
- data/lib/sequel/model/base.rb +2 -0
- data/lib/sequel/plugins/force_encoding.rb +2 -0
- data/lib/sequel/plugins/json_serializer.rb +155 -39
- data/lib/sequel/plugins/serialization.rb +14 -2
- data/lib/sequel/plugins/unlimited_update.rb +31 -0
- data/lib/sequel/plugins/validation_class_methods.rb +6 -4
- data/lib/sequel/plugins/xml_serializer.rb +133 -30
- data/lib/sequel/sql.rb +2 -0
- data/lib/sequel/timezones.rb +4 -0
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/mysql_spec.rb +0 -11
- data/spec/adapters/postgres_spec.rb +86 -54
- data/spec/adapters/spec_helper.rb +6 -0
- data/spec/core/connection_pool_spec.rb +16 -0
- data/spec/core/database_spec.rb +77 -1
- data/spec/core/dataset_spec.rb +30 -15
- data/spec/core/expression_filters_spec.rb +55 -13
- data/spec/core/mock_adapter_spec.rb +4 -0
- data/spec/core/schema_spec.rb +0 -2
- data/spec/core/spec_helper.rb +5 -0
- data/spec/core_extensions_spec.rb +33 -28
- data/spec/extensions/constraint_validations_spec.rb +2 -2
- data/spec/extensions/core_refinements_spec.rb +12 -12
- data/spec/extensions/json_serializer_spec.rb +137 -31
- data/spec/extensions/named_timezones_spec.rb +10 -0
- data/spec/extensions/pg_auto_parameterize_spec.rb +5 -0
- data/spec/extensions/pg_json_spec.rb +14 -0
- data/spec/extensions/pg_row_spec.rb +11 -0
- data/spec/extensions/pretty_table_spec.rb +2 -2
- data/spec/extensions/query_spec.rb +11 -8
- data/spec/extensions/serialization_spec.rb +20 -0
- data/spec/extensions/spec_helper.rb +8 -2
- data/spec/extensions/sql_expr_spec.rb +1 -1
- data/spec/extensions/unlimited_update_spec.rb +20 -0
- data/spec/extensions/xml_serializer_spec.rb +68 -16
- data/spec/integration/dataset_test.rb +28 -0
- data/spec/integration/spec_helper.rb +6 -0
- data/spec/integration/transaction_test.rb +39 -0
- data/spec/model/model_spec.rb +1 -1
- data/spec/sequel_coverage.rb +15 -0
- metadata +8 -3
@@ -240,14 +240,14 @@ describe "constraint_validations extension" do
|
|
240
240
|
@db.create_table(:foo){String :name; validate{like 'foo%', :name}}
|
241
241
|
sqls = @db.sqls
|
242
242
|
parse_insert(sqls.slice!(1)).should == {:validation_type=>"like", :column=>"name", :table=>"foo", :argument=>'foo%'}
|
243
|
-
sqls.should == ["BEGIN", "COMMIT", "CREATE TABLE foo (name varchar(255), CHECK ((name IS NOT NULL) AND (name LIKE 'foo%')))"]
|
243
|
+
sqls.should == ["BEGIN", "COMMIT", "CREATE TABLE foo (name varchar(255), CHECK ((name IS NOT NULL) AND (name LIKE 'foo%' ESCAPE '\\')))"]
|
244
244
|
end
|
245
245
|
|
246
246
|
it "should support :ilike constraint validation" do
|
247
247
|
@db.create_table(:foo){String :name; validate{ilike 'foo%', :name}}
|
248
248
|
sqls = @db.sqls
|
249
249
|
parse_insert(sqls.slice!(1)).should == {:validation_type=>"ilike", :column=>"name", :table=>"foo", :argument=>'foo%'}
|
250
|
-
sqls.should == ["BEGIN", "COMMIT", "CREATE TABLE foo (name varchar(255), CHECK ((name IS NOT NULL) AND (name
|
250
|
+
sqls.should == ["BEGIN", "COMMIT", "CREATE TABLE foo (name varchar(255), CHECK ((name IS NOT NULL) AND (UPPER(name) LIKE UPPER('foo%') ESCAPE '\\')))"]
|
251
251
|
end
|
252
252
|
|
253
253
|
it "should support :unique constraint validation" do
|
@@ -69,35 +69,35 @@ describe "Core refinements" do
|
|
69
69
|
end
|
70
70
|
|
71
71
|
it "should support LIKE via Symbol#like" do
|
72
|
-
@d.l(:x.like('a')).should == '(x LIKE \'a\')'
|
72
|
+
@d.l(:x.like('a')).should == '(x LIKE \'a\' ESCAPE \'\\\')'
|
73
73
|
@d.l(:x.like(/a/)).should == '(x ~ \'a\')'
|
74
|
-
@d.l(:x.like('a', 'b')).should == '((x LIKE \'a\') OR (x LIKE \'b\'))'
|
74
|
+
@d.l(:x.like('a', 'b')).should == '((x LIKE \'a\' ESCAPE \'\\\') OR (x LIKE \'b\' ESCAPE \'\\\'))'
|
75
75
|
@d.l(:x.like(/a/, /b/i)).should == '((x ~ \'a\') OR (x ~* \'b\'))'
|
76
|
-
@d.l(:x.like('a', /b/)).should == '((x LIKE \'a\') OR (x ~ \'b\'))'
|
76
|
+
@d.l(:x.like('a', /b/)).should == '((x LIKE \'a\' ESCAPE \'\\\') OR (x ~ \'b\'))'
|
77
77
|
end
|
78
78
|
|
79
79
|
it "should support NOT LIKE via Symbol#like and Symbol#~" do
|
80
|
-
@d.l(~:x.like('a')).should == '(x NOT LIKE \'a\')'
|
80
|
+
@d.l(~:x.like('a')).should == '(x NOT LIKE \'a\' ESCAPE \'\\\')'
|
81
81
|
@d.l(~:x.like(/a/)).should == '(x !~ \'a\')'
|
82
|
-
@d.l(~:x.like('a', 'b')).should == '((x NOT LIKE \'a\') AND (x NOT LIKE \'b\'))'
|
82
|
+
@d.l(~:x.like('a', 'b')).should == '((x NOT LIKE \'a\' ESCAPE \'\\\') AND (x NOT LIKE \'b\' ESCAPE \'\\\'))'
|
83
83
|
@d.l(~:x.like(/a/, /b/i)).should == '((x !~ \'a\') AND (x !~* \'b\'))'
|
84
|
-
@d.l(~:x.like('a', /b/)).should == '((x NOT LIKE \'a\') AND (x !~ \'b\'))'
|
84
|
+
@d.l(~:x.like('a', /b/)).should == '((x NOT LIKE \'a\' ESCAPE \'\\\') AND (x !~ \'b\'))'
|
85
85
|
end
|
86
86
|
|
87
87
|
it "should support ILIKE via Symbol#ilike" do
|
88
|
-
@d.l(:x.ilike('a')).should == '(x
|
88
|
+
@d.l(:x.ilike('a')).should == '(UPPER(x) LIKE UPPER(\'a\') ESCAPE \'\\\')'
|
89
89
|
@d.l(:x.ilike(/a/)).should == '(x ~* \'a\')'
|
90
|
-
@d.l(:x.ilike('a', 'b')).should == '((x
|
90
|
+
@d.l(:x.ilike('a', 'b')).should == '((UPPER(x) LIKE UPPER(\'a\') ESCAPE \'\\\') OR (UPPER(x) LIKE UPPER(\'b\') ESCAPE \'\\\'))'
|
91
91
|
@d.l(:x.ilike(/a/, /b/i)).should == '((x ~* \'a\') OR (x ~* \'b\'))'
|
92
|
-
@d.l(:x.ilike('a', /b/)).should == '((x
|
92
|
+
@d.l(:x.ilike('a', /b/)).should == '((UPPER(x) LIKE UPPER(\'a\') ESCAPE \'\\\') OR (x ~* \'b\'))'
|
93
93
|
end
|
94
94
|
|
95
95
|
it "should support NOT ILIKE via Symbol#ilike and Symbol#~" do
|
96
|
-
@d.l(~:x.ilike('a')).should == '(x NOT
|
96
|
+
@d.l(~:x.ilike('a')).should == '(UPPER(x) NOT LIKE UPPER(\'a\') ESCAPE \'\\\')'
|
97
97
|
@d.l(~:x.ilike(/a/)).should == '(x !~* \'a\')'
|
98
|
-
@d.l(~:x.ilike('a', 'b')).should == '((x NOT
|
98
|
+
@d.l(~:x.ilike('a', 'b')).should == '((UPPER(x) NOT LIKE UPPER(\'a\') ESCAPE \'\\\') AND (UPPER(x) NOT LIKE UPPER(\'b\') ESCAPE \'\\\'))'
|
99
99
|
@d.l(~:x.ilike(/a/, /b/i)).should == '((x !~* \'a\') AND (x !~* \'b\'))'
|
100
|
-
@d.l(~:x.ilike('a', /b/)).should == '((x NOT
|
100
|
+
@d.l(~:x.ilike('a', /b/)).should == '((UPPER(x) NOT LIKE UPPER(\'a\') ESCAPE \'\\\') AND (x !~* \'b\'))'
|
101
101
|
end
|
102
102
|
|
103
103
|
it "should support sql_expr on arrays with all two pairs" do
|
@@ -3,12 +3,15 @@ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
|
|
3
3
|
describe "Sequel::Plugins::JsonSerializer" do
|
4
4
|
before do
|
5
5
|
class ::Artist < Sequel::Model
|
6
|
+
unrestrict_primary_key
|
6
7
|
plugin :json_serializer
|
7
8
|
columns :id, :name
|
8
9
|
def_column_accessor :id, :name
|
10
|
+
@db_schema = {:id=>{:type=>:integer}}
|
9
11
|
one_to_many :albums
|
10
12
|
end
|
11
13
|
class ::Album < Sequel::Model
|
14
|
+
unrestrict_primary_key
|
12
15
|
attr_accessor :blah
|
13
16
|
plugin :json_serializer
|
14
17
|
columns :id, :name, :artist_id
|
@@ -27,8 +30,8 @@ describe "Sequel::Plugins::JsonSerializer" do
|
|
27
30
|
end
|
28
31
|
|
29
32
|
it "should round trip successfully" do
|
30
|
-
|
31
|
-
|
33
|
+
Artist.from_json(@artist.to_json).should == @artist
|
34
|
+
Album.from_json(@album.to_json).should == @album
|
32
35
|
end
|
33
36
|
|
34
37
|
it "should handle ruby objects in values" do
|
@@ -37,52 +40,106 @@ describe "Sequel::Plugins::JsonSerializer" do
|
|
37
40
|
super(Date.parse(v))
|
38
41
|
end
|
39
42
|
end
|
40
|
-
|
43
|
+
Artist.from_json(Artist.load(:name=>Date.today).to_json).should == Artist.load(:name=>Date.today)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should have .json_create method for creating an instance from a hash parsed from JSON" do
|
47
|
+
JSON.parse(@artist.to_json, :create_additions=>true).should == @artist
|
48
|
+
JSON.parse(@artist.to_json(:include=>{:albums=>{:include=>{:artist=>{:include=>:albums}}}}), :create_additions=>true).albums.map{|a| a.artist.albums}.should == [[@album]]
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should have .json_create method raise error if not given a hash" do
|
52
|
+
proc{Artist.json_create([])}.should raise_error(Sequel::Error)
|
41
53
|
end
|
42
54
|
|
43
55
|
it "should handle the :only option" do
|
44
|
-
|
45
|
-
|
56
|
+
Artist.from_json(@artist.to_json(:only=>:name)).should == Artist.load(:name=>@artist.name)
|
57
|
+
Album.from_json(@album.to_json(:only=>[:id, :name])).should == Album.load(:id=>@album.id, :name=>@album.name)
|
46
58
|
end
|
47
59
|
|
48
60
|
it "should handle the :except option" do
|
49
|
-
|
50
|
-
|
61
|
+
Artist.from_json(@artist.to_json(:except=>:id)).should == Artist.load(:name=>@artist.name)
|
62
|
+
Album.from_json(@album.to_json(:except=>[:id, :artist_id])).should == Album.load(:name=>@album.name)
|
51
63
|
end
|
52
64
|
|
53
65
|
it "should handle the :include option for associations" do
|
54
|
-
|
55
|
-
|
66
|
+
Artist.from_json(@artist.to_json(:include=>:albums), :associations=>:albums).albums.should == [@album]
|
67
|
+
Album.from_json(@album.to_json(:include=>:artist), :associations=>:artist).artist.should == @artist
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should raise an error if attempting to parse json when providing array to non-array association or vice-versa" do
|
71
|
+
proc{Artist.from_json('{"albums":{"id":1,"name":"RF","artist_id":2,"json_class":"Album"},"id":2,"name":"YJM","json_class":"Artist"}', :associations=>:albums)}.should raise_error(Sequel::Error)
|
72
|
+
proc{Album.from_json('{"artist":[{"id":2,"name":"YJM","json_class":"Artist"}],"id":1,"name":"RF","json_class":"Album","artist_id":2}', :associations=>:artist)}.should raise_error(Sequel::Error)
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should raise an error if attempting to parse an array containing non-hashes" do
|
76
|
+
proc{Artist.from_json('[{"id":2,"name":"YJM","json_class":"Artist"}, 2]')}.should raise_error(Sequel::Error)
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should raise an error if attempting to parse invalid JSON" do
|
80
|
+
begin
|
81
|
+
Sequel.instance_eval do
|
82
|
+
alias pj parse_json
|
83
|
+
def parse_json(v)
|
84
|
+
v
|
85
|
+
end
|
86
|
+
end
|
87
|
+
proc{Album.from_json('1')}.should raise_error(Sequel::Error)
|
88
|
+
ensure
|
89
|
+
Sequel.instance_eval do
|
90
|
+
alias parse_json pj
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should handle case where Sequel.parse_json already returns an instance" do
|
96
|
+
begin
|
97
|
+
Sequel.instance_eval do
|
98
|
+
alias pj parse_json
|
99
|
+
def parse_json(v)
|
100
|
+
Album.load(:id=>3)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
::Album.from_json('1').should == Album.load(:id=>3)
|
104
|
+
ensure
|
105
|
+
Sequel.instance_eval do
|
106
|
+
alias parse_json pj
|
107
|
+
end
|
108
|
+
end
|
56
109
|
end
|
57
110
|
|
58
111
|
it "should handle the :include option for arbitrary attributes" do
|
59
|
-
|
112
|
+
Album.from_json(@album.to_json(:include=>:blah)).blah.should == @album.blah
|
60
113
|
end
|
61
114
|
|
62
115
|
it "should handle multiple inclusions using an array for the :include option" do
|
63
|
-
a =
|
116
|
+
a = Album.from_json(@album.to_json(:include=>[:blah, :artist]), :associations=>:artist)
|
64
117
|
a.blah.should == @album.blah
|
65
118
|
a.artist.should == @artist
|
66
119
|
end
|
67
120
|
|
68
121
|
it "should handle cascading using a hash for the :include option" do
|
69
|
-
|
70
|
-
|
122
|
+
Artist.from_json(@artist.to_json(:include=>{:albums=>{:include=>:artist}}), :associations=>{:albums=>{:associations=>:artist}}).albums.map{|a| a.artist}.should == [@artist]
|
123
|
+
Album.from_json(@album.to_json(:include=>{:artist=>{:include=>:albums}}), :associations=>{:artist=>{:associations=>:albums}}).artist.albums.should == [@album]
|
71
124
|
|
72
|
-
|
73
|
-
|
125
|
+
Artist.from_json(@artist.to_json(:include=>{:albums=>{:only=>:name}}), :associations=>[:albums]).albums.should == [Album.load(:name=>@album.name)]
|
126
|
+
Album.from_json(@album.to_json(:include=>{:artist=>{:except=>:name}}), :associations=>[:artist]).artist.should == Artist.load(:id=>@artist.id)
|
74
127
|
|
75
|
-
|
76
|
-
|
128
|
+
Artist.from_json(@artist.to_json(:include=>{:albums=>{:include=>{:artist=>{:include=>:albums}}}}), :associations=>{:albums=>{:associations=>{:artist=>{:associations=>:albums}}}}).albums.map{|a| a.artist.albums}.should == [[@album]]
|
129
|
+
Album.from_json(@album.to_json(:include=>{:artist=>{:include=>{:albums=>{:only=>:name}}}}), :associations=>{:artist=>{:associations=>:albums}}).artist.albums.should == [Album.load(:name=>@album.name)]
|
130
|
+
end
|
131
|
+
|
132
|
+
it "should automatically cascade parsing for all associations if :all_associations is used" do
|
133
|
+
Artist.from_json(@artist.to_json(:include=>{:albums=>{:include=>:artist}}), :all_associations=>true).albums.map{|a| a.artist}.should == [@artist]
|
77
134
|
end
|
78
135
|
|
79
136
|
it "should handle the :include option cascading with an empty hash" do
|
80
|
-
|
81
|
-
|
137
|
+
Album.from_json(@album.to_json(:include=>{:artist=>{}}), :associations=>:artist).artist.should == @artist
|
138
|
+
Album.from_json(@album.to_json(:include=>{:blah=>{}})).blah.should == @album.blah
|
82
139
|
end
|
83
140
|
|
84
141
|
it "should accept a :naked option to not include the JSON.create_id, so parsing yields a plain hash" do
|
85
|
-
|
142
|
+
Sequel.parse_json(@album.to_json(:naked=>true)).should == @album.values.inject({}){|h, (k, v)| h[k.to_s] = v; h}
|
86
143
|
end
|
87
144
|
|
88
145
|
it "should support #from_json to set column values" do
|
@@ -107,35 +164,39 @@ describe "Sequel::Plugins::JsonSerializer" do
|
|
107
164
|
proc{@album.from_json('{"artist_id": 3}', :fields=>['name'], :missing=>:raise)}.should raise_error(Sequel::Error)
|
108
165
|
end
|
109
166
|
|
167
|
+
it "should have #from_json raise an error if parsed json isn't a hash" do
|
168
|
+
proc{@artist.from_json('[]')}.should raise_error(Sequel::Error)
|
169
|
+
end
|
170
|
+
|
110
171
|
it "should raise an exception for json keys that aren't associations, columns, or setter methods" do
|
111
172
|
Album.send(:undef_method, :blah=)
|
112
|
-
proc{
|
173
|
+
proc{Album.from_json(@album.to_json(:include=>:blah))}.should raise_error(Sequel::Error)
|
113
174
|
end
|
114
175
|
|
115
176
|
it "should support a to_json class and dataset method" do
|
116
177
|
Album.dataset._fetch = {:id=>1, :name=>'RF', :artist_id=>2}
|
117
178
|
Artist.dataset._fetch = {:id=>2, :name=>'YJM'}
|
118
|
-
|
119
|
-
|
120
|
-
|
179
|
+
Album.array_from_json(Album.to_json).should == [@album]
|
180
|
+
Album.array_from_json(Album.to_json(:include=>:artist), :associations=>:artist).map{|x| x.artist}.should == [@artist]
|
181
|
+
Album.array_from_json(Album.dataset.to_json(:only=>:name)).should == [Album.load(:name=>@album.name)]
|
121
182
|
end
|
122
183
|
|
123
184
|
it "should have dataset to_json method work with naked datasets" do
|
124
185
|
album = @album
|
125
186
|
ds = Album.dataset.naked
|
126
187
|
ds._fetch = {:id=>1, :name=>'RF', :artist_id=>2}
|
127
|
-
|
188
|
+
Sequel.parse_json(ds.to_json).should == [@album.values.inject({}){|h, (k, v)| h[k.to_s] = v; h}]
|
128
189
|
end
|
129
190
|
|
130
191
|
it "should have dataset to_json method respect :array option for the array to use" do
|
131
|
-
a = Album.
|
132
|
-
|
192
|
+
a = Album.new(:name=>'RF', :artist_id=>3)
|
193
|
+
Album.array_from_json(Album.to_json(:array=>[a])).should == [a]
|
133
194
|
|
134
195
|
a.associations[:artist] = artist = Artist.load(:id=>3, :name=>'YJM')
|
135
|
-
|
196
|
+
Album.array_from_json(Album.to_json(:array=>[a], :include=>:artist), :associations=>:artist).first.artist.should == artist
|
136
197
|
|
137
198
|
artist.associations[:albums] = [a]
|
138
|
-
x =
|
199
|
+
x = Artist.array_from_json(Artist.to_json(:array=>[artist], :include=>:albums), :associations=>[:albums])
|
139
200
|
x.should == [artist]
|
140
201
|
x.first.albums.should == [a]
|
141
202
|
end
|
@@ -191,12 +252,57 @@ describe "Sequel::Plugins::JsonSerializer" do
|
|
191
252
|
class ::Artist2 < Artist
|
192
253
|
plugin :json_serializer, :only=>:name
|
193
254
|
end
|
194
|
-
|
255
|
+
Artist2.from_json(Artist2.load(:id=>2, :name=>'YYY').to_json).should == Artist2.load(:name=>'YYY')
|
195
256
|
class ::Artist3 < Artist2
|
196
257
|
plugin :json_serializer, :naked=>:true
|
197
258
|
end
|
198
|
-
|
259
|
+
Sequel.parse_json(Artist3.load(:id=>2, :name=>'YYY').to_json).should == {"name"=>'YYY'}
|
199
260
|
Object.send(:remove_const, :Artist2)
|
200
261
|
Object.send(:remove_const, :Artist3)
|
201
262
|
end
|
263
|
+
|
264
|
+
it "should have :associations option take precedence over :all_assocations" do
|
265
|
+
Artist.from_json(@artist.to_json(:include=>:albums), :associations=>[], :all_associations=>true, :fields=>[]).associations.should == {}
|
266
|
+
end
|
267
|
+
|
268
|
+
it "should allow overriding of :all_columns options in associated objects" do
|
269
|
+
Album.restrict_primary_key
|
270
|
+
Artist.from_json(@artist.to_json(:include=>:albums), :associations=>{:albums=>{:fields=>[:id, :name, :artist_id], :missing=>:raise}}, :all_columns=>true).albums.should == [@album]
|
271
|
+
end
|
272
|
+
|
273
|
+
it "should handle typecasting if setter columns exist when using :all_columns" do
|
274
|
+
Artist.restrict_primary_key
|
275
|
+
Artist.from_json('{"id":"2","name":"YJM","json_class":"Artist"}', :all_columns=>true).should == @artist
|
276
|
+
end
|
277
|
+
|
278
|
+
it "should allow setting columns that are restricted if :all_columns is used" do
|
279
|
+
Artist.restrict_primary_key
|
280
|
+
Artist.from_json(@artist.to_json, :all_columns=>true).should == @artist
|
281
|
+
end
|
282
|
+
|
283
|
+
it "should raise an error if using :all_columns and non-column is in the JSON" do
|
284
|
+
proc{Artist.from_json('{"foo":"bar"}', :all_columns=>true)}.should raise_error(Sequel::Error)
|
285
|
+
end
|
286
|
+
|
287
|
+
it "should raise an error if attempting to set a restricted column and :all_columns is not used" do
|
288
|
+
Artist.restrict_primary_key
|
289
|
+
proc{Artist.from_json(@artist.to_json)}.should raise_error(Sequel::Error)
|
290
|
+
end
|
291
|
+
|
292
|
+
it "should raise an error if an unsupported association is passed in the :associations option" do
|
293
|
+
Artist.association_reflections.delete(:albums)
|
294
|
+
proc{Artist.from_json(@artist.to_json(:include=>:albums), :associations=>:albums)}.should raise_error(Sequel::Error)
|
295
|
+
end
|
296
|
+
|
297
|
+
it "should raise an error if using from_json and JSON parsing returns an array" do
|
298
|
+
proc{Artist.from_json([@artist].to_json)}.should raise_error(Sequel::Error)
|
299
|
+
end
|
300
|
+
|
301
|
+
it "should raise an error if using array_from_json and JSON parsing does not return an array" do
|
302
|
+
proc{Artist.array_from_json(@artist.to_json)}.should raise_error(Sequel::Error)
|
303
|
+
end
|
304
|
+
|
305
|
+
it "should raise an error if using an unsupported :associations option" do
|
306
|
+
proc{Artist.from_json(@artist.to_json, :associations=>'')}.should raise_error(Sequel::Error)
|
307
|
+
end
|
202
308
|
end
|
@@ -19,6 +19,7 @@ describe "Sequel named_timezones extension" do
|
|
19
19
|
Sequel.datetime_class = DateTime
|
20
20
|
end
|
21
21
|
after do
|
22
|
+
Sequel.tzinfo_disambiguator = nil
|
22
23
|
Sequel.default_timezone = nil
|
23
24
|
Sequel.datetime_class = Time
|
24
25
|
end
|
@@ -53,6 +54,15 @@ describe "Sequel named_timezones extension" do
|
|
53
54
|
dt.offset.should == -7/24.0
|
54
55
|
end
|
55
56
|
|
57
|
+
it "should raise an error for ambiguous timezones by default" do
|
58
|
+
proc{Sequel.database_to_application_timestamp('2004-10-31T01:30:00')}.should raise_error(Sequel::InvalidValue)
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should support tzinfo_disambiguator= to handle ambiguous timezones automatically" do
|
62
|
+
Sequel.tzinfo_disambiguator = proc{|datetime, periods| periods.first}
|
63
|
+
Sequel.database_to_application_timestamp('2004-10-31T01:30:00').should == DateTime.parse('2004-10-30T22:30:00-07:00')
|
64
|
+
end
|
65
|
+
|
56
66
|
it "should assume datetimes coming out of the database that don't have an offset as coming from database_timezone" do
|
57
67
|
dt = Sequel.database_to_application_timestamp('2009-06-01 06:20:30')
|
58
68
|
dt.should == @dt
|
@@ -62,4 +62,9 @@ describe "pg_auto_parameterize extension" do
|
|
62
62
|
it "should not auto parameterize when using cursors" do
|
63
63
|
@db[:table].filter(:a=>1).use_cursor.opts[:no_auto_parameterize].should be_true
|
64
64
|
end
|
65
|
+
|
66
|
+
it "should have a working create_view" do
|
67
|
+
@db.create_view :foo, @db[:table].filter(:a=>1)
|
68
|
+
@db.sqls.should == ["CREATE VIEW foo AS SELECT * FROM table WHERE (a = 1)"]
|
69
|
+
end
|
65
70
|
end
|
@@ -39,6 +39,20 @@ describe "pg_json extension" do
|
|
39
39
|
it "should raise an error when attempting to parse invalid json" do
|
40
40
|
proc{@m.parse_json('')}.should raise_error(Sequel::InvalidValue)
|
41
41
|
proc{@m.parse_json('1')}.should raise_error(Sequel::InvalidValue)
|
42
|
+
|
43
|
+
begin
|
44
|
+
Sequel.instance_eval do
|
45
|
+
alias pj parse_json
|
46
|
+
def parse_json(v)
|
47
|
+
v
|
48
|
+
end
|
49
|
+
end
|
50
|
+
proc{@m.parse_json('1')}.should raise_error(Sequel::InvalidValue)
|
51
|
+
ensure
|
52
|
+
Sequel.instance_eval do
|
53
|
+
alias parse_json pj
|
54
|
+
end
|
55
|
+
end
|
42
56
|
end
|
43
57
|
|
44
58
|
it "should literalize HStores to strings correctly" do
|
@@ -144,6 +144,17 @@ describe "pg_row extension" do
|
|
144
144
|
db.register_row_type(:foo)
|
145
145
|
db.sqls.should == ["SELECT pg_type.oid, typrelid, typarray FROM pg_type WHERE ((typtype = 'c') AND (typname = 'foo')) LIMIT 1",
|
146
146
|
"SELECT attname, atttypid FROM pg_attribute WHERE ((attrelid = 2) AND (attnum > 0) AND NOT attisdropped) ORDER BY attnum"]
|
147
|
+
|
148
|
+
begin
|
149
|
+
pgnt = Sequel::Postgres::PG_NAMED_TYPES.dup
|
150
|
+
Sequel::Postgres::PG_NAMED_TYPES.clear
|
151
|
+
db.fetch = [[{:oid=>1, :typrelid=>2, :typarray=>3}], [{:attname=>'bar', :atttypid=>4}, {:attname=>'baz', :atttypid=>5}]]
|
152
|
+
db.reset_conversion_procs
|
153
|
+
db.sqls.should == ["SELECT pg_type.oid, typrelid, typarray FROM pg_type WHERE ((typtype = 'c') AND (typname = 'foo')) LIMIT 1",
|
154
|
+
"SELECT attname, atttypid FROM pg_attribute WHERE ((attrelid = 2) AND (attnum > 0) AND NOT attisdropped) ORDER BY attnum"]
|
155
|
+
ensure
|
156
|
+
Sequel::Postgres::PG_NAMED_TYPES.replace pgnt
|
157
|
+
end
|
147
158
|
end
|
148
159
|
|
149
160
|
it "should handle ArrayRows and HashRows in bound variables" do
|
@@ -44,7 +44,7 @@ describe "PrettyTable" do
|
|
44
44
|
@data3 = [
|
45
45
|
{:aaa => 1},
|
46
46
|
{:bb => 2},
|
47
|
-
{:c => 3}
|
47
|
+
{:c => 3.1}
|
48
48
|
]
|
49
49
|
|
50
50
|
@output = StringIO.new
|
@@ -80,7 +80,7 @@ describe "PrettyTable" do
|
|
80
80
|
Sequel::PrettyTable.print(@data3, [:aaa, :bb, :c])
|
81
81
|
@output.rewind
|
82
82
|
@output.read.should == \
|
83
|
-
"
|
83
|
+
"+---+--+---+\n|aaa|bb|c |\n+---+--+---+\n| 1| | |\n| | 2| |\n| | |3.1|\n+---+--+---+\n"
|
84
84
|
end
|
85
85
|
|
86
86
|
specify "should print only the specified columns" do
|
@@ -77,15 +77,18 @@ describe "Dataset#query" do
|
|
77
77
|
q.class.should == @d.class
|
78
78
|
q.sql.should == "SELECT * FROM xyz ORDER BY stamp"
|
79
79
|
end
|
80
|
-
|
81
|
-
specify "should
|
82
|
-
|
80
|
+
|
81
|
+
specify "should support blocks that end in nil" do
|
82
|
+
condition = false
|
83
|
+
q = @d.query do
|
84
|
+
from :xyz
|
85
|
+
order_by :stamp if condition
|
86
|
+
end
|
87
|
+
q.sql.should == "SELECT * FROM xyz"
|
83
88
|
end
|
84
89
|
|
85
|
-
specify "should raise on
|
86
|
-
proc {@d.query {
|
87
|
-
proc {@d.query {
|
88
|
-
proc {@d.query {update(:x => 1)}}.should raise_error(Sequel::Error)
|
89
|
-
proc {@d.query {delete}}.should raise_error(Sequel::Error)
|
90
|
+
specify "should raise on non-chainable method calls" do
|
91
|
+
proc {@d.query {row_proc}}.should raise_error(Sequel::Error)
|
92
|
+
proc {@d.query {all}}.should raise_error(Sequel::Error)
|
90
93
|
end
|
91
94
|
end
|
@@ -114,6 +114,26 @@ describe "Serialization plugin" do
|
|
114
114
|
"SELECT * FROM items WHERE (id = 10) LIMIT 1"]
|
115
115
|
end
|
116
116
|
|
117
|
+
it "should handle old non-base-64 encoded marshal serialization format" do
|
118
|
+
@c.set_primary_key :id
|
119
|
+
@c.plugin :serialization, :marshal, :abc, :def
|
120
|
+
@c.dataset._fetch = [:id => 1, :abc =>Marshal.dump(1), :def =>Marshal.dump('hello')]
|
121
|
+
|
122
|
+
o = @c.first
|
123
|
+
o.abc.should == 1
|
124
|
+
o.def.should == "hello"
|
125
|
+
end
|
126
|
+
|
127
|
+
it "should raise exception for bad marshal data" do
|
128
|
+
@c.set_primary_key :id
|
129
|
+
@c.plugin :serialization, :marshal, :abc, :def
|
130
|
+
@c.dataset._fetch = [:id => 1, :abc =>'foo', :def =>'bar']
|
131
|
+
|
132
|
+
o = @c.first
|
133
|
+
proc{o.abc}.should raise_error
|
134
|
+
proc{o.def}.should raise_error
|
135
|
+
end
|
136
|
+
|
117
137
|
it "should translate values to and from json serialization format using accessor methods" do
|
118
138
|
@c.set_primary_key :id
|
119
139
|
@c.plugin :serialization, :json, :abc, :def
|